单片机串行通信课程设计.docx
- 文档编号:7488696
- 上传时间:2023-01-24
- 格式:DOCX
- 页数:16
- 大小:354.85KB
单片机串行通信课程设计.docx
《单片机串行通信课程设计.docx》由会员分享,可在线阅读,更多相关《单片机串行通信课程设计.docx(16页珍藏版)》请在冰豆网上搜索。
单片机串行通信课程设计
课程设计任务书
学生姓名:
专业班级:
指导教师:
工作单位:
题目:
PC和单片机的串行双工通信
初始条件:
具备单片机原理的理论知识和实践能力;熟悉51单片机的CPU结构和指令系统;熟悉相关常用接口电路的设计使用方法。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
1)利用串口设计4位静态数码管显示器,要求4位显示器上每隔1s交替显示“0123”和“4567”。
2)完成PC和单片机的串行双工通信,单片机的P1口接一共阴极数码管,阴极接地。
要求PC键盘每按“0~9”数字键能发送到单片机,并显示在单片机接的数码管上,单片机发送一串字符串能显示在PC的屏幕上,采用查询方式。
波特率为1200。
时间安排:
一周,其中2天程序设计,2天程序调试,1天完成课程设计报告书及答辩
指导教师签名:
年月日
系主任(或责任教师)签名:
年月日
摘要
本设计运用51单片机设计了一个能和PC进行全双工通信的程序,能由单片机向PC发送字符串,当按PC上的数字键时,能在单片机上的数码管上显示相应数字,并且单片机的其他数码管能每隔1s交替显示0123和4567,还扩展了用lcd1602显示来自PC端的任意字符,并能统计和显示发送和接受的字符数。
程序采用C语言分模块编写,并用proteus仿真通过,还有实物演示结果。
关键词:
单片机;串行通信;数码管
1基本原理
1.1串行通信
单片机的串行通信使用的是异步串行通信。
串行接口电路为用户提供了两个串行口缓冲寄存器(SBUF),一个称为发送缓存器,它的用途是接收片内总线送来的数据,即发送缓冲器只能写不能读。
发送缓冲器中的数据通过TXD引脚向外传送。
另一个称为接收缓冲器,它的用途是向片内总线发送数据,即接收缓冲器只能读不能写。
接收缓冲器通过RXD引脚接收数据。
因为这两个缓冲器一个只能写,一个只能读,所以共用一个地址99H。
串行口控制寄存器SCON是MCS-51单片机的一个可位寻址的专用寄存器,用于串行数据通信的控制。
单元地址为98H,位地址为98H~9FH。
寄存器的内容及位地址表示如下:
SM0、SM1——串行口工作方式选择位M2——允许方式2、3的多机通信控制位REN——允许接收位TB8——发送数据位8,RB8——接收数据位8,TI——发送中断标志位RI——接收中断标志位.。
位地址
9FH
9EH
9DH
9CH
9BH
9AH
99H
98H
位符号
SM0
SM1
SM2
REN
TB8
RB8
TI
RI
表1SCON控制字
1.2数码管动态显示
动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效,这样可以节省引脚。
所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使人的感觉好像各位数码管同时都在显示。
1.3定时器
MCS-51单片机内部共有两个16位可编程的定时器/计数器,即定时器T0和定时器T1它们既有定时功能又有计数功能。
(1)定时器控制寄存器(TCON)
TF0/TF1:
查询方式:
禁止中断,软件查询TF0的值,软件清“0”
中断方式:
硬件查询TF0的值,硬件自动清“0”
位地址
8FH
8EH
8DH
8CH
8BH
8AH
89H
88H
位符号
TF1
TR1
TF0
TR0
IE1
IT1
IE0
IT0
表2TCON控制字
(2)工作方式寄存器(TMOD)
功能:
确定定时器的工作方式及功能选择。
D7
D6
D5
D4
D3
D2
D1
D0
GATE
C/T
M1
M0
GATE
C/T
M1
M0
表3TMOD控制字
GATE:
门控位
功能选择位M0M1工作方式选择位
1.4LCD1602
字符型液晶模块是一种用5x7点阵图形来显示字符的液晶显示器,根据显示的容量可以分为1行16个字、2行16个字、2行20个字等等,这里采用的是2行16个字的1602液晶模块1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,内部的控制器共有11条控制指令它的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
程序在开始时对液晶模块功能进行了初始化设置,约定了显示格式。
注意显示字符时光标是自动右移的,无需人工干预,每次输入指令都先调用判断液晶模块是否忙的子程序DELAY,然后输入显示位置的地址例如0C0H,最后输入要显示的字符例如A的代码41H。
2设计过程
2.1设计思路
目前手头上有一个现成的51单片机开发板,上面有6个数码管,独立键盘等资源,根据题目要求可以分模块设计。
(1)数码管显示:
题目要求数码管数码管显示器每隔1s交替显示“0123”和“4567”,同时能按PC上的数字键能显示对于数字,6个数码显示够用。
由于字选端口和位选端口都通过74HC573与P0口相连,采用分时操作的方法,先打开与字选端口锁存器,向P0口写入位选码,接着锁存,然后打开位选端口锁存器,向P0口写入字形码,再锁存,延时一定时间后在操作其他几个数码管。
为保持数码管不熄灭,所以数码管显示程序要一直循环。
(2)串行通信:
要实现PC和单片机的串行双工通信,要设置接收允许。
采用串行方式1,T1作为波特率发生器工作于方式2,取SMOD=0,T1的时间常数为E6。
发送部分程序采用查询式方法,先发送第一个字符,等待发送完毕后在发下一个,直字符串至全部发完。
实际发送中要用按键控制,当按键按下一次时,发送一次。
接收程序采用中断方式,当单片机接收到一个来自PC的字符时,产生串行口中断,将接受到的ASCII码转换成单片机能够显示的字形码。
(3)定时器部分:
要求数码管显示器每隔1s交替显示“0123”和“4567”,很容易想到定时器控制。
选用定时器T0,工作方式1,16位计数,最大计数值65536,晶振为11.0592M,最大定时周期为71ms,不能满足要求,可以先定时50ms,此时计数初值为4C00,然后引入一个变量计数,每当定时器T0中断时变量加1,当计到20时刚好一秒,改变数码显示结果,再将计数变量清零,如此循环。
(4)液晶显示部分:
用第一行接受来自PC端得字符,由于lcd1602一行只能显示16个字符,故要引入一个变量计数,每显示一个字符,计一次,计16次时表示屏幕显示满了,清屏。
第二行显示发送和接受的字符串,故要引入两个变量统计收发的字符数。
2.2电路图
2.3流程图
图2程序流程图
3程序代码
本次设计的程序在keil上编写与调试,按照前面的设计思路采用分模块设计的方法,为每个模块建立一个文件,分别编写调试通过,然后在主函数中调用。
3.1主程序
#include
#defineucharunsignedchar
#defineuintunsignedint
externvoidint_rec(void);//中断接收
externvoidcom_init(void);//串口初始化
externvoidsendstr(uchar*p);//字符串发送函数
externvoiddisplay(uchar,uchar,uchar,uchar,uchar,uchar);//数码管显示函数
externvoidinit();//lcd初始化
externvoidwrite_com(ucharcom);//lcd写命令
externvoidwrite_data(uchardate);//lcd写数据
externvoidtimer0_init();//定时器初始化
externuchardingshi(ucharn);//定时1s函数
uintcnt_r=0,cnt_s=0;//发送接收计数
ucharcnt_xs=0;//显示计数
sbitkey1=P3^7;//定义按键
uchara[6]={0,1,2,3,19,19};//数码管显示值
ucharc[]={0xa0,0xa0,0xa0,0xa0,0};
voidnum2char(uinttemp)//无符号双字节数转为字符
{
c[4]=temp%10/1;//最低位
c[3]=temp%100/10;
c[2]=temp%1000/100;
c[1]=temp%10000/1000;
c[0]=temp%100000/10000;//最高位
}
voidlcd_disp()//lcd显示函数
{uchari;
write_com(0x80+cnt_xs-1);//显示第一行
if(cnt_xs>16)//第一行显示满后清屏
{write_com(0x01);cnt_xs=1;}
write_data(a[4]);
num2char(cnt_s);//字符转换
write_com(0x80+0x40);//显示第二行
write_data('S');write_data('E');write_data(':
');
//显示字符串“SE:
”
for(i=0;i<5;i++)write_data(c[i]+0x30);//显示发送计数值
num2char(cnt_r);//
write_data('R');write_data('E');write_data(':
');
//显示字符串“RE:
”
for(i=0;i<5;i++)write_data(c[i]+0x30);//显示接收计数值
}
main()//主函数
{
ucharcnt=0;//通过计数,控制按一次键发送的次数
com_init();//串口初始化
timer0_init();//定时器初始化
init();//lcd初始化
while
(1)
{
if(key1==0)//按键按下时单片机发送字符串
{if(cnt<1){sendstr("HanBing");cnt++;}
}
elsecnt=0;//按键弹起cnt清零
display(a[0],a[1],a[2],a[3],19,a[5]);//6位数码管显示
lcd_disp();//lcd显示
if(dingshi(20))//计到50次时即1s,变换显示数字
{a[0]=4-a[0];
a[1]=6-a[1];
a[2]=8-a[2];
a[3]=10-a[3];}
}
}
3.2串口通信程序
#include
#defineucharunsignedchar
#defineuintunsignedint
externuchara[6];//数码管6位
externvoidwrite_com(ucharcom);//lcd写数据
voiddo_uart(unsignedcharcharRcv);//串口接收执字符时的操作
voidsendchar(ucharuart_dat);//字符串发送
externuintcnt_r,cnt_s;//接收,发送计数
externucharcnt_xs;//lcd显示计数
/*串口发送字符串*/
voidsendstr(uchar*p)
{while(*p!
='\0')
{SBUF=*p;//待发送的数据写入缓冲区
while(!
TI);//等待发送完成
TI=0;//清零发送标志位
p++;//指针加1
cnt_s++;//发送计数}
}
voidint_rec(void)interrupt4using2/*串口接收中断函数*/
{unsignedcharRcv=0;
if(RI)//查询接收标志位(有数据发送过来时置为1)
{
RI=0;//接收标志位清零
Rcv=SBUF;//存储缓冲区的数据
do_uart(Rcv);//对接受到得字符操作
}
}
voidcom_init(void)/*串口初始化*/
{SCON=0x50;//串口工作方式为1,串行允许接受
TMOD=0x21;//定时器1工作在方式2定时器0工作在方式1
TH1=0xe8;//fosc="11.0592MHz"初值fd时波特率9600bps
TL1=0xe8;//初值e8时,波特率1200bps
ES=1;//开串口中断
TR1=1;//允许定时器1工作
EA=1;//开总中断
}
/*串口接收到字符的操作函数*/
voiddo_uart(unsignedcharRcv)
{
cnt_r++;//接收计数
if(Rcv>='0'&&Rcv<='9')a[5]=Rcv-0x30;//判断是否按得是0~9
elseif(Rcv>='a'&&Rcv<='f')a[5]=Rcv-87;//判断是否按a~f
elseif(Rcv>='A'&&Rcv<='F')a[5]=Rcv-55;//判断是否按A~F
elsea[5]=20;//其他字符
if(Rcv==0x1B)write_com(0x01);//按Esc清显示,光标复位到地址00h处
a[4]=Rcv;//暂存接收到得数据
cnt_xs++;//显示计数加1
}
3.3数码管显示
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitdula=P2^6;//段选信号
sbitwela=P2^7;//位选信号
ucharcodetable[]={//共阴数码管表
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,
0x76,0x73,0x38,0,0x40};//hpl灭-
voiddelay1(uintz)//延时子程序
{
uintt1,y;
for(t1=z;t1>0;t1--)
for(y=110/2;y>0;y--);
}
voiddisplay(ucharaa,ucharbb,ucharcc,ucharba,ucharsh,ucharg)
//用6个数码管显示
{
dula=1;P0=0;dula=0;//段初始化
wela=1;P0=0xc0;wela=0;//位初始化
dula=1;P0=table[aa];dula=0;//选中第一位
P0=0xff;
wela=1;P0=0xfe;wela=0;delay1(5);
dula=1;P0=table[bb];point=0;dula=0;//选中第二位
P0=0xff;
wela=1;P0=0xfd;wela=0;delay1(5);
dula=1;P0=table[cc];dula=0;//选中第三位
P0=0xff;
wela=1;P0=0xfb;wela=0;delay1(5);
dula=1;P0=table[ba];dula=0;//选中第四位
P0=0xff;
wela=1;P0=0xf7;wela=0;delay1(5);
dula=1;P0=table[sh];dula=0;//选择第五位
P0=0xff;
wela=1;P0=0xef;wela=0;delay1(5);
dula=1;P0=table[g];dula=0;//选择第六位
P0=0xff;
wela=1;P0=0xdf;wela=0;delay1(5);
}
3.4定时程序
#include
#defineucharunsignedchar
uchart50ms=0;//50ms计数
voidtimer0_init(void)//定时器初始化
{
TH0=0x4c;TL0=0;//定时器T0赋初值,晶振11.092M,定时50ms
TR0=1;ET0=1;//启动定时器T0
}
uchardingshi(ucharn)//定时50ms的n倍
{if(t50ms>=n)
{t50ms=0;//50ms计数清零
return1;}
return0;
}
voidtimer0()interrupt2using1//定时器T0产生50ms中断
{
t50ms++;//
TH0=0x4c;//计数值重载
TL0=0;
}
3.5液晶模块
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitlcden=P3^4;//lcd使能端
sbitlcdrs=P3^5;//寄存器选择端
voiddelay2(uintz)//延时程序
{uintx,y;
for(x=z;x>0;x--)
for(y=110/4;y>0;y--);
}
voidwrite_com(ucharcom)//写lcd控制命令
{lcdrs=0;P0=com;delay2(5);
lcden=1;delay2(5);lcden=0;
}
voidwrite_data(uchardate)//写入ASCII码即可,
{
lcdrs=1;P0=date;delay2(5);
lcden=1;delay2(5);lcden=0;
}
voidinit()
{lcden=0;
write_com(0x38);//置功能,数据长度4位,双行显示,5*7显示
write_com(0x0c);//显示开关控制,开显示,0x0f光标,闪烁,若改为0x0c则无光标
write_com(0x06);//光标右移,屏幕上所有文字不动
write_com(0x01);//清显示,光标复位到地址00h处
}
4运行结果
4.1仿真结果
本设计采用的是Proteus仿真,电路图见前文,主意设置晶振为11.590M,串行全双工通信仿真采用的设备是虚拟终端,仿真前注意设置波特率为1200,数据位8位。
按下单片机上的按钮的仿真结果:
以下为液晶显示结果,第一行显示接收的字符,第二行显示已发送和接收的字符数
图4LCD显示仿真
4.2运行结果
PC端采用的串口调试助手来控制串行通信与观察运行结果,先设置正确的串口号,波特率为1200,采用字符格式显示和发送。
当按下单片机上的独立按键时,在PC端观察收到字符串“HanBing”,且按一次发送一次。
液晶屏显示的结果与仿真结果完全一样,由于液晶屏拍照效果不好,故未给出液晶屏显示截图
图5PC上运行结果
图6数码显示结果1
图7数码管显示结果2
将鼠标焦点移到串口调试助手的键盘发送区,当按下PC键盘的0~9,A~F时,第六个数码管显示相应结果,按其他键时显示“—”,并且前四个数码管每隔1s交替显示“0123”
和“4567”
4.3问题与改进:
程序开始设计时,串行发送控制部分,采用当按键按下就发送,如果一直按着不动,由于程序是循环执行的,所以会一直发送下去。
为达到按一次只发送一次的目的,可以引入变量cnt,先赋初值0,按键按下时,首先检测cnt是否大于0,然后cnt加1,发送字符串。
第二次检测按键状态时,由于cnt>0,不执行此句,即不发送字符串。
当按键弹起时再将cnt清零。
数码管显示部分开始只设计了显示0~9,如果按其他键显示乱码,后来加入了多条选择语句,还能够显示A~F六个字符,对于其他字符一律显示“-”。
液晶显示部分开始时始终只能显示当前接收的一个字符,后来通过改进能够用一行显示,并且显示满后能够自动清屏,还能在第二行显示收发的字符个数。
5心得体会
时光飞逝,一转眼,一个学期又进尾声了,本学期的单片机综合课程设计也在一周内完成了。
通过该课程设计,全面系统的理解了单片机原理的一般原理和基本实现方法。
把死板的课本知识变得生动有趣,激发了学习的积极性。
把学过的单片机原理基础原理的知识强化,能够把课堂上学的知识通过自己编写的程序表示出来,加深了对理论知识的理解。
在这次课程设计中,我先是认真阅读课本上的相关知识,理解透后又翻阅关于C语言的书籍,学习C语言中的运算符、数组和指针的用法。
然后掌握了单片机串口通信、定时器、数码管动态扫描的原理与应用,学会了51单片机常用的寄存器的使用。
总体来说,这次课设我学到了很多。
在设计过程中,加深了对可内知识的理解就,真正懂得了学以致用,熟悉了keil软件的使用,了解Proteus单片机仿真中的重大应用。
做课程设计我体会到了设计的艰辛的同时,更让我体会到成功的喜悦和快乐.这次单片机原理课程设计,虽然短暂但是让我得到多方面的提高:
首先,提高了我们的对C语言的运用能力。
C语言是一种高级语言,运算符丰富,可读性好,移植性强,易于模块化设计,有丰富的函数可供调用。
原来只是零零散散的做过一些单独的模块。
通过C语言,很方便把原来做过的模块进行整合,方便调试与扩展。
其次,锻炼了课外查资料的能力。
我们在设计程序时,遇到很多不理解的东西,如LCD1602的使用,操作指令比较多,后来通过网上查阅相关的PDF的文档,参考别人写的程序,才搞清楚它的控制字和操作过程。
有的我们通过查阅参考书弄明白,有的通过网络查到,但由于时间和资料有限我们更多的还是独立思考。
最后通过课程设计提高了我的综合运用知识能力。
原来我写程序的都是一个文件,而这次单片机课程设计首次采用多文件,把功能拆分成几个相对独立的模块,既方便调试,也方便以后直接调用。
原来学微机原理也学过定时器和串行通信,但只停留在理论层面,通过这次单片机课程设计才真正理解。
还有掌握了proteus在单片机仿真中的应用,原来只用proteus做过模数电的仿真,现在学会了单片机的仿真。
参考文献
[1]邹其洪.《单片机原理》.电子工业出版社,2005
[2]吴友宇.《单片机原理与接口技术》.东南大学出版社,2008
[3]吴锡龙.《单片机实例与开发》.高等教育出版社,2004
[4]李群芳.《单片微型计算机》.电子工业出版社,2008
[5]丁春利.《单片机原理与通信接口》.清华大学出版社,2002
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 串行 通信 课程设计