模仿I2C协议利用串口组网
先祭上代码
书上郭天祥的代码有点问题,没法进行通信,但是程序流程图是对的。
我百度过关于51单片机串口多机组网资料,除了郭天祥的代码目前没看到有其他的资料。
我在郭天祥的基础上再改进一下
单片机连接方式![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/17a20610feec6cb6a55cfa2167adfb12.png)
主机通信流程图
主机代码
/***单片机串口组网
* 主机程序
* MASTER
*
***/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define SLAVE 0x02
#define BN 16
uchar rbuf[16];
uchar tbuf[16]={"master transmit"};
void err(void)//发送复位信号
{
SBUF = 0xff;
while(TI!=1);
TI = 0;
}
uchar master(uchar addr,uchar command)
{
uchar aa,i,p;
while(1)
{
SBUF = SLAVE;//呼叫从机地址
while(TI!=1);
TI = 0;
while(RI!=1);//等待从机响应
RI = 0;
if(SBUF!=addr)//如果地址错误,发送复位信号
{
err();
}
else //发送完地址发送数据
{
TB8 = 0;//清除地址标志,变为数字标志
SBUF = command;//发命令
while(TI!=1);
TI = 0;
while(RI!=1);//等待从机响应
RI = 0;
//读取返回的数据
aa = SBUF; //接收从机返回的状态
if((aa&0x08)==0x08)//若命令未接收,发送复位信号
{
TB8 = 1;
err();
}
else
{
if(command==0x01)//是发送命令
{
//************
if((aa&0x01)==0x01)//从机准备好接收
{
do
{
p = 0;
//此处可优化
for(i=0;i<BN;i++)
{
SBUF = tbuf[i];
p += tbuf[i]; //p为校验和
while(TI!=1);
TI = 0;
}
//发送校验和
SBUF = p;
while(TI!=1);
TI = 0;
while(RI!=1);
RI = 0;
}
while(SBUF!=0);//接收不对,重新发送
TB8 = 1;//切换为地址标志
return(0);
}
//************
else
{
if((aa&0x02)==0x02)//接收命令,从机准备好发送
{
while(1)
{
p = 0;//清校验
//接收数据,并计算校验p
for(i=0;i<BN;i++)
{
while(RI!=1);
RI = 0;
rbuf[i] = SBUF;
p += rbuf[i];
}
//接收p
while(RI!=1);
RI=0;
if(SBUF==p) //校验和相同发送0x00,向从机确认
{
SBUF=0x00;
while(TI!=1);
TI = 0;
break;
}
else
{
SBUF = 0xff;//校验和不同发送0xff,
while(TI!=1);
TI = 0;
}
}
TB8 = 1;//切换回地址标志
return(0);
}
}
}
}
}
}
}
void Init_Timer()
{
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
PCON = 0x00;
TR1 = 1;
SCON = 0x50;
}
void main()
{
Init_Timer();
master(SLAVE,0x01);
master(SLAVE,0x02);
while(1);
}
从机通信流程图
从机代码
/***单片机串口组网
* 从机程序
* SLAVE
*
***/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define SLAVE 0x02
#define BN 16
uchar rebuf[16];
uchar trbuf[16];
bit tready;
bit rready;
//发送数据块
void str(void)
{
uchar p,i;
tready = 0;
do
{
p = 0;
for(i=0;i<BN;i++)
{
SBUF = trbuf[i];
p += trbuf[i];
while(TI!=1);
TI = 0;
}
SBUF = p; //发送校验和
while(TI!=1);
TI = 0;
while(RI!=1);
RI = 0;
}while(SBUF!=0);//主机接收错误,重新发送
SM2 = 1;
ES = 1; //发送完,恢复监听
}
void sre(void)//接收数据块
{
uchar p,i;
rready = 0;
while(1)
{
p = 0;
for(i=0;i<BN;i++)
{
while(RI!=1);
RI = 0;
rebuf[i]=SBUF;
p += rebuf[i];
}
while(RI!=1);
RI = 0; //等待接收完成
if(SBUF==p)
{
SBUF = 0x00;//校验和相同发送0x00
break;
}
else
{
SBUF = 0xff;
while(TI==0);//校验和不同,重新接收
TI = 0;
}
}
SM2 = 1;
ES = 1;
}
void Init_Timer()
{
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
PCON = 0x00;
TR1 = 1;
SCON = 0x50;
ES = 1;
EA = 1;
}
void main()
{
Init_Timer();
while(1)
{
tready = 1;
rready = 1;
}
}
void ssio(void) interrupt 4
{
uchar a;
RI = 0;
ES = 0; //关闭串口中断
if(SBUF!=SLAVE) //非本机地址
{
ES = 1; //继续监听
goto reti;
}
SM2 = 0; //取消监听状态
SBUF = SLAVE;//发送本机地址,让主机识别
while(TI!=1);
TI = 0;
while(RI!=1);
RI = 0;
if(RB8==1) //????
{
SM2 = 1;
ES = 1;
goto reti;
} //如果接收到复位信号,恢复监听
a = SBUF; //传递接收的数据
if(a==0x01)//从主机接收到数据
{
if(rready==1)
{
SBUF = 0x01;
}
else
{
SBUF = 0x00;
}
while(TI!=1);
TI = 0;
while(RI!=1);
RI = 0;
if(RB8==1)
{
SM2 = 1;
ES = 1;
goto reti;
}
sre(); //接收数据
}
else
{
if(a==0x02)//从机向主机发数据
{
if(tready==1)
{
SBUF = 0x02; //向主机表明,已准备好数据发送
}
else
{
SBUF = 0x00;
}
while(TI!=1);
TI = 0;
while(RI!=1);
RI = 0;
if(RB8==1)
{
SM2 = 1;
ES = 1;
goto reti;
}
str();
}
else
{
SBUF = 0x80;//非法命令,发送状态
while(TI!=1);
TI=0;
SM2 = 1;
ES = 1; //开启监听
}
}
reti:;
}
目前做到了地址识别,向从机发送数据,但被数据校验难到了,待更新。。。