单片机多机通信实现.docx

上传人:b****5 文档编号:30157429 上传时间:2023-08-05 格式:DOCX 页数:33 大小:1.84MB
下载 相关 举报
单片机多机通信实现.docx_第1页
第1页 / 共33页
单片机多机通信实现.docx_第2页
第2页 / 共33页
单片机多机通信实现.docx_第3页
第3页 / 共33页
单片机多机通信实现.docx_第4页
第4页 / 共33页
单片机多机通信实现.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

单片机多机通信实现.docx

《单片机多机通信实现.docx》由会员分享,可在线阅读,更多相关《单片机多机通信实现.docx(33页珍藏版)》请在冰豆网上搜索。

单片机多机通信实现.docx

单片机多机通信实现

单片机多机通信实现

1、设计要求

三片单片机利用串行口进行串行通信:

串行通信的波特率为9600bit/s。

串行口工作方式为方式1的单工串行通信。

2、设计方案

一个主机和两个从机,主机通过按键选择要通信的从机,按键确认后通过矩阵键盘输入要传输的信息,从机接收主机发送的信息并发回长度校验码给主机,主机确认校验信息是否正确,若正确,主机液晶显示“send:

信息”和从机数,从机液晶显示所接收的信息;若错误则主机从发信息,重复前面的步骤。

3、硬件电路设计

3.1单片机最小系统的设计

本系统共用三块单片机,每块单片机均选用AT89S52,最小系统也都一样。

由于三块单片机的主要任务是通信,为了得到准确的波特率,采用振荡频率为11.0592MHz的晶振,再接两个30pF的瓷片电容即可构成单片机的时钟电路。

单片机最小系统电路如下:

图3-1单片机最小系统电路

复位电路也可以换成看门狗电路实现,可使单片机可靠的复位。

为了简化电路设计,本系统采用简单方法,可使单片机上电复位,此外可以通过按键手动复位。

单片机上电即可复位,R1与C3的充电时间大于两倍的机器周期,使RST引脚有足够长的时间保存高电平,使单片机可靠的复位。

正常工作时,按下按键SW1就可以使单片机复位。

3.2矩阵键盘电路设计

图3-2矩阵键盘电路

P1口接4×4的矩阵键盘,共16个按键,分别为0~C及“开始通信”,“选择从机”和“输入信息”键。

P1.0~P1.3接矩阵键盘的行,P1.4~P1.7接矩阵键盘的列。

3.3液晶显示电路设计

液晶显示电路如下图:

图3-3液晶LCD1602显示电路

P0口上拉10K×8的排阻,自己画的排阻符号如下:

图3-4排阻符号

排阻具有九个引脚,一个公共端,另外八个脚分别接到需要接上拉电阻的单片机的P0口。

排阻相当于8个大小均为10K的电阻,在电路中主要其电平转化作用,通过的电流很小,每只电阻的功耗也很小。

如接5V电源,每只电阻的电流约为0.5mA,很小,但是由于P0口是接液晶,不用接排阻也能实现,本着节约的原则在本设计中没有接排阻。

主机整体原理图如下:

图3—5主机原理图

两从机的原理图与主机的原理图仅仅的区别就是没有外接矩阵键盘,其他的都一样。

4电源电路设计

本系统主要供电为5V直流电,为了获得5V的直流电压和足够大的电流,并能提供两种接口,交流与直流输入都能通用,将电源电路设计成如下形式。

图3-6电源电路原理图

交流输入用15V的变压器,将变压器通过接口插到板子上。

直流输入与交流输入类似,都要经过整流桥,确保电解电容C4不会反接,稳压电路公用,用MC7805实现5V直流稳压,最大可输出1A的电流,足以为整个系统供电。

C5与C6用于防止稳压块产生自激振荡。

C4用于滤波,使输入纹波很小,输出端接电容C7,用于防止输出电压突变。

5多机通信协议的算法设计

5.1主从机程序设计

主机模式流程如下:

图3-7主机模式通信流程图

从机模式通信流程如下:

图3-8从机模式通信流程图

5.2键盘程序设计

1号单片机的按键采用矩阵形式,4×4的行列矩阵,共16个按键,可以完成多种控制功能。

1号单片机的键盘程序包括:

按键扫描、获取键值与按键处理几部分。

按键处理又包括实现各种功能的函数。

由键盘程序负责调度。

键盘控制流程如下:

