单片机课程设计论文基于C++Builder的PC机与单片机之间的串口通信Word文档下载推荐.docx
《单片机课程设计论文基于C++Builder的PC机与单片机之间的串口通信Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《单片机课程设计论文基于C++Builder的PC机与单片机之间的串口通信Word文档下载推荐.docx(32页珍藏版)》请在冰豆网上搜索。
图1
方式1是10位数据的异步通信口。
TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图2所示。
其中1位起始位,8位数据位,1位停止位。
用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。
接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。
当RI=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU请求中断。
用单片机内部定时器1即T1,使其工作在方式2,作为波特率发生器。
图2
由于基于C++Builder的通信协议如图3所示,因此在程序编写时,需要在设置一个缓冲区来暂时存储单片机接收的来自PC机的一串字符串。
前导符
站号地址
功能码
数据长度
数据
结束符
校验码
##
AAAA
FF
LL
DDDD
@@
X
图3
2.硬件设计
51单片机有一个全双工的串行通讯口,所以单片机和电脑之间可以方便地进行串口通讯。
进行串行通讯时要满足一定的条件,比如电脑的串口是RS232电平的,而单片机的串口是TTL电平的,两者之间必须有一个电平转换电路,我们采用了专用芯片MAX232进行转换。
如图4所示。
图4
3.软件设计
如图4,PC机作为主机,80C51单片机作为从机(波特率为9600b/s)。
通信程序采用C语言编程。
这个程序的流程图如图5所示。
程序见下。
图5
3.1串口初始化
3.2从机(单片机)接收主机(PC机)发送来的数据帧
3.3从机发送数据帧给主机
(1)解析从机发送的数据帧(程序见附录3的voidsend()部分)
(2)从机发送数据帧
3.4拓展部分
利用P1口连接的8个LED灯来显示C++Builder的十三个功能(见附录1)。
三、运行调试
1.硬件方面
(1)烧写程序时,已经上电了,可软件还是一直提示上电,反复上电也不行后,最终通过反复换串口,反复烧写上电解决了。
类似的还有只要进行烧写,烧写软件界面就会消失,也是通过上述方法解决。
(2)有时烧写时,忽略了相应的串口和波特率的选择甚至忘记打开串口助手的串口,发送数据后使得PC机的接收窗口中无显示。
(3)有时发送数据后接收窗口无显示,经过复位后,问题得以解决。
2.软件方面
编程时遇到的主要问题有四个:
(1)如何在C51单片机中存储接收的一个字符串数据帧。
如上所述,需要设置一个缓冲数组来接收主机发送的字符串数据帧。
程序见3.2。
(2)如何判断从机已经接收到完整的数据帧即结束接收。
设置一个标志位,如ucharfinish。
当finish=1时,表示接收结束。
(3)如何解析从机发送的数据帧。
对此,我前后采用了两种方法进行调试运行(以下程序仅为“查询功能”模块的代码)
方案一:
voidsend()
{
if(host[6]=='
0'
)
{
switch(host[7])
{
case'
:
//查询地址
TI=0;
SBUF='
#'
;
while(!
TI);
SBUF='
SBUF=slave_addr[0];
SBUF=slave_addr[1];
SBUF=slave_addr[2];
SBUF=slave_addr[3];
4'
@'
x'
break;
}
方案二:
voidsend_109()
if(count_109==13)
{
if((buf_109[3]=='
)&
&
(buf_109[3]=='
(buf_109[4]=='
(buf_109[5]=='
(buf_109[8]=='
(buf_109[9]=='
))
if(buf_109[6]=='
buf_109[7]=='
{
count_109=0;
load_109("
##"
);
load_109(&
slave_addr_109);
0004"
@@X"
}
}//查询地址
方案一没有把通信协议表达完善,因此运行不成功。
方案二解决了通信协议部分,运行成功,而且代码长度较方案一更为简短。
(4)如何放置功能拓展部分的程序。
遵循着“中断中程序尽可能少些,一般放在主程序部分实现”的原则,对于我这次拓展的一点点功能(LED灯显示、报警蜂鸣器响,程序见3.4),我把标志位flag的设置放在了解析函数voidsend()部分,将LED显示放在了主函数中。
起初我把蜂鸣器代码“RD=0”也放在解析函数中,效果失败,经过调试放在主函数中后,蜂鸣器响了起来。
四、总结与体会
每次课设后都会收获很多,这次也不例外。
平时编写代码的机会不多,因而这次课设显得比较棘手。
鉴于已经系统地学过C语言以及单片机中常用C的编写,程序的整体架构不存在多大问题。
因而主要问题在于各部分功能的实现。
首先针对于这次课设,必须先了解主机与从机之间的通信协议,才能正确地编写代码实现上述所说的“解析从机发送的数据帧”部分的功能。
这也是我在这次课设中的一个瓶颈。
幸运的是,在同学的帮助下顺利地解决了这个问题。
其次,对C语言数组、指针的娴熟运用,可以大大减短代码的编写,并能有效的解决数据帧的缓存发送问题。
然后,就是程序整体架构的排列。
这点在“运行调试”的软件方面的第四点提及。
最后,对Keil、烧写软件、串口调试助手以及试验箱的熟练使用也是这次课设成功的重要因素。
其间遇到的各种问题多亏有同学的帮助和老师周二晚上的集体辅导,促成了我们高效率地完成了这次课设,谢谢老师,谢谢大家!
其实,每件事情并没有想象中的那么难,只要自己多动手操作,知识掌握了,经验积累了,一切问题都可以迎刃而解!
五、参考文献
丁海军等编著.程序设计基础(C语言).北京:
北京航空航天大学出版社,2009
田希晖,薛亮儒编著.C51单片机技术教程.北京:
人民邮电出版社,2007
六、附录
1.实验箱介绍
G部分电路为串口通讯部分。
U5PL2303HX构成了USB转URAT电路,即完成USB口转TTL串口电平。
U6MAX232构成了RS232转URAT电路,即完成RS232串口转TTL串口电平。
由于单片机只有一个串口,所以以上两部分通过双刀双掷开关切换使用,当实验板上S-COM开关按下时选择USB转URAT电路。
否则选RS232转URAT电路。
这部分电路可以完成PC机跟单片机的串行通讯,也可以完成两个单片机进行串行通讯。
D_RXD和D_TXD指示收和发线上是否有信号,当通信时可观察到二灯闪烁。
当选择USB转URAT电路时,PC机的USB口同时承担给实验板供电的任务。
A部分由一个8位琴健开关(U11)和8个LED(D00-D07)组成。
连在P1口上完成基本输入输出功能。
输入功能:
当某开关闭合后,对应P1口线上输入0,同时相应的LED点亮。
否则,对应P1口线上输入1,同时相应的LED熄灭。
例如:
第一位开关闭合,D10点亮,同时P1.0输入0。
LED可以做为开关是否闭合的直观指示。
输出功能:
当某开关打开时,对得用P1口线可以做为输出引脚使用。
当输出1时,相应的LED熄灭,当输出0时,相应的LED点亮。
当某开关闭合时,无法做输
出功能使用。
2.功能码介绍
2.1查询(读)功能码介绍
2.1.1查询地址
功能码00
数据帧
类型
备注
##00000000@@X
发送
查询时由于不知对方地址,使用“0000”地址
##AAAA0004AAAA@@X
正常返回
返回时从机用本机地址覆盖0000,并返回地址AAAA
##AAAA00011@@X
出错返回
校验错误
##AAAA00012@@X
格式错误(前导符、结束符)
##AAAA00013@@X
内容错误(数据超限等)
实例:
发送##00000000@@X
返回##123400041234@X
2.2.2查询量程上限
功能码:
01
##AAAA0100@@X
对方地址必须正确,否则不响应
##AAAA0104DDDD@@X
量程上限必须是4位整数,范围0001
--9999,例如0100,4250等
##AAAA01011@@X
##AAAA01012@@X
格式错误
##AAAA01013@@X
内容错误
2.2.3查询量程下限
02
##AAAA0200@@X
##AAAA0204DDDD@@X
量程下限必须是4位整数,范围0000
--9998,且必须比上限小
##AAAA02011@@X
##AAAA02012@@X
##AAAA02013@@X
2.2.4查询报警上限
03
##AAAA0300@@X
##AAAA0304DDDD@@X
报警上限必须是4位整数,范围0001
##AAAA03011@@X
##AAAA03012@@X
##AAAA03013@@X
2.2.5查询报警下限
04
##AAAA0400@@X
##AAAA0404DDDD@@X
报警下限必须是4位整数,范围0000
##AAAA04011@@X
##AAAA04012@@X
##AAAA04013@@X
2.2.5查询温度值
05
##AAAA0500@@X
##AAAA0507DDDD.DD@@X
温度范围0000.00—5000.00,例如0134.56
##AAAA05011@@X
##AAAA05012@@X
##AAAA05013@@X
2.2.5查询报警状态
06
##AAAA0600@@X
##AAAA0601D@@X
当D为5表示没有报警
当D为6表示正在报警
##AAAA06011@@X
##AAAA06012@@X
##AAAA06013@@X
2.2.5批量查询参数
07
##AAAA0700@@X
##AAAA0716DDDDDDDDDDDDDDDD@@X
共16位数据分别是量程上限、量程下限、报警上限、报警下限
##AAAA07011@@X
##AAAA07012@@X
##AAAA07013@@X
2.2设置(写)功能码介绍
2.2.1设置地址
功能码50
##AAAA5004BBBB@@X
AAAA为原地址,BBBB为新地址
##BBBB50010@@X
成功返回
##AAAA50011@@X
##AAAA50012@@X
##AAAA50013@@X
2.2.2设置量程上限
功能码51
##AAAA5104DDDD@@X
##AAAA51010@@X
##AAAA51011@@X
##AAAA51012@@X
##AAAA51013@@X
2.2.3设置量程下限
功能码52
##AAAA5204DDDD@@X
##AAAA52010@@X
##AAAA52011@@X
##AAAA52012@@X
##AAAA52013@@X
2.2.4设置报警上限
功能码53
##AAAA5304DDDD@@X
##AAAA53010@@X
##AAAA53011@@X
##AAAA53012@@X
##AAAA53013@@X
2.2.5设置量程下限
功能码54
##AAAA5404DDDD@@X
##BBBB54010@@X
##AAAA54011@@X
##AAAA54012@@X
##AAAA54013@@X
3.整个程序
#include<
AT89X51.H>
#defineucharunsignedchar
#defineuintunsignedint;
#definespeakRD;
//蜂鸣器
charbuf_109[30];
//用于单片机字符串数据的缓冲
charslave_addr_109[]="
1234"
charslave_lch_109[]="
5000"
charslave_lcl_109[]="
1000"
charslave_bj_109h_109[]="
9000"
charslave_bj_109l_109[]="
3000"
ucharcount_109=0;
//数据帧长度
ucharflag_109;
//标志点亮P1口连接的LED(已接高)
uintj_109;
voiddelay_109()
//uintj_109;
for(j_109=0;
j_109<
32000;
j_109++);
}
voidserial_109()interrupt4
if(RI)
RI=0;
buf_109[count_109]=SBUF;
count_109++;
}
}
voidload_109(uchar*msg_109)
while(*msg_109!
=0)
SBUF=*msg_109;
while(!
TI=0;
msg_109++;
}
}//查询地