51单片机多机通信原理

电子说

1.3w人已加入

描述

一、多机通信原理

在多机通信中,主机必须要能对各个从机进行识别,在51系列单片机中可以通过SCON寄存器的SM2位来实现。当串口以方式2或方式3发送数据时,每一帧信息都是11位,第9位是数据可编程位,通过给TB8置1或置0来区别地址帧和数据帧,当该位为1时,发送地址帧;该位为0时,发送数据帧。

在多机通信过程中,主机先发送某一从机的地址,等待从机的应答,所有的从机接收到地址帧后与本机地址进行比较,若相同,则将SM2置0准备接收数据;若不同,则丢弃当前数据,SM2位不变。

二、多机通信电路图

多机通信

此处,U1作为主机,U2为从机1,U3为从机2。

三、C语言程序

(1)主机程序

#include#include

#define _SUCC_   0x0f//数据传送成功#define _ERR_    0xf0//数据传送失败unsigned char Table[9]={0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};unsigned char Buff[20];  //数据缓冲区unsigned char temp=0xff;sbit KEY1=P1^6;sbit KEY2=P1^7;//unsigned char addr;

//延时1ms函数void delay_1ms(unsigned int t){ unsigned int x,y; for(x=t;x>0;x--)  for(y=110;y>0;y--);}//缓冲区初始化void Buff_init(){ unsigned char i;    //将Table里的数据放到缓冲区里 for(i=0;i<9;i++)   {  Buff[i]= Table[i];  delay_1ms(100); } }//串口初始化函数void serial_init(){ TMOD=0x20; //定时器1工作于方式2 TH1=0xfd;   TL1=0xfd; //波特率为9600 PCON=0; SCON=0xd0;  //串口工作于方式3 TR1=1;  //开启定时器 TI=0; RI=0;}//发送数据函数void SEND_data(unsigned char *Buff){ unsigned char i; unsigned char lenth; unsigned char check; lenth=strlen(Buff);      //计算数据长度 check=lenth;

TI=0;         //发送数据长度 TB8=0;      //发送数据帧 SBUF=lenth; while(!TI); TI=0;          for(i=0;i;i++)  >

TB8=0;      //发送校验字节 SBUF=check;     while(!TI); TI=0;     }//向指定从机地址发送数据void ADDR_data(unsigned addr){ while(temp!=addr) //主机等待从机返回其地址作为应答信号 {  TI=0;    //发送从机地址  TB8=1;    //发送地址帧  SBUF=addr;  while(!TI);  TI=0;     RI=0;  while(!RI);  temp=SBUF;  RI=0; }

temp=_ERR_;   //主机等待从机数据接收成功信号 while(temp!=_SUCC_) {  SEND_data(Buff);  RI=0;  while(!RI);  temp=SBUF;  RI=0; }}      

void main(){ Buff_init(); serial_init(); while(1) {  if(KEY1==0)  {   delay_1ms(5);   if(KEY1==0)   {    while(!KEY1);    ADDR_data(0x01);   }  }  if(KEY2==0)  {   delay_1ms(5);   if(KEY2==0)   {    while(!KEY2);    ADDR_data(0x02);   }  }

}}

(2)从机1程序

#include#include

#define addr     0x01//从机1的地址#define _SUCC_   0x0f//数据传送成功#define _ERR_    0xf0//数据传送失败unsigned char aa=0xff;//主机与从机之间通信标志unsigned char Buff[20];//数据缓冲区

//串口初始化函数void serial_init(){ TMOD=0x20; //定时器1工作于方式2 TH1=0xfd;   TL1=0xfd; //波特率为9600 PCON=0; SCON=0xd0;  //串口工作于方式3 TR1=1;  //开启定时器 TI=0; RI=0;}//接收数据函数unsigned char RECE_data(unsigned char *Buff){ unsigned char i,temp; unsigned char lenth; unsigned char check;