图3-9按键控制流程图

按键扫描采用行扫描法,先输出全零行,再读看是否有按键按下,如有按键,则先消抖动,然后再次确认是否有按键,如果确有按键,再逐行置低电平扫描按下的键的行列位置,最后将按键对应位置的8位二进制码(即低四位表示行号,高四位表示列号)返回;若无按键,则返回0。

获取键值函数为Switch结构的散转程序,根据按键的行与列得到按键的键值,这里预先定义按键的键值为字符‘0’~‘C’、‘E’,‘C’’S’。

以字符形式表示键值利于液晶直接显示。

按键处理为多分支结构,每个分支完成一种功能。

具体流程如下:

图4-1按键处理流程图

通信方向设置流程如下:

图4-2通信方向设置流程图

从机选择流程如下:

图4-3从机选择流程图

5.3系统初始化程序设计

系统初始化程序包括定时器初始化、串口初始化、发送数据初始化和全局变量初始化。

初始化步骤如下:

图4-4系统初始化步骤

对于1号单片机,还有液晶屏初始化这一步。

1号单片机的主程序执行顺序:

图4-51号单片机主程序

定时器初始化使定时器一工作在方式二,波特率设置为9600b/s,并开中断。

串口初始化使串口工作在方式三,9位数据位。

发送与接收数据区的开始地址被已经被指定,用指针常量表示。

发送数据初始化在发送数据区存放待发送的数据串,以空字符作为结束符。

全局变量初始化只需根据需要设置即可。

液晶显示程序只许根据需要调用液晶模块内的函数即可,显示以字符形式输出。

输出字符的ASCII码,液晶显示对应的字符。

用指向code区的指针访问待显示的字符数据串来显示。

6结论

本设计解决了多单片机的串行通信问题,通信速度较快并具有一定的检错能力。

但检错机制不够精确,难以保证很高的正确率,还需进一步完善。

扩展功能:

平权式多机通信协议,这样就可解决通信过程中,争用主机权问题,采用优先编码器为核心的主机权分配电路,可以使电路工作可靠稳定。

 

参考文献

[1]吕汉兴,祁志勇.MCS—51系列单片机多机通信的实现[J].仪表技术,1999.3

[2]郭天祥,51单片机C语言教程——入门,提高,开发,拓展全攻略,2011.5

[3]叶佩.MCS_51单片机的多机通信方式研究[J].计算技术与信息发展,2009.12.

[4]杨玉军.单片机多机通信系统可靠性的研究[J].河南科学,2002.6.

[5]林雪每,彭佳红,姚志成.单片机多机通信协议的设计[J].单片机开发与应用,2006.2.

[6]戴仙金.51单片机及其C语言程序开发实例[M].北京:

清华大学出版社.2008.

 

7、完成效果

A、系统开始工作时的界面:

 

B、选择从机1:

 

传送信息CA6215,结果显示如下:

 

C、选择从机2:

 

传送信息CBA62,结果显示如下:

 

D、系统整体图:

 

程序:

主机

#include

#include

#defineuintunsignedint

#defineucharunsignedchar

#define_SUCC_0x0f//数据传送成功

#define_ERR_0xf0//数据传送失败

unsignedcharTable[16]="";

unsignedcharTable4[]="welcome!

";

unsignedcharTable1[]="slaveis2";

unsignedcharTable2[]="slaveis1";

unsignedcharTable3[16]="send:

";

unsignedcharBuff[20];//数据缓冲区

unsignedchartemp=0xff;

sbitrs=P2^6;//1602的数据/指令选择控制线

sbitrw=P2^5;//1602的读写控制线

sbiten=P2^7;//1602的使能控制线

//voidjian()

sbitKEY1=P3^2;

sbitKEY2=P3^3;

ucharstart,add;

voiddelay_1ms(unsignedintt);

voidjian();

//unsignedcharaddr;

//延时1ms函数

voiddelay_1ms(unsignedintt)

{

unsignedintx,y;

for(x=t;x>0;x--)

for(y=110;y>0;y--);

}

voiddelay11()//延时程序

{

uinti,j;

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

for(j=0;j<=200;j++);

}

voiddelay(uintn)//延时函数

{

uintx,y;

for(x=n;x>0;x--)

for(y=110;y>0;y--);

}

voidlcd_wcom(ucharcom)//1602写命令函数

