您的位置 首页 分销

单片机模仿串口发送和波特率问题

传统的8051系列单片机一般都配备一个串口,而STC89C52RC增强型单片机也不例外,只有一个串口可供使用,这样就出问题了,假如当前单片机系

传统的8051系列单片机一般都装备一个串口,而STC 89C52RC增强型单片机也不破例,只要一个串口可供运用,这样就出问题了,假定当时单片机体系要求二个串口或多个串口进行一起通讯,8051系列单片机只要一个串口可供通讯就显得非常为难,可是在实践的运用中,有两种办法能够挑选。

办法1:运用能够支撑多串口通讯的单片机,不过经过替换其他单片机来替代8051系列单片机,这样就会直接导致本钱的添加,长处便是编程简略,并且通讯安稳牢靠。
办法2:在IO资源比较足够的情况下,能够经过IO来模仿串口的通讯,尽管这样会添加编程的难度,模仿串口的波特率会比真实的串口通讯低一个层次,可是仅有长处便是本钱上得到操控,并且经过不同的IO组合能够完结愈加之多的模仿串口,在实践运用中往往会选用模仿串口的办法来完结多串口通讯。
遍及运用串口通讯的数据流都是1位开始位、8位数据位、1位中止位的格局的,如表1。
表1

开始位 8位数据位 中止位
0 Bit0 Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7 1


要注意的是,开始位作为辨认是否有数据到来,中止位标志数据现已发送完毕。开始位固定值为0,中止位固定值为1,那么为什么开始位要是0,中止位要是1呢?这个很好了解,假定中止位固定值为1,为了愈加易辨认数据的到来,电平的跳变最为简略也最简单辨认,那么当有数据来的时分,只要在规则的时刻内检测到发送过来的第一位的电平是否0值,就能够确认是否有数据到来;别的中止位为1的效果便是当没有收发数据之后引脚置为高电平起到抗干扰的效果。
在平常运用红外无线收发数据时,一般都选用模仿串口来完结的,可是有个问题要注意,波特率越高,传输间隔越近;波特率越低,传输间隔越远。关于这些经过模仿串口进行数据传输,波特率适合为1200b/s来进行数据传输。
比如:在运用单片机的串口接纳数据试验傍边,运用串口调试帮手发送16字节数据,单片机选用模仿串口的办法将接纳到的数据返发到PC机。
模仿串口试验代码:


1#include”stc.h”
2
3#defineRXD P3_0//宏界说:接纳数据的引脚
4#defineTXD P3_1//宏界说:发送数据的引脚
5#defineRECEIVE_MAX_BYTES 16//宏界说:最大接纳字节数
6
7#defineTIMER_ENABLE() {TL0=TH0;TR0=1;fTimeouts=0;}//使能T/C
8#defineTIMER_DISABLE() {TR0=0;fTimeouts=0;}//制止T/C
9#defineTIMER_WAIT() {while(!fTimeouts);fTimeouts=0;}//等候T/C超时
10
11
12unsignedcharfTimeouts=0;//T/C超时溢出标志位
13unsignedcharRecvBuf[16];//接纳数据缓冲区
14unsignedcharRecvCount=0;//接纳数据计数器
15
16
17
23voidSendByte(unsignedcharb)
24{
25unsignedchari=8;
26
27TXD=0;
28
29TIMER_ENABLE();
30TIMER_WAIT();
31
32
33while(i–)
34{
35if(b&1)TXD=1;
36elseTXD=0;
37
38TIMER_WAIT();
39
40b>>=1;
41
42}
43
44
45TXD=1;
46
47TIMER_WAIT();
48TIMER_DISABLE();
49}
50
56unsignedcharRecvByte(void)
57{
58unsignedchari;
59unsignedcharb=0;
60
61TIMER_ENABLE();
62TIMER_WAIT();
63
64for(i=0;i<8;i++)
65{
66if(RXD)b|=(1<67
68TIMER_WAIT();
69}
70
71TIMER_WAIT();//等候完毕位
72TIMER_DISABLE();
73
74returnb;
75
76}
77
83voidPrintfStr(char*pstr)
84{
85while(pstr&&*pstr)
86{
87SendByte(*pstr++);
88}
89}
90
96voidTimerInit(void)
97{
98TMOD=0x02;
99TR0=0;
100TF0=0;
101TH0=(256-99);
102TL0=TH0;
103ET0=1;
104EA=1;
105}
106
112unsignedcharStartBitCome(void)
113{
114return(RXD==0);
115}
116
122voidmain(void)
123{
124unsignedchari;
125
126TimerInit();
127
128PrintfStr(“Hello 8051rn”);
129
130while(1)
131{
132if(StartBitCome())
133{
134RecvBuf[RecvCount++]=RecvByte();
135
136if(RecvCount>=RECEIVE_MAX_BYTES)
137{
138RecvCount=0;
139
140for(i=0;i141{
142SendByte(RecvBuf[i]);
143}
144}
145}
146
147}
148}
149
155voidTimer0IRQ(void) interrupt1using0
156{
157fTimeouts=1;
158}
159


代码剖析
在模仿串口试验代码中,宏的运用占用了适当的一部分。
#define RXD P3_0//宏界说:接纳数据的引脚
#define TXD P3_1//宏界说:发送数据的引脚
#define TIMER_ENABLE(){TL0=TH0;TR0=1;fTimeouts=0;}//使能T/C
#define TIMER_DISABLE() {TR0=0;fTimeouts=0;}//制止T/C
#define TIMER_WAIT(){while(!fTimeouts);fTimeouts=0;}//等候T/C超时

模仿串口接纳引脚为P3.0,发送引脚为P3.1。为了到达准确的守时,削减模仿串口时收发数据的累积差错,有必要经过对T/C进行频频的使能和制止等操作。例如宏TIMER_ENABLE为使能T/C,宏TIMER_DISABLE制止T/C,宏TIMER_WAIT等候T/C超时。
模仿串口的作业波特率为9600b/s,在串口收发的数据流傍边,每一位的时刻为1/9600≈104us,
若单片机作业在12MHz频率下,运用T/C0作业在方法2,那么为了到达104us的守时时刻,TH0、TL0的初值为256-104=152,在实践的模仿串口中,往往呈现收发数据不正确的现象。原因就在于TH0、TL0的初值,或许很多人会疑问,按道理来说,核算T/C0的初值是没有错的。对,是没有错,可是在SendByte和Recv的函数傍边,履行每一行代码都要耗费必定的时刻,这便是所谓的“累积差错”导致收发数据呈现问题,因而咱们有必要经过实践测验得到TH0、TL0的初值,最佳值256-99=157。那么在T/C初始化TimerInit函数中,TH0、TL0的初值不能够依照惯例来核算得到,实践初值在正常初值邻近,能够经过实践测验得到。
模仿串口首要杂乱在模仿串口发送与接纳,详细完结函数在SendByte和RecvByte函数,这两个函数有必要要遵从“1位开始位、8位数据位、1位中止位”的数据流。
SendByte函数用于模仿串口发送数据,以开始位“0”作为移位传输的开始标志,然后即将发送的自己从低字节到高字节移位传输,最终以中止位“1”作为移位传输的完毕标志。
RecvByte函数用于模仿串口接纳数据,一旦检测到开始位“0”,就马上将接纳到的每一位移位存储,最终以判别中止位“1”完毕当时数据的接纳。
main函数完结T/C的初始化,在while(1)死循环以检测开始位“0”为意图,当接纳到的数据到达宏RECEIVE_MAX_BYTES的个数时,将接纳到的数据返发到外设。

波特率的研讨


通常情况下,8051系列单片机外接晶振频率一般是12MHz、24MHz、48MHz如图7-6-1,为什么会这样选取呢?早年面的章节现已介绍8051系列单片机的每12个时钟周期为一个指令周期,当8051系列单片机外接12MHz晶振时,指令周期=12/12MHz=1us;若外接24MHz晶振时,指令周期=12/24MHz=0.5us;若外接48MHz晶振时,指令周期=12/48MHz=0.25us。8051系列单片机外接能够被除尽的晶振,在运用单片机内部的守时器/计数器资源时作守时器运用时能够得到准确认时运用;当运用汇编语言编程时,能够清楚知道当时每一行代码履行的时刻。
8051系列单片机外接能够被除尽的晶振即12MHz、24MHz、48MHz这些晶振时,波特率的准确性就得不到确保。

假若现在单片机外接的晶振为12MHz时,以T/C2作波特率发生器,依据波特率公式:
波特率=Fosc/2x16x(65536-t)
9600=12MHz/2x16x(65536-t)
t=65496.9375
“65496.9375”不是一个整数值,是一个带有小数点的数值。关于常用的8位、9位、11位一帧的数据接纳与传输,最大的答应差错别离是6.25%、5.56%、4.5%。尽管波特率答应差错,可是这样通讯时便会发生堆集差错,从而影响数据的正确性。仅有的解决办法便是更改单片机外接的晶振频率,更改为常用于发生准确波特率的晶振如11.0592MHz、22.1184MHz。
假若现在单片机外接的晶振为11.0592MHz时,以T/C2作波特率发生器,依据波特率公式:
波特率=Fosc/2x16x(65536-t)
9600=11.0592MHz/2x16x(65536-t)
t=65500=0xFFDC

尽管运用11.0592MHz、22.1184MHz的晶振能够发生准确的波特率,可是用于体系准确的守时服务不是非常的抱负。例如单片机外接11.0592MHz晶振时,指令周期=12/11.0592MHz≈1.085us,是一个无限循环的小数。当单片机外接22.1184MHz晶振时,指令周期=12/22.1184MHz≈0.5425us,也是一个无限循环的小数。

串口作业在方法1时别离选用T/C1和T/C2发生常用波特率初值表如下。

波特率
(11.0592MHz)
初值 波特率
(12MHz)
初值
TH1、TL1
(SMOD=0)
TH1、TL1
(SMOD=1)
TH1、TL1
(SMOD=0)
TH1、TL1
(SMOD=1)
1200 0xE7 0xD0 1200 0xE5 0xCB
2400 0xF3 0xE7 2400 0xF2 0xE5
4800 0xF9 0xF3 4800 0xF9 0xF2
9600 0xFC 0xF9 9600 0xFC 0xF9
14400 0xFD 0xFB 14400 0xFD 0xFB
19200 0xFE 0xFC 19200 0xFE 0xFC


波特率
(11.0592MHz)
初值 波特率
(12MHz)
初值
RCAL2H RCAL2L RCAL2H RCAL2L
1200 0xFE 0xE0 1200 0xFE 0xC8
2400 0xFF 0x70 2400 0xFF 0x64
4800 0xFF 0xD8 4800 0xFF 0xB2
9600 0xFF 0xDC 9600 0xFF 0xD9
14400 0xFF 0xE8 14400 0xFF 0xE6
19200 0xFF 0xEE 19200 0xFF 0xED


假如我们想经过设置不同的晶振获取愈加多的波特率的值,能够下载以下东西进行核算:
软件下载地址:http://files.cnblogs.com/wenziqi/单片机多功能帮手.rar

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/bandaoti/fenxiao/256766.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部