使用了3块80c51的单片机,其中U1为主机控制其他两个从机U2,U3。每个单片机上都有一个数码管用来显示数据。主机上有两个按键KEY_1,KEY_2,分别用来控制不同的从机。
主要实现的目标就是通过写多机通讯来了解他们其中的协议,以及简单协议的写法!本程序主要达到了一下效果,主机可以通过发送命令来控制从机:发送数据给从机、接收从机的数据。然后将从机或者主机显示的数据显示在数码管上。
0x01表示:主机向从机发送数据
0x02表示:从机向主机发送数剧
●主机发送地址帧,从机接收到地址帧后就会与本机地址进行比对,如果正确则发送自己的地址应答;如果不正确,则丢弃数据,继续监测等待数据;
●从机接收地址正确后,返回自己的地址作为应答信号;如果主机接收到的数据与自己发送的地址数据相同,就会发送命令(是让从机接收数据还是发送数据);如果与自己发送的地址数据不同,则发送0xff,当从机接收到数据得到RB8 ==1,则进入继续监测等待数据。
●主机发送命令,从机接收到命令后,就会返回接收到的命令作为应答(没有处理异常情况);主机监测到应答数据正确就会发送数据,并且等待从机的应答信号(0x11),接收到应答信号后,再发送第二个数据(这个地方主机没有处理异常情况),指导发送数据结束
●发送数据接收后,主机会发送校验和,与从机接收的数据的校验和比较,如果检验和相同说明发送数据正确,然后就退出程序;如果检验和发送不正确则重新发送数据。
串行口有一个很重要的寄存器:
#include
#define uint unsigned int
#define uchar unsigned char
sbit key_1 = P1^0;
sbit key_2 = P1^1;
sbit Led = P1^7;
#define master_U1 0x01 //主机地址
#define slave_U2 0x02 //从机地址
#define slave_U3 0x03 //从机地址
uchar tbuf[16] = {0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uchar rbuf[16];//待接收数据的数组
void DelayUs2x(unsigned char t)
{
while(--t);
}
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
void Uart_init(void)
{
SCON |= 0xf8;//工作方式1,T1,R1置零,允许串行口接收数据
TMOD |= 0x20;//定时器1,模式2
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
EA = 1;//打开总中断
ES = 1;//打开串口中断
}
void master_send(uchar addr,uchar command)
{
uchar status,check,i = 0;
SBUF = addr;//发送要操作的地址
while(!TI);
DelayMs(10);
TI = 0;//发送从机地址
while(!RI);
RI = 0;//等待从机地址答复
if(addr!=SBUF)//如果返回的地址与要操作的地址不同
{
SBUF=0xff;
while(!TI);
TI=0;
}
else
{
TB8=0;
SBUF=command;
while(!TI);
TI = 0; //发送命令
while(!RI);
RI = 0;//等待从机的回复
status = SBUF; //从机发送确认命令
if(status == 0x80)
{
TB8 = 1;
}
else
{
if(status == 0x01)//主机知道从机已经准备好接收数据,就进入发送状态
{
while(1)
{
check = 0;
for(i = 0;i < 16;i++)
{
SBUF = tbuf[i];
while(!TI);
TI = 0;
while(!RI); //等待从机返回确认信号0x11
RI = 0;
check += tbuf[i];//校验和
DelayMs(2000);
}
SBUF = check;//向从机发送校验和
while(!TI);//发送校验和给从地址
TI = 0;
while(!RI);
RI = 0;//接收从地址返回的数据(0x00或者0xff)
if(SBUF == 0x00)
{
break;
}
//接收到0x00表明校验正确,则跳出发送函数,如果接收到0xff则表明校验出错,重新发送
}
}
if(status == 0x02)//主机知道要接收来自从机的数据了
{
while(1)
{
check = 0;
for(i = 0;i < 16; i++)
{
while(!RI);
RI = 0;
rbuf[i] = SBUF;
P2 = rbuf[i];
SBUF = 0x11;//每收到一个数据,发送0x11
while(!TI); //表示接受到数据后的确认
TI = 0;
check += rbuf[i];
}
while(!RI);
RI = 0;
if(check == SBUF)//如果主机数据的校验和与从机的校验和相等,则返回主机0x00
{ //否则,需要重新等待接收数据。
SBUF = 0x00;
while(!TI);
TI = 0;
P2 = 0;
break;
}
}
}
}
}
}
void main()
{
Uart_init();
P2 = 0;
Led = 1;
if(!key_1)
{
DelayMs(20);
if(!key_1)
{
master_send(slave_U2,0x02);
}
}
if(!key_2)
{
DelayMs(20);
if(!key_2)
{
master_send(slave_U3,0x01);
}
Led = 0;
}
}
/**从机1 U3**/
#include
#define uint unsigned int
#define uchar unsigned char
//#define slave_U2 0x02
#define slave_U3 0x03
sbit key = P1^0;
static uchar tbuf[] = {0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
static uchar rbuf[16];
void Uart_receive();
void Send_receive();
void DelayUs2x(unsigned char t)
{
while(--t);
}
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
void Uart_init()//串口初始化
{
PCON = 0;
SCON |= 0xf8;
TMOD |= 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
EA = 1;
ES = 1;
}
void main()
{
P2 = 0;
Uart_init();
while(1);
}
void Ser_uart() interrupt 4
{
uchar save;
RI = 0;
ES = 0;
if(SBUF != slave_U3)
{
ES = 1;
goto end; //如果发送的从机地址与本从机地址不相符则,执行此语句。
}
SM2 = 0;//设置为单击模式
SBUF = slave_U3;//发送从机地址给主机
while(!TI);
TI = 0;
while(!RI);//接收主机发来的命令
RI = 0;
if(RB8 == 1)//如果返回的地址出错误,则发送0xff,RB8 = 1;
{
SM2 = 1;
ES = 1;
goto end;//进入等待地址帧模式
}
save = SBUF;//将接收到的命令存在save中
if(save == 0x01)//如果接收的命令是0x01
{
SBUF = 0x01;//向主机发送03表示确认,已经做好准备
while(!TI);
TI = 0;
Uart_receive();//进入接收状态等待
}
else
{
if(save == 0x02)
{
SBUF = 0x02;//告诉主机,要准备发送数据了
while(!TI);
TI = 0;
Send_receive();//进入发送数据函数
}
else
{
SBUF = 0x80;
while(!TI);
TI = 0;
SM2 = 1;
ES = 1;
goto end;
}
}
end:;
}
void Uart_receive()
{
uchar check,i;
while(1)
{
check = 0;
for(i = 0;i < 16;i++)
{
while(!RI);
RI = 0;
rbuf[i] = SBUF;
P2 = rbuf[i];//显示接受到的数据
SBUF = 0x11;//每收到一个数据,发送0x11
while(!TI); //表示接受到数据后的确认
TI = 0;
check += rbuf[i];
}
while(!RI);
RI = 0;
if(SBUF == check)//如果主机数据的校验和与从机的校验和相等,则返回主机0x00
{
SBUF = 0x00;
while(!TI);
TI = 0;
P2 = 0;
break;
}
else//如果主机数据的校验和与从机的校验和不相等,则重新发送数据
{
SBUF = 0xff;
while(!TI);
TI = 0;
}
}
}
void Send_receive()
{
uchar check,i;
while(1)
{
check = 0;
for(i = 0;i < 11;i++)
{
SBUF = tbuf[i];
while(!TI);
TI = 0;
check += tbuf[i];
}
SBUF = check;
while(!TI); //发送校验数据
TI = 0;
while(!RI);
RI = 0;//等待校验结果,接收主地址返回的数据(0x00或者0xff)
if(SBUF == 0x00)
break;
//接收到0x00表明校验正确,则跳出发送函数,如果接收到0xff则表明校验出错,重新发送
}
while(1)
{
for(i = 0;i < 16;i ++)
P2 = rbuf[i];
DelayMs(1000);
}
}
/**从机2,电路图U2**/
#include
#define uint unsigned int
#define uchar unsigned char
#define slave_U2 0x02
//#define slave_U3 0x03
sbit Key = P1^0;
static uchar tbuf[] = {0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
static uchar rbuf[16];
void Uart_receive();
void Send_receive();
static uchar rbuf[16];
void DelayUs2x(unsigned char t)
{
while(--t);
}
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
void Uart_init()//串口初始化
{
PCON = 0;
SCON |= 0xf8;
TMOD |= 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
EA = 1;
ES = 1;
}
void main()
{
P2 = 0;
Uart_init();
while(1);
}
void Ser_uart() interrupt 4
{
uchar save;
RI = 0;
ES = 0;
if(SBUF != slave_U2)
{
ES = 1;
goto end; //如果发送的从机地址与本从机地址不相符则,执行此语句。
}
SM2 = 0;//设置为单击模式
SBUF = slave_U2;//发送从机地址给主机
while(!TI);
TI = 0;
while(!RI);//接收主机发来的命令
RI = 0;
if(RB8 == 1)//如果返回的地址出错误,则发送0xff,RB8 = 1;
{
SM2 = 1;
ES = 1;
goto end;//进入等待地址帧模式
}
save = SBUF;//将接收到的命令存在save中
if(save == 0x01)//如果接收的命令是0x01
{
SBUF = 0x01;//向主机发送01表示确认,已经做好准备
while(!TI);
TI = 0;
Uart_receive();//进入接收状态等待
}
else
{
if(save == 0x02)
{
SBUF = 0x02;//告诉主机,要准备发送数据了
while(!TI);
TI = 0;
Send_receive();//进入发送数据函数
//DelayMs(1000);
}
else
{
SBUF = 0x80;
while(!TI);
TI = 0;
SM2 = 1;
ES = 1;
goto end;
}
}
end:;
}
void Uart_receive()
{
uchar check,i;
while(1)
{
check = 0;
for(i = 0;i < 11;i++)
{
while(!RI);
RI = 0;
tbuf[i] = SBUF;
SBUF = 0x11;//每收到一个数据,发送0x11
while(!TI); //表示接受到数据后的确认
TI = 0;
check += tbuf[i];
}
while(!RI);
RI = 0;
if(SBUF == check)//如果主机数据的校验和与从机的校验和相等,则返回主机0x00
{
SBUF = 0x00;
while(!TI);
TI = 0;
break;
}
else//如果主机数据的校验和与从机的校验和不相等,则重新发送数据
{
SBUF = 0xff;
while(!TI);
TI = 0;
}
}
}
void Send_receive()
{
uchar check,i;
while(1)
{
check = 0;
for(i = 0;i < 16;i++)
{
SBUF = tbuf[i];
while(!TI);
TI = 0;
while(!RI);
RI = 0;
check += tbuf[i];
DelayMs(2000);
}
SBUF = check;
while(!TI); //发送校验数据
TI = 0;
while(!RI);
RI = 0;//等待校验结果,接收主地址返回的数据(0x00或者0xff)
if(SBUF == 0x00)
break;
//接收到0x00表明校验正确,则跳出发送函数,如果接收到0xff则表明校验出错,重新发送
}
}