{

rs=0;//选择指令寄存器

rw=0;//选择写

P0=com;//把命令字送入P2

delay(5);

//延时一小会儿,让1602准备接收数据

en=1;

//使能线电平变化,命令送入1602的8位数据口

en=0;

}

voidlcd_wdat(uchardat)//1602写数据函数

{

rs=1;//选择数据寄存器

rw=0;//选择写

P0=dat;//把要显示的数据送入P2

delay(5);

//延时一小会儿,让1602准备接收数据

en=1;

//使能线电平变化,数据送入1602的8位数据口

en=0;

}

voidlcd_init()

//1602初始化函数

{

lcd_wcom(0x38);

//8位数据,双列,5*7字形

lcd_wcom(0x0c);

//开启显示屏,关光标,光标不闪烁

lcd_wcom(0x06);

//显示地址递增,即写一个数据后,

显示位置右移一位

lcd_wcom(0x01);//清屏

}

//缓冲区初始化

voidBuff_init()

{

unsignedchari;

//将Table里的数据放到缓冲区里

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

{

Buff[i]=Table[i];

delay_1ms(100);

}

}

//串口初始化函数

voidserial_init()

{

TMOD=0x20;//定时器1工作于方式2

TH1=0xfd;

TL1=0xfd;//波特率为9600

PCON=0;

SCON=0xd0;//串口工作于方式3

TR1=1;//开启定时器

TI=0;

RI=0;

}

//发送数据函数

voidSEND_data(unsignedchar*Buff)

{

unsignedchari;

unsignedcharlenth;

unsignedcharcheck;

lenth=strlen(Buff);//计算数据长度

check=lenth;

TI=0;//发送数据长度

TB8=0;//发送数据帧

SBUF=lenth;//发送长度

while(!

TI);

TI=0;

for(i=0;i

{

check=check^Buff[i];

TB8=0;

SBUF=Buff[i];

while(!

TI);

TI=0;

}

TB8=0;//发送校验字节

SBUF=check;

while(!

TI);

TI=0;

}

//向指定从机地址发送数据

voidADDR_data(unsignedaddr)

{

while(temp!

=addr)

//主机等待从机返回其地址作为应答信号

{

TI=0;//发送从机地址

TB8=1;//发送地址帧

SBUF=addr;

while(!

TI);

TI=0;

RI=0;

while(!

RI);

temp=SBUF;

RI=0;

}

temp=_ERR_;

//主机等待从机数据接收成功信号

while(temp!

=_SUCC_)

{

SEND_data(Buff);

RI=0;

while(!

RI);

temp=SBUF;

RI=0;

}

}

voidmain()

{

ucharm;

lcd_init();

lcd_wcom(0x80);

//显示地址设为80H(即00H,)上排第一位

for(m=0;m

//将table[]中的数据依次写入1602显示

{

lcd_wdat(Table4[m]);

delay(4);

}

delay_1ms(3000);

serial_init();

while

(1)

{

jian();

lcd_wcom(0x80);

//显示地址设为80H(即00H,)上排第一位

for(m=0;m

//将table[]中的数据依次写入1602显示

{

lcd_wdat(Table[m]);

delay(4);

}

if(add!

=0)

{

lcd_wcom(0x80+40);

//显示地址设为80H(即00H,)上排第一位

for(m=0;m

//将table[]中的数据依次写入1602显示

{

lcd_wdat(Table1[m]);

delay(4);

}

}

else

{

lcd_wcom(0x80+40);

//显示地址设为80H(即00H,)上排第一位

for(m=0;m

//将table[]中的数据依次写入1602显示

{

lcd_wdat(Table2[m]);

delay(4);

}

}

if(start!

=0)

{

for(m=0;m

{

Table3[m+5]=Table[m];

}

Buff_init();

lcd_wcom(0x80);

for(m=0;m

//将table[]中的数据依次写入1602显示

{

lcd_wdat(Table3[m]);

delay(4);

}

if(add!

=0)

ADDR_data(0x01);

else

ADDR_data(0x02);

}

}

}

voidjian()//键盘的扫描

{

staticuchartemp,flag,num,wei;

P1=0xef;//选中其中的第一列

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{delay11();//延时10ms,消抖

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

switch(temp)

{case0x0e:

num='0';wei++;

break;//0

case0x0d:

num='1';

wei++;

break;//1

case0x0b:

num='2';wei++;

break;//2

case0x07:

num='3';wei++;

break;//3

}

while(temp!

=0x0f)

//松手检测

{

temp=P1;

temp&=0x0f;

}

}

}

P1=0xdf;//选中第二列

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

delay11();//延时10ms

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

switch(temp)

{

case0x0e:

num='4';wei++;

break;//4

case0x0d:

num='5';wei++;

break;//5

case0x0b:

num='6';wei++;

break;//6

case0x07:

num='7';wei++;

break;//7

}

while(temp!

=0x0f)//松手检测

{

temp=P1;

temp&=0x0f;

}

}

}

P1=0xbf;

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

delay11();//延时10ms

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

switch(temp)

{

case0x0e:

num='8';wei++;

break;//8

case0x0d:

num='9';wei++;

break;//9

case0x0b:

num='A';wei++;

break;

case0x07:

num='B';wei++;

break;}

//while(temp!

=0x0f)松手检测

//break;

//}

while(temp!

=0x0f)//松手检测

{

temp=P1;

temp&=0x0f;

}

}

}

P1=0x7f;

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

delay11();//延时10ms

temp=P1;

temp&=0x0f;

if(temp!

=0x0f)

{

switch(temp)

{

case0x0e:

num='C';wei++;

break;

case0x0d:

start=~start;

break;

case0x0b:

add=~add;

break;

case0x07:

num='C';wei=0;flag=~flag;

break;

}

while(temp!

=0x0f)//松手检测

{temp=P1;

temp&=0x0f;

}

}

}

if(flag!

=0)

{

Table[wei]=num;

}

}

