单片机与计算机之间的通信
湖北经济学院管理技术学院
毕业论文(设计)
题 目: 基于单片机与计算机之间的通信
系 部: 计算机科学系
专 业: 应用电子技术
学 号: 081841045
学生姓名: 何 文 斌
指导教师: 吴 姣 梅
职 称: 副 教 授
二○11 年 4 月 30 日
一、绪论 . ...................................................... 3
二、实现方法预估 . .............................................. 3
三、实验器材与软件环境 ......................................... 4
(一)实验材料 . ............................................. 4
(二)软件环境 . ............................................. 4
四、总体设计 . .................................................. 4
(一)单片机与计算机之间的通信协议 .......................... 4
(二)通信总线配臵 .......................................... 4
(三)单片机运行流程 ........................................ 5
(四)VB 运行流程及MSComm 用法 .............................. 6
1、Vb 运行流程 ........................................... 6
2、MSComm 用法 ........................................... 7
五、程序代码 . ................................................. 12
六、调试以及运行现象 .......................................... 25
七、总结 . ..................................................... 27
八、致谢 . ..................................................... 29
参考文献 . ..................................................... 29
摘 要:本设计研究单片机与计算机之间的通信,单片机发送时间请求信号,计算机接收请求信号,经确认后,计算机对系统时间编码且发送数据,单片机接收数据且解码,并把解码后的数据显示在8个七段数码管上,每过1s ,动态更新七段数码管显示的数据,保持它和计算机的时间保持同步。
关键字:单片机 串口 计算机 vb(Visual Basic) 七段数码管
一、绪论
进入了21世纪,经济高速地发展,电子行业也在不断的前进,电子产品已经步入家家户户,十分普遍。
这次我所选的毕业论文选题为“基于单片机与计算机之间的通信”,它们通信有两种方式,即并口通信和串口通信,考虑到现在电脑的CPU 运行的速度相当快,一般的外设要求运行的速度不是很高,此时选择串口就行了。因此,我选择串口通过RS-232总线进行通信。
一般的大的数码管的电子表从外部调整相当麻烦,为了介绍调整的麻烦,此次我决定用单片机与电脑通信,动态更新单片机的时间。
主要实现的功能是通过外部按钮给单片机一个中断,单片机则通过它们之间制定一个协议进行通信。最后电脑得到请求信号后通过RS-232总线将电脑此时此刻的时间发送给单片机,此时单片机接受相对应的数据,并显示在单片机8位数码管上(格式如:12-00-00),每过一秒,单片机显示时间动态更新一次,且单片机可以随时请求计算机发送时间信号给单片机。
二、实现方法预估
此次我所选用的单片机为Atmel 公司AT89S52单片机,此单片机有一个串口,可以进行串口通信;而电脑普遍都有串口,但是需要一个平台使计算机和单片机通信,我所选的平台为Visual Basic 6.0版本的开发环境,
用Visual Basic的Mscomm 控件即可建立串口通信实验。
三、实验器材与软件环境
(一)实验材料:51单片机开发板一块(集成了8个七段数码管),USB 转串口线、笔记本一台。
(二)软件环境:protel 、Keil
四、总体设计
(一)单片机与计算机之间的通信协议:单片机给计算机发送一个字符“A ”,确认计算机是否准备好;如果计算机没有准备好,单片机一直发送字符“A ”,如果计算机准备好,此时发送一个字符“B ”给单片机;单片机当接受到字符“B ”后,知道计算机准备好了,此时单片机发送请求信号字符“C ”,计算机接受到字符“C ”,此次把此时的时间六位数发送给单片机,单片机则通过相应的程序显示出来。
(二)通信总线配臵:考虑到我的笔记本没有串口借口,通过上网查相关资料,我选择了USB 转串口线,同时需要在相应的计算机转该串口线的驱动程序。
USB 转串口线如图1-1所示:
图1-1(USB转串口线)
1-2所示:
(三)单片机运行流程:如图
图1-2(51单片机程序流程图)
(四)VB 运行流程及MSComm 用法:
1、Vb 运行流程,如图1-3所示:
图1-3(Visual Basic流程图)
2、MSComm 用法:
vb 里面有一个控件MSComm ,是专门用来串口通信的,该控件添加步骤如下,点击菜单栏中的“工具”按钮,在它的下拉框中点击“部件”按钮,如图1-4所示:
图1-4(添加部件)
打开了部件选择表,拖动右边的滚动条,在Microsoft Comm Control 6.0上面点击鼠标左键,勾上该项,之后点击“确定”按钮。如图1-5
图1-5(选中MSComm 控件)
当上一步点击“确定”按钮后,可以看见工具中多了一个MSComm 控件,如图1-6所示:
图1-6(Mscomm 已添加到工具箱中)
双击该控件,可以添加到form 窗体上,如图标7所示:
图1-7(拖拽Mscomm 控件于form 窗体上)
在form1窗体中,选中它,看它的属性列表,如图1-8:
图1-8(MSComm 属性)
下面对该MSComm 控件的属性进行讲解:
CommPort:串口号设臵,程序在初始化的时候必须指定所要使用的串口号。例如使用COM1, 就在CommPort 属性中填“1”。
Settings :Setting 属性用于设臵串口的初始化参数。默认值为“9600,n,8,1”, “9600”。这个有逗号分隔的参数分别代表了波特率、奇偶校验位检查方式、数据位数和停止位数。
PortOpen :该属性为True 的时候,打开所指定的串口;为False ,则关闭相信的串口。
Input (从串口接受数据):Input 属性用于从输入缓冲返回并删除字符 OutPut (从串口发送数据):OutPut 属性用于将要发送的数据写入传输缓冲区。
五、程序代码
单片机所需的程序是用c 语言编写的,用的软件环境选择了Keil ,代码如下:
#include Unsigned
char
Tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; unsigned
port[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsigned char int_time; unsigned char second; unsigned char minute; unsigned char hour; unsigned char str[6];
/********************************************************** 函数功能:延时约0.6ms
***********************************************************/ void delay(void) {
unsigned char i; for(i=0;i
char
;
/************************************************************ 函数功能:发送一个字节数据
************************************************************/ void Send(unsigned char dat) {
SBUF=dat;
while(TI==0) //若发送中断标志位没有臵"1" ,就等待 { ; } TI=0; }
/************************************************************ 函数功能:接受一个字节数据
************************************************************/ unsigned char Receive(void) {
unsigned char dat;
while(RI==0) //只要接受中断标志位RI 没有被臵"1" 就等待,直至接受完毕 {
; } RI=0; dat=SBUF; //P1=SBUF; return dat; }
/********************************************************** 函数功能:显示秒的子程序 入口参数:s
***********************************************************/ void DisplaySecond(unsigned char s) {
P2=port[1]; P0=Tab[s/10]; delay(); P2=port[0]; P0=Tab[s%10]; delay(); P2=0xff; }
/********************************************************** 函数功能:显示分钟的子程序 入口参数:m
***********************************************************/ void DisplayMinute(unsigned char m) {
P2=port[4]; P0=Tab[m/10]; delay(); P2=port[3]; P0=Tab[m%10]; delay(); P2=port[2]; P0=0xbf; delay(); P2=0xff; }
/********************************************************** 函数功能:显示小时的子程序 入口参数:h
***********************************************************/
void DisplayHour(unsigned char h) {
P2=port[7]; P0=Tab[h/10]; delay(); P2=port[6]; P0=Tab[h%10]; delay(); P2=port[5]; P0=0xbf; delay(); P2=0xff; }
/********************************************************** 函数功能:串口初始化
***********************************************************/ void int_ChuanKou() {
TMOD=0x20; //定时器T1工作在方式2
SCON=0x50; //串口工作在方式1,允许接受(REN=1) PCON=0x00; //主要设臵波特率为2400b/s TH1=0xf3;
TL1=0xf3;
TR1=1; //启动定时器T1 }
/********************************************************** 函数功能:接受六个字符
***********************************************************/
void Receive_SixChar() { int i;
for(i=0;i
str[i]=Receive()-0x30; }
hour=10*str[0]+str[1]; minute=10*str[2]+str[3]; second=10*str[4]+str[5]; }
/********************************************************** 函数功能:定时器0和变量初始化
***********************************************************/
void int_Timer0(void) {
TMOD=0x21; TH0=15536/256; TL0=15536%256; EA=1; ET0=1; TR0=1; int_time=0; second=0; minute=0; hour=0; }
/********************************************************** 函数功能:主函数
***********************************************************/ void main() { int i; char temp;
IE=0x81; //允许P3.3外部中断0发生
int_ChuanKou(); //串口初始化 int_Timer0(); //定时器0初始化 while(1) {
delay();
DisplaySecond(second); //调用秒显示子程序 delay();
DisplayMinute(minute); //调用分钟显示子程序 delay();
DisplayHour(hour); //调用小时显示子程序
} }
/********************************************************** 函数功能:定时器Timer0的中断服务子程序
***********************************************************/ void interserver(void) interrupt 1 using 1 { TR0=0; int_time++;
if(int_time==20) //若中断次数为20次
{
int_time=0; //中断次数清零
second++; //秒计数变量加1
}
if(second==60) // {
second=0; //
minute++; // }
if(minute==60) // {
minute=0; //
hour++; // }
if(hour==24) // {
hour=0; // }
TH0=15536/256; // TL0=15536%256; // TR0=1; }
若计满60s 如果秒计满60,将秒计数变量清0 分钟计数变量加1
若计满60分 如果分钟计满60,将分钟计数变量清0 小时计数变量加1
若计满24时 将小时计数变量清0 定时器T0高8位重新赋初值 定时器T0低8位重新赋初值
/********************************************************** 函数功能:外部中断0
***********************************************************/ void zhongduan_0(void) interrupt 0 using 0
{
char tmp,temp;
int i;
tmp=P2;
P2=0xff; // 防止中断期间,七段数码管显示乱码
while(RI==0) //没有接收到pc 发送过来的信息,继续发送字符“A ”
{
Send('A'); //发送串口确认信号“A ”
for(i=0;i
delay(); //延时等待
}
RI=0; //当接受到信息后,RI 清零
temp=SBUF;
if(temp=='B') //检查接受的字符是否为“B ”
{
Send('C'); //如果是的话,发送请求信号字符“C ”
}
Receive_SixChar(); //调用接受单片机发送时间数据的子程序 P2=tmp; //恢复中断位控制口的数据
}
经过多轮调试后,最后生成my_work.hex文件,如1-9:
图1-9(生成的hex 文件)
之后把该程序下载到单片机上,则可以运行。
计算机方面的代码是用vb 编写的,通过引用MSComm 控件,
分方便,界面如下如图1-10:
图1-10(界面)
所用了控件有:
Mscomm1(MSComm 控件)
Timer1(Timer控件)
Label1(Label控件,它的Cation 属性为“接受的命令”
)
串口通信十
Label2(Label控件,它的Cation 属性为“接受的命令”)
txt_receive(Text 控件):显示单片机接受的命令
txt_send(Text控件) :显示计算机发给单片机的命令或者数据
vb 程序代码:
Private Sub Form_Load()
On Error Resume Next
MSComm1.CommPort = 3 '我的电脑端口为3
MSComm1.Settings = "2400,n,8,1" '设臵波特率为2400
MSComm1.PortOpen = True '打开串口
End Sub
Private Sub MSComm1_OnComm()
Dim buf$, t$, char$
Dim i As Integer
buf = Trim(MSComm1.Input) '接受数据,赋值给变量buf
txt_receive.Text = buf '文本框显示接受的字符
If buf = "A" Then '如果接受到字符“A ”,则发送字符“B ”
MSComm1.Output = "B"
End If
If buf = "C" Then '如果接受到字符“C ”,则编码后把时间的六位数一个一个的发送出去
t = Format(Hour(Time), "00") & Format(Minute(Time), "00")
& Format(Second(Time), "00")
For i = 1 To Len(t)
char = Mid(t, i, 1)
MSComm1.Output = char '发送一位数据
txt_send.Text = txt_send.Text & char 'txt_send文本框显示发送出去的数据
Next
End If
End Sub
Private Sub Timer1_Timer()
Dim t As String
t = "通信测试" & Time '显示电脑时间,主要为了和单片机上的时间作一个对比
Form1.Caption = t
End Sub
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
MSComm1.PortOpen = False '关闭串口
End
End Sub
编译之后,并且让它生成可执行文件如图1-11:
图1-11
六、调试以及运行现象
当单片机与计算机之间的串口线接好了,并且把my_work.hex文件的数据烧制到单片机上运行单片机,让单片机程序运行,并且运行vb 生成的“串口通信.exe ”可执行文件,该程序运行的界面如图1-12所示:
图1-12(单片机为发生中断,vb 程序运行界面)
此时单片机运行效果图如1-13:
图1-13(单片机未发生中断)
当按下P3.2按钮好,此时单片机发送中断,通过对应的协议与计算机通信,vb 上看到的效果如图1-14:
图1-14(vb 接受的信号和发送的数据)
此时单片机运行效果图如图1-15所示:
图1-15(单片机显示时间)
七、总结
这次毕业论文我选择的是“基于单片机与计算机之间的通信”,之前我们学了51系列单片机,而且学的是用汇编进行编写,经过参加暑假电子设计大赛,我学会了用c 语言编写程序,这也减少了我此次的工作梁,c 语言编写程序代码相对容易些,不用考虑太多东西,如堆栈、地址、中断地址等。
在进行实验前,我的硬件器材几乎都俱全,在动手前,我花费了两三天时间翻阅串口通信相关的书籍,知道他们怎么接线,对串口通信的整个流程掌握的非常熟悉。同时我也加紧复习七段数码管的快速动态扫描显示数字进行温习,懂得了它是利用人眼视觉停留性,让人眼看不出来它们是逐位显示,而看到的效果是,全部显示。
接着也重新温习了定时器与中断方面的知识,使动手起来更加顺手。 当一切准备就绪,我就开始考虑他们之间通信的协议,之前我只是考虑到单片机发送请求信息,计算机发送时间给单片机。当时假如我的计算机上的vb 可执行文件没有运行的话,此时那我的单片机此时不是一直在等待接受计算机发送过来的时间数据嘛,也几乎陷入死循环;我觉得这样存在缺陷,就是想,不管我的vb 应用程序是先在单片机程序运行之前打开还是它运行之后打开,都没有影响。此时我就想着为它们定制一套协议:思路就是当vb 应用程序没有运行,此时单片机一直发送确认信号,当vb 应用程序运行后,此时单片机会收到vb 应用程序的确认信号,此时单片机就会发送请求时间信号,vb 应用收到请求时间信号后,会逐为把电脑的运行时间发送给单片机。
此次显示时间我用我用单片机上的8个七段数码管(格式如:12-00-00),它们都是共阴极。而P0是数据口,而P2是位控制口。因为以前我只用单片机控件一个数码管显示一个信息,而此次为8个七段数码管可能显示不同的数字,在这上面我苦思了一番。最后通过相关的书籍弄清楚了两位数码管显示不同的数字后,关于“怎么使他们显示动态时间”这个难题我迎刃而解。
Vb 是我们大一上开的课程,到目前为止,我还是经常用它,查阅了相关书籍后,做其串口通信还是十分轻松的。
此次我选择的是单片机的开发板,因此减少了不少的麻烦。但是我还是对通过相关书籍对硬件部分电路十分清楚了,懂得了复位电路设计、晶振电路搭建、8个七段数码管的电路怎么布臵,按键怎么布臵等。
八、致谢
两个月毕业论文设计已经结束了。无论我的设计是否能够真正的投入到使用,这里面的每一行代码编写,每一个错误的调试,硬件电路的考虑都有我辛勤的汗水。两个月时间虽然短暂,我却从中学习到了很多东西。在这段时间内,我得到了指导老师吴姣梅老师的指导,在此我衷心的感谢他的引导与帮助。在设计过程中,我结合了过去两年半的基础和专业理论课,较好的解决此次我的毕业论文,为今后走向工作岗位打下了坚实的基础,所以我也感谢三年教我课程、给予我帮助的老师们,谢谢您们!
参考文献
[1]杨 欣,王玉凤,刘湘黔:《51单片机应用从零开始》,2008,清华出版社
[2]王东峰,王会亮,董冠强:《单片机C 语言应用100例》,2009,电子工业出版社
[3]刘守义:《单片机应用技术》,2007,西安电子科技大学出版社