#ifndef __485_C__
#define __485_C__
#include
#include
#define unsigned char uchar
#define unsigned int uint
/* 通信命令 */
#define __ACTIVE_ 0x01 // 主机询问从机是否存在
#define __GETDATA_ 0x02 // 主机发送读设备请求
#define __OK_ 0x03 // 从机应答
#define __STATUS_ 0x04 // 从机发送设备状态信息
#define __MAXSIZE 0x08 // 缓冲区长度
#define __ERRLEN 12 // 任何通信帧长度超过12则表示出错
uchar dbuf[__MAXSIZE]; // 该缓冲区用于保存设备状态信息
uchar dev; // 该字节用于保存本机设备号
sbit M_DE = P1 ^ 0; // 驱动器使能,1有效
sbit M_RE = P1 ^ 1; // 接收器使能,0有效
void get_status(); // 调用该函数获得设备状态信息,函数代码未给出
void send_data(uchar type, uchar len, uchar *buf); // 发送数据帧
bit recv_cmd(uchar *type); // 接收主机命令,主机请求仅包含命令信息
void send_byte(uchar da); // 该函数发送一帧数据中的一个字节,由send_data()函数调用
void main()
{
uchar type;
uchar len;
/* 系统初始化 */
P1 = 0xff; // 读取本机设备号
dev = (P1 >> 2);
TMOD = 0x20; // 定时器T1使用工作方式2
TH1 = 250; // 设置初值
TL1 = 250;
TR1 = 1; // 开始计时
PCON = 0x80; // SMOD = 1
SCON = 0x50; // 工作方式1,波特率9600bps,允许接收
ES = 0; // 关闭串口中断
IT0 = 0; // 外部中断0使用电平触发模式
EX0 = 1; // 开启外部中断0
EA = 1; // 开启中断
/* 主程序流程 */
while(1) // 主循环
{
if(recv_cmd(&type) == 0) // 发生帧错误或帧地址与本机地址不符,丢弃当前帧后返回
continue;
switch(type)
{
case __ACTIVE_: // 主机询问从机是否存在
send_data(__OK_, 0, dbuf); // 发送应答信息,这里buf的内容并未用到
break;
case __GETDATA_:
len = strlen(dbuf);
send_data(__STATUS_, len, dbuf); // 发送设备状态信息
break;
default:
break; // 命令类型错误,丢弃当前帧后返回
}
}
}
void READSTATUS() interrupt 0 using 1 // 产生外部中断0时表示设备状态发生改变,该函数使用寄存器组1
{
get_status(); // 获得设备状态信息,并将其存入dbuf指向的存储区,数据最后一字节置0表示数据结束
}
/* 该函数接收一帧数据并进行检测,无论该帧是否错误,函数均会返回
* 函数参数type保存接收到的命令字
* 当接收到数据帧错误或其地址位不为0时(非主机发送帧),函数返回0,反之返回1
*/
bit recv_cmd(uchar *type)
{
bit db = 0; // 当接收到的上一个字节为0xdb时,该位置位
bit c0 = 0; // 当接收到的上一个字节为0xc0时,该位置位
uchar data_buf[__ERRLEN]; // 保存接收到的帧
uchar tmp;
uchar ecc = 0;
uchar i;
M_DE = 0; // 置发送禁止,接收允许
M_RE = 0;
/* 接收一帧数据 */
i = 0;
while(!c0) // 循环直至帧接收完毕
{
RI = 0;
while(!RI);
tmp = SBUF;
RI = 0;
if(db == 1) // 接收到的上一个字节为0xdb
{
switch(tmp)
{
case 0xdd:
data_buf[i] = 0xdb; // 0xdbdd表示0xdb
ecc = ecc ^ 0xdb;
db = 0;
break;
case 0xdc
data_buf[i] = 0xc0; // 0xdbdc表示0xc0
ecc = ecc ^ 0xc0;
db = 0;
break;
default
return 0; // 帧错误,返回
}
i++;
}
switch(tmp) // 正常情况
{
case 0xc0: // 帧结束
c0 = 1;
break;
case 0xdb: // 检测到转义字符
db = 1;
break;
default: // 普通数据
data_buf[i] = tmp; // 保存数据
ecc = ecc ^ tmp; // 计算校验字节
i++;
}
if(i == __ERRLEN) // 帧超长,错误,返回
return 0;
}
/* 判断帧是否错误 */
if(i
return 0;
if(ecc != 0) // 校验错误,返回
return 0;
if(data_buf[0] != dev) // 非访问本机命令,错误,返回
return 0;
*type = data_buf[1]; // 获得命令字
return 1; // 函数成功返回
}
/* 该函数发送一帧数据帧,参数type为命令字、len为数据长度、buf为要发送的数据内容 */
void send_data(uchar type, uchar len, uchar *buf)
{
uchar i;
uchar ecc = 0; // 该字节用于保存校验字节
M_DE = 1; // 置发送允许,接收禁止
M_RE = 1;
send_byte(dev); // 发送本机地址
ecc = dev;
send_byte(type); // 发送命令字
ecc = ecc ^ type;
send_byte(len); // 发送长度
ecc = ecc ^ len;
for(i = 0; i
{
send_byte(*buf);
ecc = ecc ^ (*buf);
buf++;
}
send_byte(ecc); // 发送校验字节
TI = 0; // 发送帧结束标志
SBUF = 0xc0;
while(!TI);
TI = 0;
}
/* 该函数发送一个数据字节,若该字节为0xdb,则发送0xdbdd,若该字节为0xc0则,发送0xdbdc */
void send_byte(uchar da)
{
switch(da)
{
case 0xdb: // 字节为0xdb,发送0xdbdd
TI = 0;
SBUF = 0xdb;
while(!TI);
TI = 0;
SBUF = 0xdd;
while(!TI)
TI = 0;
break;
case 0xc0: // 字节为0xc0,发送0xdbdc
TI = 0;
SBUF = 0xdb;
while(!TI);
TI = 0;
SBUF = 0xdc;
while(!TI)
TI = 0;
break;
default: // 普通数据则直接发送
TI = 0;
SBUF = da;
while(!TI);
TI = 0;
}
}
#endif
RS - 232接口实现计算机和单片机通信程序
作者:
佚名 来源:
本站原创 点击数:… 更新时间:2008年07月10日 【字体:大 中 小】
//此程序通过RS-232接口来完成计算机和单片机通信(程序已用p18f458试验板上调试通过)
//程序的调试可以用"串口调试助手V2.1"辅助完成,此程序可在http://www.51hei.com 下载
//此程序首先发送测试数据55H,再通过中断实现数据的接收和发送
#include "p18f458.h"
void InterruptHandlerHigh(void);
//初始化程序
void initial()
{
SPBRG = 0X19; //选择传输波特率为9600bps
TXSTA = 0X04; //选择异步高速方式传输8位数据
RCSTA = 0X80; //允许同步串行口工作
TRISC = 0X80; //将RC7,RC6设置为输入,断绝与外接电路的连接
TXSTAbits.TXEN = 1; //发送允许
RCSTAbits.CREN = 1; //接受数据允许
PIE1bits.RCIE = 1; //接收中断使能
INTCON = 0XC0; //总中断和外围中断允许
}
//高优先级中断向量
#pragma code InterruptVectorHigh=0x08
void InterruptVectorHigh (void)
{
_asm
goto InterruptHandlerHigh //跳到中断程
_endasm
}
//高优先级中断服务程序
#pragma code
#pragma interrupt InterruptHandlerHigh
void InterruptHandlerHigh ()
{
while(PIR1bits.RCIF == 1) //若接收中断标志不为1,则为误操作,返回
{
TXREG = RCREG; //将接收到的数据放入发送寄存器,并启动发送
}
}
//主程序
main()
{
initial(); //系统初始化
TXREG = 0X55; //发送数据55H进行测试
for(;;);
}
------------------------------------------汇编语言版本的RS - 232接口实现计算机和单片机通信程序------------
;
此程序通过RS - 232接口来完成计算机和单片机通讯(程序以在p18f458试验板上调通)
;
本单片机程序由http://www.51hei.com提供
;
此程序首先发送测试数据55H,再通过中断实现数据的接收和发送
;
程序的调试可以用"串口调试助手V2.1"辅助完成
LIST P = 18f458
INCLUDE "P18f458.INC"
ORG 0x00
GOTO MAIN
ORG 0x08
GOTO INTSERVE
ORG 0X30
;
************ **中断服务子程序 ************ ***
INTSERVE
BTFSS PIR1,RCIF ;
接收中断标志为1?
GOTO ERR_RE ;
误操作,返回
MOVF RCREG,0 ;
否则,将接收到的数据通过W寄存器
MOVWF TXREG ;
放入发送寄存器,并启动发送
ERR_RE NOP
RETFIE
;
************** **初始化程序 ************ ***
INITIAL NOP
MOVLW 0X19 ;
选择传输波特率为9600bps
MOVWF SPBRG
MOVLW 0X04 ;
选择异步高速方式传输8位数据
MOVWF TXSTA
MOVLW 0X80 ;
允许同步串行口工作
MOVWF RCSTA
MOVLW 0X80 ;
将RC7,RC6设置为输入,断绝与外接电路的连接
MOVWF TRISC
BSF TXSTA,TXEN ;
发送允许
BSF RCSTA,CREN ;
接受数据允许
BSF PIE1,RCIE ;
接收中断使能
MOVLW 0XC0 ;
总中断和外围中断允许
MOVWF INTCON
RETURN
;
******************** **主程序 ****************** ***
MAIN NOP
CLRWDT
CALL INITIAL
MOVLW 0X55 ;
发送数据55H进行测试
MOVWF TXREG
LOOP
GOTO LOOP
END
两片51单片机互相通信的串行通信程序(一个发送程序, 一个接收程序)
2007 - 05 - 27 08: 27
;
系统晶振是 11.0592 MHz
;
51单片机发送单片机程序
;
此程序用Proteus仿真通过
;
此程序在硬件上测试通过
;
2007 - 05 - 27
;
附有简化电路图
;
为了使初学者能看懂,程序与图尽可能的简单扼要
;
实验现象为,发送端的P1口的哪个键被接下,接收端的哪个灯对应着亮
;
如果把两个单片机的T和R通过无线模块(如基于MCP2120芯片的模块)来扩充,便可做成无线通信
ORG 0000H
AJMP START
ORG 0040H
START:
MOV SP, #60H
MOV SCON, #50H ;串口 方式 1
MOV TMOD, #20H ;T1 方式2
MOV TL1, #0FDH ;波特率 9600 的常数
MOV TH1, #0FDH
SETB TR1
mov r5, #00h
WAIT:
mov p1, #0ffh
mov a , p1
mov r5, a
lcall delay ;
读键盘,这里去抖动,还要加几句话
mov a , p1
nop
CJNE A, 5, WAIT ;
是否有键输入
MOV SBUF, a ;
串口输出键盘输入的值
NOP
SS:
JBC TI, WAIT ;
是否发送完毕
SJMP SS
DELAY:
;
延时子程序
PUSH 0 ;
保存现场
PUSH 1
MOV 0, #06H
DELAY1:
MOV 1, #0H
DJNZ 1, $
DJNZ 0, DELAY1
POP 1 ;
恢复现场
POP 0
RET
END
;
系统晶振是 11.0592 MHz
;
51单片机接收单片机程序
;
此程序用Proteus仿真通过
;
此程序在硬件上测试通过
;
2007 - 05 - 27
;
附有简化电路图
;
为了使初学者能看懂,程序与图尽可能的简单扼要
;
实验现象为,发送端的P1口的哪个键被接下,接收端的哪个灯对应着亮
;
如果把两个单片机的T和R通过无线模块(如基于MCP2120芯片的模块)来扩充,便可做成无线通信
ORG 0000H
AJMP START
ORG 0040H
START:
MOV SCON, #50H ;串口 方式 1
MOV TMOD, #20H ;T1 方式 2
MOV TL1, #0FDH ;波特率 9600 的常数
MOV TH1, #0FDH
SETB TR1
WAIT:
JBC RI, DIS_REC ;
是否接收到数据
sjmp wait
DIS_REC:
MOV A, SBUF ;
读串口接收到的数据
mov p1, a
SJMP wait
end
51单片机串行口通信程序设计例子
时间: 2009 - 03 - 06 17: 13来源:
未知 作者:
牛牛 点击: 768次
串行口方式0应用编程 8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就能扩展一个并行口。 单片机串行口通信
程序设计硬件连接图 例:用8051单片机串行口外接CD4094扩展8位并行输出口,如图所示,8位并行口的各位都接一个发光二极管
串行口方式0应用编程 8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就能扩展一个并行口。
例:用8051单片机串行口外接CD4094扩展8位并行输出口,如图所示,8位并行口的各位都接一个发光二极管,要求发光管呈流水灯状态。 串行口方式0的数据
传送可采用中断方式,也可采用查询方式,无论哪种方式,都要借助于TI或RI标志。串行发送时,能靠TI置位(发完一帧数据后)引起中断申请,在中断服务程序中发送
下一帧数据,或者通过查询TI的状态,只要TI为0就继续查询,TI为1就结束查询,发送下一帧数据。在串行接收时,则由RI引起中断或对RI查询来确定何时接收下一帧数据。
无论采用什么方式,在开始通信之前,都要先对控制寄存器SCON进行初始化。在方式0中将,将00H送SCON就能了。
---------------- -单片机串行口通信程序设计列子--------------------------
ORG 2000H
START:
MOV SCON, #00H ;置串行口工作方式0
MOV A, #80H ;最高位灯先亮
CLR P1.0 ;
关闭并行输出(避象传输过程中,各LED的"暗红"现象)
OUT0:
MOV SBUF, A ;
开始串行输出
OUT1:
JNB TI, OUT1 ;
输出完否
CLR TI ;
完了,清TI标志,以备下次发送
SETB P1.0 ;
打开并行口输出
ACALL DELAY ;
延时一段时间
RR A ;
循环右移
CLR P1.0 ;
关闭并行输出
JMP OUT0 ;
循环
说明:DELAY延时子程序能用前面我们讲P1口流水灯时用的延时子程序,这里就不给出了
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』