×
嵌入式 > 嵌入式开发 > 详情

51单片机实现的485通讯程序

发布时间:2020-08-27 发布时间:
|
#ifndef__485_C__
#define__485_C__
#include
#include

#defineunsignedcharuchar
#defineunsignedintuint
/*通信命令*/
#define__ACTIVE_0x01//主机询问从机是否存在
#define__GETDATA_0x02//主机发送读设备请求
#define__OK_0x03//从机应答
#define__STATUS_0x04//从机发送设备状态信息
#define__MAXSIZE0x08//缓冲区长度
#define__ERRLEN12//任何通信帧长度超过12则表示出错
uchardbuf[__MAXSIZE];//该缓冲区用于保存设备状态信息
uchardev;//该字节用于保存本机设备号
sbitM_DE=P1^0;//驱动器使能,1有效
sbitM_RE=P1^1;//接收器使能,0有效
voidget_status();//调用该函数获得设备状态信息,函数代码未给出
voidsend_data(uchartype,ucharlen,uchar*buf);//发送数据帧
bitrecv_cmd(uchar*type);//接收主机命令,主机请求仅包含命令信息
voidsend_byte(ucharda);//该函数发送一帧数据中的一个字节,由send_data()函数调用
voidmain()
{
uchartype;
ucharlen;

/*系统初始化*/
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;//命令类型错误,丢弃当前帧后返回
}
}
}
voidREADSTATUS()interrupt0using1//产生外部中断0时表示设备状态发生改变,该函数使用寄存器组1
{
get_status();//获得设备状态信息,并将其存入dbuf指向的存储区,数据最后一字节置0表示数据结束
}
/*该函数接收一帧数据并进行检测,无论该帧是否错误,函数均会返回
*函数参数type保存接收到的命令字
*当接收到数据帧错误或其地址位不为0时(非主机发送帧),函数返回0,反之返回1
*/
bitrecv_cmd(uchar*type)
{
bitdb=0;//当接收到的上一个字节为0xdb时,该位置位
bitc0=0;//当接收到的上一个字节为0xc0时,该位置位
uchardata_buf[__ERRLEN];//保存接收到的帧
uchartmp;
ucharecc=0;
uchari;

M_DE=0;//置发送禁止,接收允许
M_RE=0;

/*接收一帧数据*/
i=0;
while(!c0)//循环直至帧接收完毕
{
RI=0;
while(!RI);
tmp=SBUF;
RI=0;
if(db==1)//接收到的上一个字节为0xdb
{
switch(tmp)
{
case0xdd:
data_buf[i]=0xdb;//0xdbdd表示0xdb
ecc=ecc^0xdb;
db=0;
break;
case0xdc
data_buf[i]=0xc0;//0xdbdc表示0xc0
ecc=ecc^0xc0;
db=0;
break;
default
return0;//帧错误,返回
}
i++;
}
switch(tmp)//正常情况
{
case0xc0://帧结束
c0=1;
break;
case0xdb://检测到转义字符
db=1;
break;
default://普通数据
data_buf[i]=tmp;//保存数据
ecc=ecc^tmp;//计算校验字节
i++;
}
if(i==__ERRLEN)//帧超长,错误,返回
return0;
}
/*判断帧是否错误*/
if(i<4)//帧过短,错误,返回
return0;
if(ecc!=0)//校验错误,返回
return0;
if(data_buf[0]!=dev)//非访问本机命令,错误,返回
return0;
*type=data_buf[1];//获得命令字
return1;//函数成功返回
}
/*该函数发送一帧数据帧,参数type为命令字、len为数据长度、buf为要发送的数据内容*/
voidsend_data(uchartype,ucharlen,uchar*buf)
{
uchari;
ucharecc=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*/
voidsend_byte(ucharda)
{
switch(da)
{
case0xdb://字节为0xdb,发送0xdbdd
TI=0;
SBUF=0xdb;
while(!TI);
TI=0;
SBUF=0xdd;
while(!TI)
TI=0;
break;
case0xc0://字节为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"辅助完成,此程序可在/zixunimg/eepwimg/www.51hei.com下载
//此程序首先发送测试数据55H,再通过中断实现数据的接收和发送
#include"p18f458.h"
voidInterruptHandlerHigh(void);
//初始化程序
voidinitial()
{
SPBRG=0X19;//选择传输波特率为9600bps
TXSTA=0X04;//选择异步高速方式传输8位数据
RCSTA=0X80;//允许同步串行口工作
TRISC=0X80;//将RC7,RC6设置为输入,断绝与外接电路的连接
TXSTAbits.TXEN=1;//发送允许
RCSTAbits.CREN=1;//接受数据允许
PIE1bits.RCIE=1;//接收中断使能
INTCON=0XC0;//总中断和外围中断允许
}
//高优先级中断向量
#pragmacodeInterruptVectorHigh=0x08
voidInterruptVectorHigh(void)
{
_asm
gotoInterruptHandlerHigh//跳到中断程
_endasm
}
//高优先级中断服务程序
#pragmacode
#pragmainterruptInterruptHandlerHigh
voidInterruptHandlerHigh()
{
while(PIR1bits.RCIF==1)//若接收中断标志不为1,则为误操作,返回
{
TXREG=RCREG;//将接收到的数据放入发送寄存器,并启动发送
}
}
//主程序
main()
{
initial();//系统初始化
TXREG=0X55;//发送数据55H进行测试
for(;;);
}


------------------------------------------汇编语言版本的RS-232接口实现计算机和单片机通信程序------------
;
此程序通过RS-232接口来完成计算机和单片机通讯(程序以在p18f458试验板上调通)
;
本单片机程序由/zixunimg/eepwimg/www.51hei.com提供
;
此程序首先发送测试数据55H,再通过中断实现数据的接收和发送
;
程序的调试可以用"串口调试助手V2.1"辅助完成
LISTP=18f458
INCLUDE"P18f458.INC"
ORG0x00
GOTOMAIN
ORG0x08
GOTOINTSERVE
ORG0X30
;
**************中断服务子程序***************
INTSERVE
BTFSSPIR1,RCIF;
接收中断标志为1?
GOTOERR_RE;
误操作,返回
MOVFRCREG,0;
否则,将接收到的数据通过W寄存器
MOVWFTXREG;
放入发送寄存器,并启动发送
ERR_RENOP
RETFIE
;
****************初始化程序***************
INITIALNOP
MOVLW0X19;
选择传输波特率为9600bps
MOVWFSPBRG
MOVLW0X04;
选择异步高速方式传输8位数据
MOVWFTXSTA
MOVLW0X80;
允许同步串行口工作
MOVWFRCSTA
MOVLW0X80;
将RC7,RC6设置为输入,断绝与外接电路的连接
MOVWFTRISC
BSFTXSTA,TXEN;
发送允许
BSFRCSTA,CREN;
接受数据允许
BSFPIE1,RCIE;
接收中断使能
MOVLW0XC0;
总中断和外围中断允许
MOVWFINTCON
RETURN
;
**********************主程序*********************
MAINNOP
CLRWDT
CALLINITIAL
MOVLW0X55;
发送数据55H进行测试
MOVWFTXREG
LOOP
GOTOLOOP
END




两片51单片机互相通信的串行通信程序(一个发送程序,一个接收程序)
2007-05-2708:27
;
系统晶振是11.0592MHz
;
51单片机发送单片机程序
;
此程序用Proteus仿真通过
;
此程序在硬件上测试通过
;
2007-05-27
;
附有简化电路图
;
为了使初学者能看懂,程序与图尽可能的简单扼要
;
实验现象为,发送端的P1口的哪个键被接下,接收端的哪个灯对应着亮
;
如果把两个单片机的T和R通过无线模块(如基于MCP2120芯片的模块)来扩充,便可做成无线通信
ORG0000H
AJMPSTART
ORG0040H
START:
MOVSP,#60H
MOVSCON,#50H;串口方式1
MOVTMOD,#20H;T1方式2
MOVTL1,#0FDH;波特率9600的常数
MOVTH1,#0FDH
SETBTR1
movr5,#00h
WAIT:
movp1,#0ffh
mova,p1
movr5,a
lcalldelay;
读键盘,这里去抖动,还要加几句话
mova,p1
nop
CJNEA,5,WAIT;
是否有键输入
MOVSBUF,a;
串口输出键盘输入的值
NOP
SS:
JBCTI,WAIT;
是否发送完毕
SJMPSS
DELAY:
;
延时子程序
PUSH0;
保存现场
PUSH1
MOV0,#06H
DELAY1:
MOV1,#0H
DJNZ1,$
DJNZ0,DELAY1
POP1;
恢复现场
POP0
RET
END


;
系统晶振是11.0592MHz
;
51单片机接收单片机程序
;
此程序用Proteus仿真通过
;
此程序在硬件上测试通过
;
2007-05-27
;
附有简化电路图
;
为了使初学者能看懂,程序与图尽可能的简单扼要
;
实验现象为,发送端的P1口的哪个键被接下,接收端的哪个灯对应着亮
;
如果把两个单片机的T和R通过无线模块(如基于MCP2120芯片的模块)来扩充,便可做成无线通信
ORG0000H
AJMPSTART
ORG0040H
START:
MOVSCON,#50H;串口方式1
MOVTMOD,#20H;T1方式2
MOVTL1,#0FDH;波特率9600的常数
MOVTH1,#0FDH
SETBTR1
WAIT:
JBCRI,DIS_REC;
是否接收到数据
sjmpwait
DIS_REC:
MOVA,SBUF;
读串口接收到的数据
movp1,a
SJMPwait
end




51单片机串行口通信程序设计例子
时间:2009-03-0617: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就能了。


-----------------单片机串行口通信程序设计列子--------------------------
ORG2000H
START:
MOVSCON,#00H;置串行口工作方式0
MOVA,#80H;最高位灯先亮
CLRP1.0;
关闭并行输出(避象传输过程中,各LED的"暗红"现象)
OUT0:
MOVSBUF,A;
开始串行输出
OUT1:
JNBTI,OUT1;
输出完否
CLRTI;
完了,清TI标志,以备下次发送
SETBP1.0;
打开并行口输出
ACALLDELAY;
延时一段时间
RRA;
循环右移
CLRP1.0;
关闭并行输出
JMPOUT0;
循环
说明:DELAY延时子程序能用前面我们讲P1口流水灯时用的延时子程序,这里就不给出了


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机控制220VAC开断