单片机级联通讯
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机级联通讯功能实现
多机通信充分利用了单片机内部的多机通信控制位SM2。
当从机SM2=1时,从机只接收主机发出的
地址帧(第九位为1),对数据帧(第九位为0)不予理睬;而当SM2=0时,可接收主机发送过来的所有信息。
多机通信的过程如下:
(1)所有从机SM2均置1,处于只接收地址帧状态。
(2)主机先发送一个地址帧,其中前8位数据表示地址,第9位为1表示该帧为地址帧。
(3)所有从机接收到地址帧后,进行中断处理,把接收到的地址与自身地址相比较。
地址相符时将SM2清成0,脱离多机状态,地址不相符的从机不作任何处理,即保持SM2=1。
(4)地址相符的从机SM2=0,可以接收到主机随后发来的信息,即主机发送的所有信息。
收到信息TB8=0,则表示是数据帧,而对于地址不符的从机SM2=1,收到信息TB8=0,则不予理睬,这样就实现了主机与地址相符的从机之间的双机通信。
(5)被寻址的从机通信结束后置SM2=1,恢复多机通信系统原有的状态。
主机:
设置为SM2=0。
这是双机通信的形式,可以任意的发送和接收
发送:
以TB8=1发送,将发送到所有SM2=1的分机。
这是呼叫某个从机。
以TB8=0发送,将发送到SM2=0的分机。
这是双机通信的形式。
------
从机:
先设置为SM2=1。
这是多机通信的形式,只能收到RB8=1的。
接收:
仅能收到RB8=1的数据,确认是呼叫本机时,令SM2=0。
设置为SM2=0后,是双机通信的形式。
追问那从机的RB8要怎么设,是需要软件设置还是单片机自己识别?在编程的时候要怎么写?回答从机的RB8,不需要编程。
从机的RB8,是接收到的,它是主机发送出来的TB8。
想要对TB8进行控制,需要在主机中编程。
单片机多机通讯
说明:该程序为多机通讯程序,最多可以挂255个从机。
该程序主机发送端与多个从机的接收端相接,主机的接收端与多个从机的发送端相接。
该程序主要的目的为给从机发送作为命令的数据。
该程序调试成功,从机可正确接收。
//================================================= ====================
// 多机通讯主机程序
//zhuji.c
//writer:谷雨2008年3月22日于EDA实验室
//注:主机先发送地址,接收到应答后,再发送数据
//================================================= ====================
#include
#define unit unsigned int
#define uchar unsigned char
#define addr1 0x31 //从机1地址
#define addr2 0x32 //从机2地址
void Uart_Init(void)
{
TMOD=0x20; //定时器T1使用工作方式2
TH1=250;
TH0=250;
TR1=1; //开始计时
PCON=0x80; //SMOD=1;
SCON=0xd0; //工作方式3,9位数据位,波特率9600bit/s,允许接收
TI=1;
RI=1;
}
uchar Receive(void) //接收数据程序
{
uchar Data;
while(!RI); //等待接受完毕
Data=SBUF; //接收数据
RI=0;
return Data;
}
void send_addr(uchar addr) //发送地址
{
uchar tem;
while(addr!=tem) //如果发送的地址与从机应答的地址不一样,则一直发送地址
{
while(!TI); //等待发送完毕
TI=0; //软件复位TI
TB8=1; //发送地址帧
SBUF=addr; //发送地址
tem=Receive();
}
}
void send_data(uchar ddata) //发送数据,但此处由于与从机的协议,禁止发送0xff
{
while(!TI); //等待发送完毕
TI=0; //软件复位TI
TB8=0; //发送数据帧
SBUF=ddata; //发送数据
while(!TI);
}
void main()
{
Uart_Init();
send_addr(addr1); //向从机1发地址
send_data(0x33);
send_addr(addr2); //向从机2发地址
send_data(0x34);
while(1);
}
//================================================= ====================
// 多机通讯从机1程序
//cong1.c
//writer:谷雨2008年3月22日于EDA实验室
//注:从机先接收地址,然后与自己的地址比较,正确了再接收数据,修改地址可挂多个从机
//================================================= ====================
#include
#define unit unsigned int
#define uchar unsigned char
#define addr 0x31 //从机1地址
void Uart_Init(void)
{
TMOD=0x20; //定时器T1使用工作方式2
TH1=250;
TH0=250;
TR1=1; //开始计时
PCON=0x80; //SMOD=1;
SCON=0xd0; //工作方式3,9位数据位,波特率9600bit/s,允许接收
TI=1;
RI=1;
}
void send(uchar Data) //发送数据程序
{
while(!TI); //等待发送完毕
SBUF=Data;
TI=0;
while(!TI);
}
uchar recv_data(void) //接收数据
{
uchar date;
while(!RI); //等待接受完毕
RI=0;
if(RB8==1) //若当前接收为地址帧则返回0xff return 0xff;
date=SBUF;
while(!RI);
return date;
}
void main()
{
uchar tem,Data;
Uart_Init();
while(1)
{
SM2=1; //只接收地址帧
//如果接收到的地址帧不是本机地址,则继续等待while(tem!=addr)
{
while(!RI);
RI=0;
tem=SBUF;
}
//如果是本机地址,发送应答信号,并做好接受数据的准备
TB8=0; //主机不检测该位
send(addr);
SM2=0; //允许接受数据信息
//接收数据
Data=recv_data();
if(Data==0xff)
continue;
switch(Data)
{
case 0x01: //在此可以写入要完成的动作,最多可完成256个动作
break;
case 0x33:
P1=0xaa; //为方便其间,赋值给P1口,测P1口电平来检测该程序
break;
case 0x02:
break;
case 0x03:
break;
default:
break;
}
}
}
主机接收从机数据
主机:
/*
主从通信基本步骤:
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位UA TR;
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位UA TR;
开启总中断;
开启串行中断;
*******************************/ 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: ;
}。