主机接收从机数据
主机:
/*
主从通信基本步骤:
1. 主机从机初始化为方式2或者3,从机都置SM2=1,允许中断
2. 主机置TB8=1,发送从机地址
3. 所有从机均接收主机发送要寻址的从机地址
4. 被寻址的从机确认地址后,置本机SM2=0,向主机返回地址,供主机核对
5. 核对无误后,主机向被寻址的从机发送命令,通知从机接受或者发送数据。
6. 本次通信结束后,主从机重置SM2=1,主机可再对其他从机寻址
*/
/*
★数据的传递主机发送信息,可以传送到各个从机或指定从机,各从机发送的信息只能被主机接收。
★多机通信(关键是地址帧的识别)
◇ 主机发送:地址帧、数据帧的鉴别是通过第9位数据确定:
TB8=1,地址帧
TB8=0,数据帧
◇从机接收:
各从机串行口工作在方式2、方式3下;
多机通信标志SM2(SCON.5)=1;
检查接收到的第9位RB8(SCON.2),当:
RB8=1:地址帧,将地址装入SBUF,置位RI,发出接收中断请求;判断主机发送地址是否与本机相符,若相符,则将从机SM2清0(变成直通方式),准备接收其后传送来的数据。
RB8=0:数据帧,对SM2=1,RB8=0的从机,接收数据丢弃,而对SM2=0的从机:直通方式,不论RB8是0还是1,都将接受到的数据送SBUF,并发出中断请求。
多机通信的过程总结如下:
(1)全部从机串行口工作方式初始化为2或3,置位SM2,允许中断;
(2)主机置位TB8,发送要寻址的从机地址;
(3)所有的从机均接收主机发送的地址,进入中断进行地址比较;
(4)确认寻址从机,自身SM2清0,向主机返回地址供主机核对;
(5)主机核对无误,向被寻址从机发送发送命令,通知从机进行一对一数据通信。
*/
#include<reg52.h>
#define BN 16
#define uchar unsigned char
#define uint unsigned int
uchar slave=0x00;
uchar idata rdata[16];
uchar idata tdata[16]={"abcdefghijklmnop"};
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
void delay(uint n)
{
uint i;
uchar j;
for(i=n;i>0;i--)
for(j=110;j>0;j--);
}
/**************************************************/
void send(uchar dat)
{
SBUF=dat;
while(!TI);
TI=0;
}
/****************** c********************************/
void error(void)
{
SBUF=0xff;
while(!TI);
TI=0;
}
/**************************************************/
void master(uchar address,uchar command)
{
uchar command_temp,i,p;
while(1)
{
TB8=1; //置地址标志位
send(slave); //发送地址;
while(RI!=1); /*等待从机发送地址*/
RI=0;
if(SBUF!=address) //地址不符合发送0xff
error();
else //地址相符合;
{
led1=0;
TB8=0; //发送数据标志位
send(command);
while(RI!=1);
RI=0;
command_temp=SBUF;
if((command_temp&0x80)==0x80) //命令不正确发送复位信号
{
TB8=1;
error();
}
else
{
led2=0;
//delay(1000);
if(command==0x02)
{
if((command_temp&0x02)==0x02) //从机准备好发送
{
while(1)
{
p=0;
for(i=0;i<2;i++)
{
while(RI!=1);
RI=0;
rdata[i]=SBUF;
p+=rdata[i];
}
while(RI!=1);
RI=0;
if(SBUF==p)
{
send(0x00);
led3=0;
//delay(1000);
break;
}
else
{
send(0xff);
}
}
while(RI!=1);
RI=0;
P2=SBUF;
TB8=1; /*置地址标志位1*/
}
}
}
}
}
}
/*******************************
1.定时器1,工作模式2;
2.装入初值,波特率;
3.启动定时器/计数器1;
4.串行工作方式1,8位UATR;
5.开启总中断;
6.开启串行中断;
*******************************/
void main()
{
TMOD=0x20; //定时器1,工作模式2
TH1=0xfd; //载入波特率,9600kps,晶振11.0592MHz
TL1=0xfd;
TR1=1; //开启定时器1
PCON=0x00; //允许接收
SCON=0xf0; //SM0=1,SM1=1,SM2=1,REN=1,串行工作方式3
EA=1; //开总中断
ES=1; //开串行中断
while(1)
{
master(slave,0x02);/*向从机0x00接收数据*/;
}
从机 : #include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define slave 0x00
#define BN 16
bit tready; //发送准备标志
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
uchar idata tdata[16];
void delayms(uint xms)
{
uchar i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
uchar code table[]={
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e
};
void send(uchar keynum)
{
//SBUF=keynum;
SBUF=table[keynum];
while(!TI);
TI=0;
}
/**********************************/
void sent() //向主机发送数据
{
uchar p,i;
tready=0;
do
{
p=0;
for(i=0;i<2;i++)
{
tdata[i]=SBUF;
p+=tdata[i];
while(!TI);TI=0;
}
SBUF=p;
while(!TI);TI=0;
while(!RI);RI=0;
} while(SBUF!=0);
led3=0;
SM2=1;
ES=1;
}
/*******************************
定时器1,工作模式2;
装入初值,波特率;
启动定时器/计数器1;
串行工作方式1,8位UATR;
开启总中断;
开启串行中断;
*******************************/
void main()
{
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
TR1=1;
PCON=0x00;
SCON=0xf0;
EA=1;
ES=1;
while(1)
{
keyscan();
tready=1;
}
}
/********************************/
void ssio() interrupt 4 using 1
{
void sent();
uchar a,x;
RI=0;
ES=0;
if(SBUF!=slave)
{
ES=1;
goto reti;
}
led1=0;
SM2=0;
SBUF=slave;
while(!TI);TI=0;
while(!RI);RI=0;
led2=0; //地址标志位
if(RB8==1)
{
SM2=1;
ES=1;
goto reti;
}
a=SBUF;
if(a==0x02)
{
if(tready==1)
SBUF=0x02;
else
SBUF=0x00;
while(!TI);TI=0;
while(!RI);RI=0;
if(RB8==1)
{
SM2=1;
ES=1;
goto reti;
}
led2=0;
sent();
}
else
{
SBUF=0x80;
while(!TI);TI=0;
SM2=1;
ES=1;
}
reti: ;
} }
主机却接收不到数据 |