RI=0;     //接收数据长度 while(!RI); if(RB8==1)    //若接收到地址帧,则返回0xfe  return 0xfe; lenth=SBUF; RI=0;       check=lenth; for(i=0;i;i++) >

while(!RI);    //接收校验字节 if(RB8==1)    //若接收到地址帧,则返回0xfe  return 0xfe; temp=SBUF; RI=0;       check=temp^check;  //将从主机接收到的校验码与自己计算的校验码比对 if(check!=0)   //校验码不一致,表明数据接收错误,向主机发送错误信号,函数返回0xff {  TI=0;  TB8=0;  SBUF=_ERR_;  while(!TI);  TI=0;  return 0xff; } TI=0;           //校验码一致,表明数据接收正确,向主机发送成功信号,函数返回0x00 TB8=0; SBUF=_SUCC_; while(!TI); TI=0; return 0;} 

void main(){ serial_init(); while(1) {  SM2=1;              //接收地址帧  while(aa!=addr)  //从机等待主机请求自己的地址  {   RI=0;   while(!RI);   aa=SBUF;   RI=0;  }

TI=0;     //一旦被请求,从机返回自己的地址作为应答,等待接收数据  TB8=0;  SBUF=addr;  while(!TI);  TI=0;

SM2=0;                  //接收数据帧  aa=0xff;    //从机接收数据,并将数据保存到数据缓冲区  while(aa==0xff)  {   aa=RECE_data(Buff);  }  if(aa==0xfe)   continue;   P1=Buff[1];      //查看接收到的数据 }}

(3)从机2程序

#include#include

#define addr     0x02//从机2的地址#define _SUCC_   0x0f//数据传送成功#define _ERR_    0xf0//数据传送失败unsigned char aa=0xff;//主机与从机之间通信标志unsigned char Buff[20];//数据缓冲区

//串口初始化函数void serial_init(){ TMOD=0x20; //定时器1工作于方式2 TH1=0xfd;   TL1=0xfd; //波特率为9600 PCON=0; SCON=0xd0;  //串口工作于方式3 TR1=1;  //开启定时器 TI=0; RI=0;}//接收数据函数unsigned char RECE_data(unsigned char *Buff){ unsigned char i,temp; unsigned char lenth; unsigned char check;

RI=0;     //接收数据长度 while(!RI); if(RB8==1)    //若接收到地址帧,则返回0xfe  return 0xfe; lenth=SBUF; RI=0;       check=lenth; for(i=0;i;i++) >

while(!RI);    //接收校验字节 if(RB8==1)    //若接收到地址帧,则返回0xfe  return 0xfe; temp=SBUF; RI=0;       check=temp^check;  //将从主机接收到的校验码与自己计算的校验码比对 if(check!=0)   //校验码不一致,表明数据接收错误,向主机发送错误信号,函数返回0xff {  TI=0;  TB8=0;  SBUF=_ERR_;  while(!TI);  TI=0;  return 0xff; } TI=0;           //校验码一致,表明数据接收正确,向主机发送成功信号,函数返回0x00 TB8=0; SBUF=_SUCC_; while(!TI); TI=0; return 0;} 

void main(){ serial_init(); while(1) {  SM2=1;              //接收地址帧  while(aa!=addr)  //从机等待主机请求自己的地址  {   RI=0;   while(!RI);   aa=SBUF;   RI=0;  }

TI=0;     //一旦被请求,从机返回自己地址作为应答,等待接收数据  TB8=0;  SBUF=addr;  while(!TI);  TI=0;

SM2=0;                  //接收数据帧  aa=0xff;    //从机接收数据,并将数据保存到数据缓冲区  while(aa==0xff)  {   aa=RECE_data(Buff);  }  if(aa==0xfe)   continue;   P1=Buff[2];      //查看接收到的数据 }}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
88855555 2019-02-10
0 回复 举报
写得好!&nbsp;check=lenth;&nbsp;for(i=0;i后面少了些内容,请问是什么啊?谢谢! 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分