单片机单片机课程设计双机串行通信e.docx
《单片机单片机课程设计双机串行通信e.docx》由会员分享,可在线阅读,更多相关《单片机单片机课程设计双机串行通信e.docx(52页珍藏版)》请在冰豆网上搜索。
单片机单片机课程设计双机串行通信e
一、总体设计
1.实现功能:
用单片机的串口模拟短信的收发,当A主机要向B主机发送一行字符串时,首先A主机把这行字符串打印到1602LCD液晶屏幕上,当A主机按发送按键的时候,A主机向B主机发送一行字符串,这时字符串会通过串口发送到B主机上,当B主机收到字符串时,会在1602LCD液晶屏幕上把字符串打印出来,这时按下B主机上的接受按键,B主机会把要发送的字符串,打印到B主机的1602LCD液晶屏幕上,按下B主机的发送按键,这时B主机会通过串口向A主机发送字符串。
最后用两个矩阵键盘模拟发送短信用的字母键盘,A主机可以通过矩阵键盘输入想要发送的数据,然后按发送按键发送,同样B主机也可以通过矩阵键盘输入信息,然后通过发送按键发送。
2.设计方案:
首先把两个ATS89C51各自连接成单片机最小系统,在把他们的TXD、RXD口分别与MAX232相连,然后一个MAX232的T1out和R1IN,分别与另一个MAX232的R1IN和T1out相连,P0口接矩阵键盘,P1口接液晶显示的数据端。
总的电路图如图:
图1、总电路图
二、设计基础
1.单片机串行口通信方式
图2.AT89C51
计算机与外界的信息交换称为通信,常用的通信方式有两种:
并行通信和串行通信。
51单片机用4个接口与外界进行数据输入与数据输出就是并行通信,并行通信的特点是传输信号的速度快,但所用的信号线较多,成本高,传输的距离较近。
串行通信的特点是只用两条信号线(一条信号线,再加一条地线作为信号回路)即可完成通信,成本低,传输的距离较远。
51单片机的串行接口是一个全双工的接口,它可以作为UART(通用异步接受和发送器)用,也可以作为同步移位寄存器用。
51单片机串行接口的结构如下:
(1)数据缓冲器(SBUF)
接受或发送的数据都要先送到SBUF缓存。
有两个,一个缓存,另一个接受,用同一个接地址99H,发送时用指令将数据送到SBUF即可启动发送;接收时用指令将SBUF中接收到的数据取出。
(2)串行控制寄存器(PCON)
SCON用于串行通信方式的选择,收发控制及状态指示,各位含义如下:
SM0
SM1
SM2
REN
TB8
RB8
TI
RI
SM0,SM1:
串行接口工作方式选择位,这两位组合成00,01,10,11对应于工作方式0、1、2、3。
串行接口工作方式特点见下表
SM0
SM1
工作方式
功能
波特率
0
0
0
8位同步移位寄存器(用于I/O扩展)
fORC/12
0
1
1
10位异步串行通信(UART)
可变(T1溢出率*2SMOD/32)
1
0
2
11位异步串行通信(UART)
fORC/64或fORC/32
1
1
3
11位异步串行通信(UART)
可变(T1溢出率*2SMOD/32)
SM2:
多机通信控制位。
REN:
接收允许控制位。
软件置1允许接收;软件置0禁止接收。
TB8:
方式2或3时,TB8为要发送的第9位数据,根据需要由软件置1或清0。
RB8:
在方式2或3时,RB8位接收到的第9位数据,实际为主机发送的第9位数据TB8,使从机根据这一位来判断主机发送的时呼叫地址还是要传送的数据。
TI:
发送中断标志。
发送完一帧数据后由硬件自动置位,并申请中断。
必须要软件清零后才能继续发送。
RI:
接收中断标志。
接收完一帧数据后由硬件自动置位,并申请中断。
必须要软件清零后才能继续接收。
(3)输入移位寄存器
接收的数据先串行进入输入移位寄存器,8位数据全移入后,再并行送入接收SBUF中。
(4)波特率发生器
波特率发生器用来控制串行通信的数据传输速率的,51系列单片机用定时器T1作为波特率发生器,T1设置在定时方式。
波特率用来表示串行通信数据传输快慢程度的物理量,定义为每秒钟传送的数据位数。
(5)电源控制寄存器PCON,其最高位为SMOD。
(6)波特率计算
对于方式1和方式3,波特率都是由定时器1的溢出率决定,计算公式如下:
定时器T1工作于方式0时,k=13;
定时器T1工作于方式1时,k=16;
定时器T1工作于方式2和方式3,k=8;
2、1602LCD操作
(1)1602LCD特性:
+5V电压,对比度可调
内含复位电路
提供各种控制命令,如:
清屏、字符闪烁、光标闪烁、显示移位等多种功能
有80字节显示数据存储器DDRAM
内建有160个5X7点阵的字型的字符发生器CGROM
8个可由用户自定义的5X7的字符发生器CGRAM
字符型LCD1602通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚)
图3、1602各引脚的定义
HD44780内置了DDRAM(显示数据存储RAM)、CGROM(字符存储ROM)和CGRAM(用户自定义RAM)。
DDRAM就是显示数据RAM,用来寄存待显示的字符代码。
共80个字节,其地址和屏幕的对应关系如下表:
也就是说想要在LCD1602屏幕的第一行第一列显示一个“A”字,就要向DDRAM的00H地址写入“A”的代码就行了。
但具体的写入是要按LCD模块的指令格式来进行的,后面我会讲到的。
一行有40个地址在1602中我们就用前16个就行了。
第二行也一样用前16个地址。
对应如下:
DDRAM地址与显示位置的对应关系
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如下表所示,这些字符有:
阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”
图4、1602字符表
上表中的字符代码与我们PC中的字符代码是基本一致的。
因此我们在向DDRAM写C51字符代码程序时甚至可以直接用P1='A'这样的方法。
PC在编译时就把“A”先转为41H代码了。
字符代码0x00~0x0F为用户自定义的字符图形RAM(对于5X8点阵的字符,可以存放8组),就是CGRAM了。
对DDRAM的内容和地址操作,HD44780的指令集及其设置说明,共有11条指令:
基本操作时序:
读状态 输入:
RS=L,RW=H,E=H
输出:
DB0~DB7=状态字
写指令 输入:
RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码
输出:
无
读数据 输入:
RS=H,RW=H,E=H
输出:
DB0~DB7=数据
写数据 输入:
RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据
输出:
无
1.清屏指令
功能:
<1>清除液晶显示器,即将DDRAM的内容全部填入“空白”的字符码20H;
<2>光标归位,即将光标撤回液晶显示屏的左上方;
<3>将地址计数器(AC)的值设为0。
2.光标归位指令
功能:
<1>把光标撤回到显示器的左上方;
<2>把地址计数器(AC)的值设置为0;
<3>保持DDRAM的内容不变
3.输入模式设置指令
功能:
设定每次写入1位数据后光标的移位方向,并且设定每次写入的一个字符是否
移动。
参数设定的情况如下所示:
位名 设置
I/D 0=写入新数据后光标左移 1=写入新数据后光标右移
S 0=写入新数据后显示屏不移动1=写入新数据后显示屏整体右移1个字
4.显示开关控制指令
功能:
控制显示器开/关、光标显示/关闭以及光标是否闪烁。
参数设定的情况如下:
位名 设置
D 0=显示功能关 1=显示功能开
C 0=无光标 1=有光标
B 0=光标不闪烁 1=光标闪烁
5.设定显示屏或光标移动方向指令
功能:
使光标移位或使整个显示屏幕移位。
参数设定的情况如下:
S/C R/L 设定情况
0 0 光标左移1格,且AC值减1
0 1 光标右移1格,且AC值加1
1 0 显示器上字符全部左移一格,但光标不动
1 1 显示器上字符全部右移一格,但光标不动
6.功能设定指令
功能:
设定数据总线位数、显示的行数及字型。
参数设定的情况如下:
位名 设置
DL 0=数据总线为4位1=数据总线为8位
N 0=显示1行1=显示2行
F 0=5×7点阵/每字符 1=5×10点阵/每字符
7.设定CGRAM地址指令
功能:
设定下一个要存入数据的CGRAM的地址。
8.设定DDRAM地址指令
功能:
设定下一个要存入数据的CGRAM的地址。
(注意这里我们送地址的时候应该
是0x80+Address,这也是前面说到写地址命令的时候要加上0x80的原因)
9.读取忙信号或AC地址指令
功能:
<1>读取忙碌信号BF的内容,BF=1表示液晶显示器忙,暂时无法接收单片机
送来的数据或指令;当BF=0时,液晶显示器可以接收单片机送来的数据或指令;
<2>读取地址计数器(AC)的内容。
10.数据写入DDRAM或CGRAM指令
功能:
<1>将字符码写入DDRAM,以使液晶显示屏显示出相对应的字符;
<2>将用户自己设计的图形存入CGRAM。
11.从CGRAM或DDRAM读出数据的指令
功能:
读取DDRAM或CGRAM中的内容。
基本操作时序:
读状态 输入:
RS=L,RW=H,E=H 输出:
DB0~DB7=状态字
写指令 输入:
RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码
输出:
无
读数据 输入:
RS=H,RW=H,E=H 输出:
DB0~DB7=数据
写数据 输入:
RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据
输出:
无
2.MAX232芯片
用8051串行接口通信,如果两台8051单片机之间的距离很近(不超过1.5m),可以采用直接将两台8051单片机的串行接口直接相连,利用其自身的TTL电平(0-5V)直接传输数据信息。
如果传输距离较远(超过1.5m),由于传输线的阻抗与分布电容,会产生电平损耗和波形畸变,以至于检测不出数据或数据出错。
此时可利用RS232标准总线接口,将单片机输出的TTL电平转换为RS232标准电平(逻辑1为-15—-5V;逻辑0为+5-—+15V)。
用RS232可将传输距离提高到15m,如果想远距离传输,可以采用RS422或者RS485。
电平转换芯片MAX232是美信公司(MAXIM)生产,专用于进行将TTL电平转换为RS232电平的芯片,MAX232内部有泵电源,能将+5V电源电压在芯片内提高到RS232电平所需的+10V或者-10V电平。
图5、两个MAX232的接法
3.整体电路设计
最终设计电路如下图3所示,发送方的数据由串行口TXD段输出,经过电平转换芯片MAX232将TTL电平转换为RS232电平输出,经过传输线将信号传送到接收端。
接收方也使用MAX232芯片进行电平转换后,信号到达接收方串行口的接收端。
接受方接收后,通过1602LCD液晶显示接收的信息。
图6、串行通信电路
3、软件设计
本单片机课程设计实现的功能:
单片机间的串口通信。
首先,A主机与B主机进入模拟英文对话(英文短语直接调用已编好的数组,无需输入)的交流短信模式.。
A主机发送数据时,A主机显示器显示要发送的数据,发送键按下就开始向B主机发送数据,发送成功后,发送灯闪烁提示发送成功。
A主机接收数据时,将B主机发送来的数据送到A主机显示器显示,接收完毕,接收灯亮起提示接收成功。
B主机的发送与接收英问短语与A主机是一致的。
当A主机与B主机进行完模拟英文对话的交流短信模式结束之后,A主机与B主机进入到可输入数据的数字串口通信模式,此模式增加了增加输入功能,其他功能与模拟英文对话的交流短信模式是一样的。
串行口工作于方式1;用定时器1产生9600bit/s的波特率,工作于方式2。
2.程序流程图
(1)发送端程序流程图
开始
发送数字键盘输入数据
模式?
是
否
LCD显示数字
LCD显示英文
发送数据
发送数据?
否
?
否
是
是
接收数据
接收数据
?
否
?
否
是
是
LCD显示数字
LCD显示英文
(2)接收方程序流程图同上
四、联合调试
在protues上进行仿真实验。
首先使用KeilC将编写完成的程序编译生成HEX文件,将HEX文件烧录到两片单片机中,进行仿真实验,结果如下图所示,可以看到,接收端已将接受到的数据完整的显示了出来。
图7.仿真图
五、设计小结
回顾起此课程设计,至今我仍感慨颇多,从理论到实践,在这段日子里,可以说得
是苦多于甜,但是可以学到很多很多的东西,同时不仅可以巩固了以前所学过的知识,
而且学到了很多在书本上所没有学到过的知识。
通过这次课程设计使我懂得了理论与实
际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结
合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独
立思考的能力。
在设计的过程中遇到问题,可以说得是困难重重,但可喜的是最终都得
到了解决。
六、附录
1.A机发送程序
/*串口通信模拟短信通信*/
/*发送方写完信息,点击按下发送按键,发送数据,发送成功后,发送灯闪烁三次*/
/*接收方接收开始信息时,接收灯亮起,按下接收按键,接收灯熄灭,随后开始填下将要发送的数据*/
#include
sbitLED1=P2^0;//定义接收灯
sbitLED2=P2^1;//定义发送灯
sbitlcden=P2^7;//定义LCD使能端
sbitlcdrs=P2^6;//定义LCD的RS端
#defineucharunsignedchar
#defineuintunsignedint
ucharcodetable[]="Hello,";
ucharcodetable1[]="Nicetomeetyou.";
ucharcodetable2[]="Metoo,";
ucharcodetable3[]="Yourname?
.";
ucharcodetable4[]="Mynameis,";
ucharcodetable5[]="Jox.";
ucharcodedigit[]="0123456789-+=-*/";//定义字符数组显示数字及正负号
uintbutter[16]={0};//定义待发送数据数组
ucharagr,agr0,agr1,agr2,num,flag,flag1,flag2,flag3,a1,a2,temp;//定义全局标志位及全局变量
charnum1,num2;//定义全局变量
voiddelay(uintz)//延时子程序
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voidLED2_turn()//发送灯闪烁子程序
{
LED2=0;
delay(500);
LED2=1;
delay(500);
LED2=0;
delay(500);
LED2=1;
delay(500);
}
voidwrite_com(ucharcom)//液晶写指令子程序
{
lcdrs=0;
P1=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
voidwrite_data(uchardate)//液晶写数据子程序
{
lcdrs=1;
P1=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
voidlcdinit()//液晶初始化函数
{
lcden=0;
write_com(0x38);
write_com(0x0f);
write_com(0x06);
write_com(0x01);
write_com(0x80);//设液晶初始地址为第一行第一列
}
voidsend(unsignedchardat)//数据发送程序
{
SBUF=dat;//将要发送的数据存入发送缓冲器中
while(TI==0);//若发送中断标志位没有置1(正在发送数据),就等待
TI=0;//若发送完成,TI自动置1,这里把它清零
}
voidtrinit()//串口通信初始化
{
TMOD=0x20;//设置定时器1为工作方式2
TH1=0xfd;//设波特率置
TL1=0xfd;
TR1=1;
PCON=0X00;
SM0=0;
SM1=1;
REN=1;
ES=1;
}
voidextern_interrupt()//外部中断初始化
{
EX0=1;//开外部中断0
EX1=1;//开外部中断1
IT0=1;//下降沿触发中断
}
uintkeeyboard()//键盘扫描子程序
{
P0=0xfe;
temp=P0;
temp=temp&0xf0;
num1=20;
while(temp!
=0xf0)
{
temp=P0;
switch(temp)
{
case0xee:
num1=7;
break;
case0xde:
num1=8;
break;
case0xbe:
num1=9;
break;
case0x7e:
num1=13;
break;
}
while(temp!
=0xf0)//松手检测
{
temp=P0;
temp=temp&0xf0;
}
}
P0=0xfd;
temp=P0;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P0;
switch(temp)
{
case0xed:
num1=4;
break;
case0xdd:
num1=5;
break;
case0xbd:
num1=6;
break;
case0x7d:
num1=14;
break;
}
while(temp!
=0xf0)//松手检测
{
temp=P0;
temp=temp&0xf0;
}
}
P0=0xfb;
temp=P0;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P0;
switch(temp)
{
case0xeb:
num1=1;
break;
case0xdb:
num1=2;
break;
case0xbb:
num1=3;
break;
case0x7b:
num1=10;
break;
}
while(temp!
=0xf0)//松手检测
{
temp=P0;
temp=temp&0xf0;
}
}
P0=0xf7;
temp=P0;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P0;
switch(temp)
{
case0xe7:
num1=15;
break;
case0xd7:
num1=0;
break;
case0xb7:
num1=12;
break;
case0x77:
num1=11;
break;
}
while(temp!
=0xf0)//松手检测
{
temp=P0;
temp=temp&0xf0;
}
}
return(num1);
}
voidmain(void)
{
uchari,numn;
uintm;
uint*pbutter;//定义数组指针
pbutter=&butter[0];//将数组指针初始化为butter[]起止地址
flag=1;
flag3=0;
agr=0;
agr0=0;
agr1=0;
agr2=0;
a1=1;
LED1=1;//关闭接收灯
LED2=1;//关闭发送灯
i=0;
EA=1;//开总中断
extern_interrupt();//外部中断初始化
lcdinit();//LCD初始化