19.3 C51多机通信实例

在单片机的多机通信中,除了约定相同的波特率和数据格式外,还需要使用SM2位来实现主从机之间的数据通信。在多机通信系统中,电路可以采用前面双机通信的电路原理图,只不过需要规定完善的多机通信协议。

在多机通信协议中,从机按照从机地址来区分和选择。另外,规定了几条多机通信的指令。

❑从机复位指令0xEE,当发生通信错误的时候,主机发

19.3 C51多机通信实例 - 图1

图 19.12 接收方B的程序流程图

送0xEE复位所有从机。

❑发送数据指令0x01,用于主机向从机发送数据。

❑接收数据命令0x02,用于主机接收从机返回的数据。

另外,从机在通信过程中,如果收到非法指令则返回0x80,如果接收准备完毕则返回0x01,如果发送准备完毕则返回0x02。

19.3.1 主机程序设计

这里在KeilµVision3集成开发环境中,使用Keil C51语言进行设计。建立项目的方法可以参考双机通信一节,这里主要介绍多机通信时主机的程序。

1.主函数

在多机通信主机的主函数中,首先初始化串口,然后分别向从机发送数据和接收数据。主函数的源代码示例如下。其中用到了发送子函数和接收子函数,将在后面的内容中进行介绍。


include<reg52.h>

define uchar unsigned char

define BN 16//传送一次的字节数

uchar SLAVE=0x00;//从机地址

uchar idata ReceiveData[16];

uchar idata SendData[16]={“0123456789abcdef”};

void error(void);//出错子函数

void SendDataFun(void);//发送数据子函数

void ReceiveDataFun();//接收数据子函数

void main(void)//主函数

{

SCON=0x50;//设置串行口:方式1,8位UART,允许接收

TMOD|=0x20;//设置定时器T1,方式2,8位自动重装

PCON=0x80;//设置SMOD=1

TL1=0xF4;//波特率4800bit/s,初值

TH1=0xF4;

TR1=1;//启动定时器T1

SendData();//发送数据

ReceiveDataFun();//接收数据

}


2.出错子函数

出错子函数用于在传输出现错误时,发送出错标志,使从机复位。在这里,出错标志为0xEE。出错子函数的程序代码示例如下。


void error(void)//出错子函数

{

SBUF=0xEE;//发给出错标志

while(TI!=1);//等待发送完

TI=0;

}


3.发送数据子函数

发送数据子函数用于选择通信的从机,并向其发送数据。程序中,首先发送从机的地址来选择通信的从机。接着,发送指令,如果从机准备就绪,则向从机发送数据。发送数据子函数的流程图如图19.13所示。发送数据子函数的程序代码示例如下。

19.3 C51多机通信实例 - 图2

图 19.13 发送数据子函数流程图


void SendDataFun(void)//发送数据子函数

{

uchar a,i,p,comond,addrs;

comond=0x01;//发送数据指令

addrs=SLAVE;//从机地址

SBUF=addrs;//发送呼叫地址

while(TI!=1);//等待发送完

TI=0;

while(RI!=1);//等待从机应答

RI=0;

if(SBUF!=addrs)

error();//若地址出错,发出错标志,从机复位

else

{

TB8=0;//清地址标志位,准备接收数据

SBUF=comond;//发送数据指令

while(TI!=1);

TI=0;

while(RI!=1);

RI=0;

a=SBUF;//接收从机返回的地址帧

if((a&0x80)==0x80)//若主机命令非法,发复位信号给从机

{

TB8=1;

error();

}

else

{

if((a&0x01)==0x01)//从机准备接收就绪

{

do

{

p=0;//清校验和

for(i=0;i<BN;i++)

{

SBUF=SendData[i];//发送数据

p=p+SendData;//计算校验和

while(TI!=1);

TI=0;

}

SBUF=p;//发送校验和给从机

while(TI!=1);

TI=0;

while(RI!=1);

RI=0;

}while(SBUF!=0);//从机接收不正确,主机重新发送

TB8=1;//重置地址标志位

}

}

}

}


4.接收数据子函数

接收数据子函数用于选择通信的从机,并接收其返回的数据。程序中,首先发送从机的地址来选择通信的从机。接着,发送指令,如果从机准备就绪,则读取从机返回的数据。接收数据子函数的流程图如图19.14所示。接收数据子函数的程序代码示例如下。


void ReceiveDataFun()//接收数据子函数

{

uchar a,i,p,comond,addrs;

comond=0x02;//接收数据指令

addrs=SLAVE;//从机地址

SBUF=addrs;//发送呼叫地址

while(TI!=1);//等待发送完

TI=0;

while(RI!=1);//等待从机应答

RI=0;

if(SBUF!=addrs)

error();//若地址出错,发出错标志,从机复位

else

{

TB8=0;//清地址标志位,准备接收数据

SBUF=comond;//发送接收数据指令

while(TI!=1);

TI=0;

while(RI!=1);

RI=0;

a=SBUF;//接收从机的返回地址帧

if((a&0x80)==0x80)//若主机命令非法,发复位信号给从机

{

TB8=1;

error();

}

else

{

if((a&0x02)==0x02)//从机准备发送就绪

{

while(1)

{

p=0;

for(i=0;i<BN;i++)

{

while(RI!=1);

RI=0;

ReceiveData[i]=SBUF;//主机接收数据

p+=rdata[i];

}

while(RI==0);

RI=0;

if(SBUF==p)

{

SBUF=0x00;//校验和相同,发0x00给从机

while(TI!=1);

TI=0;

}

else

{

SBUF=0x0F;//校验和不同,发0x0F给从机

while(TI!=1);

TI=0;

}

}

TB8=1;//重置地址标志位

}

}

}

}


19.3 C51多机通信实例 - 图3

图 19.14 接收数据子函数流程图