从机:

从机1程序

(从机2的程序只要把从机地址改了就可以

其他的都和从机1相同)

#include

#include

#defineuintunsignedint

#defineucharunsignedchar

#defineaddr0x02//从机1的地址

#define_SUCC_0x0f//数据传送成功

#define_ERR_0xf0//数据传送失败

unsignedcharaa=0xff;//主机与从机之间通信标志

unsignedcharBuff[20];//数据缓冲区

sbitrs=P2^0;//1602的数据/指令选择控制线

sbitrw=P2^1;//1602的读写控制线

sbiten=P2^2;//1602的使能控制线

sbitLED1=P3^6;//绿色指示灯

sbitLED2=P3^7;//红色指示灯

ucharcodetable[]="Information:

";//要显示的内容1放入数组table

//ucharcodetable1[]="123456789";//要显示的内容2放入数组table1

voiddelay(uintn)//延时函数

{

uintx,y;

for(x=n;x>0;x--)

for(y=110;y>0;y--);

}

voidlcd_wcom(ucharcom)//1602写命令函数

{

rs=0;//选择指令寄存器

rw=0;//选择写

P0=com;//把命令字送入P2

delay(5);//延时一小会儿,让1602准备接收数据

en=1;//使能线电平变化,命令送入1602的8位数据口

en=0;

}

voidlcd_wdat(uchardat)//1602写数据函数

{

rs=1;//选择数据寄存器

rw=0;//选择写

P0=dat;//把要显示的数据送入P2

delay(5);//延时一小会儿,让1602准备接收数据

en=1;//使能线电平变化,数据送入1602的8位数据口

en=0;

}

voidlcd_init()//1602初始化函数

{

lcd_wcom(0x38);//8位数据,双列,5*7字形

lcd_wcom(0x0c);//开启显示屏,关光标,光标不闪烁

lcd_wcom(0x06);//显示地址递增,即写一个数据后,显示位置右移一位

lcd_wcom(0x01);//清屏

}

//串口初始化函数

voidserial_init()

{

TMOD=0x20;//定时器1工作于方式2

TH1=0xfd;

TL1=0xfd;//波特率为9600

PCON=0;

SCON=0xd0;//串口工作于方式3

TR1=1;//开启定时器

TI=0;

RI=0;

}

//接收数据函数

unsignedcharRECE_data(unsignedchar*Buff)

{

unsignedchari,temp;

unsignedcharlenth;

unsignedcharcheck;

RI=0;//接收数据长度

while(!

RI);

if(RB8==1)//若接收到地址帧,则返回0xfe

return0xfe;

lenth=SBUF;

RI=0;

check=lenth;

for(i=0;i

{

while(!

RI);

if(RB8==1)//若接收到地址帧,则返回0xfe

return0xfe;

Buff[i]=SBUF;

check=check^(Buff[i]);

RI=0;

}

whil

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1