您的位置:首页 > 其它

【51单片机学习过程记录】15 中断之串口中断查询方式中出现的问题及分析

2016-11-10 03:24 295 查看
声明:【51单片机学习过程记录】全是我自己学习、实践所记录的过程,我只是菜鸟,所有论点和观点仅代表我个人,不能确定是这个技术的真理。我的目的是学习和有可能成为可以向别人分享的经验,因此有错误我会虚心接受,并认真改正。

问题代码:

#include <reg52.h>

#define uchar unsigned char

#define uint unsigned int

uchar ch,x;

void serialportinit()

{

// EA=1;//全开

// ES=1;//串口中断开查询方式需要把中断关闭

TMOD=0x20;//定时计数器1,8位自动装载计数器,作用是产生波特率

SCON=0x70;//串口使用工作模式1,8位UART,波特率可变

PCON|=0x00;//计算波特率中的smod位在PCON寄存器中

TH1=0xfd;//设置串口波特率为9600bps;

TR1=1;//定时计数器1开启

}

void main()

{

x=1;

serialportinit(); //串口初始化

while(1)

{

if(RI)
{

RI=0;

ch=SBUF;  

SBUF=ch;

while(!TI);

TI=0;

SBUF=x;

while(!TI);

TI=0;

}

}

}

串口通信中的查询方式,代码基本和上一篇记录差不多,不同的地方(红色标注代码)是我在发送接收到的数据后,继续发送自己定义的一个unsigned char型的x给串口助手。



现象一:

串口助手发送abc,  在mcu发送回数据后,串口助手显示的数据是   61 01 62 01 63 01(十六进制显示)

解释: 之所以没有得到预期的返回 61 62 63 01(abc1),是因为串口是把数据一个字节一个字节那样发送的,abc是三个字符,即三个字节。整个过程是串口助手发送abc(分三次发送,每次发送一个字节)---mcu接收a---mcu发送a---mcu发送x=1---mcu接收b---mcu发送b---mcu发送x=1---mcu接收c---mcu发送c---mcu发送x=1。
 所以串口助手显示61 01 62 01 63 01。

现象二:

串口助手发送abc1,在mcu发送回数据后,串口助手显示的数据是  61 01 62 01 63 01  ,或者是  61 01 62 01 31 01(字符1的ACSII值是0x31),前者的次数较多。却没有得到预期的返回数据 61 01 62 01 63 01 31 01,即mcu只是发送了三个字节给串口助手。

(问题出现了,也许避免问题,可以按照常见的方式去写代码,但还是要知道问题出现在什么地方,毕竟项目中的代码不可能一直仿照正确的模板吧?这里涉及的串口数据不正确的例子,只是众多问题之一,所以当以后出现其他数据丢失方面的问题,也许可以按照这样思路去想。)

解释:

串口助手的数据是连续的,每个字节的发送给mcu,mcu在接收到数据后再发送数据回串口助手的过程中,仍然在接收来自串口助手发送来的数据。也就是说,在全双工的串口通信中,接收和发送是同时进行的。

一帧接收结束,使RI=1;申请中断

当起始位0移到输入寄存器的最左边时,就通知接收控制器进行最后一次移位,把移位寄存器的内容(第9位)分别装入SBUF和RB8,并使RI=1,申请中断,装入SBUF和RB8以及置位RI的信号,只有产生在最后一个移位脉冲,且同时满足下列两个条件时才会发生:

1 RI=0;

2 SM2=0 或 接收到的停止位=1

上述两个条件任一不满足时,所接收的数据帧就被丢弃,RI仍为0,不申请中断;两者都满足时,停止位就进入RB8,8位数据位进入SBUF,RI=1,申请中断,然后,接收控制器将重新采样RXD端出现的负跳变,以接收下一帧数据。

那么问题可能就出现在RI上,因为它是由硬件置位,由软件(代码)清零   

mcu接收a,然后发送a,再发送x,注意,mcu串口接收数据和发送数据的用时是一样的,发送和接收的时间是 1/9600*10秒(波特率的倒数是一位的时间,一帧包括8位,以及起始位和结束位,所以一共是10位)

当mcu在连续发送a和x的时候,则比接收一个字符多了1/9600*10秒,而在这段时间中,mcu的接收寄存器正在接收来自串口助手的第二个字符b,以及,第三个字符c,数据b进入串口缓冲寄存器SBUF,然后RI=1,而数据c 则仍然在接收中,(硬件上,mcu的接收端是双缓冲,有缓冲寄存器SBUF和移位寄存器,这样的硬件结构目的是避免了接收数据帧时发生帧重叠,即下一帧数据到来时,上一帧数据还没读走)。
 判断完RI=1后,将RI置零,然后mcu从SBUF中接收b,代码ch=SBUF,接收b,同样,在mcu连续发送b和x 时,从串口助手发送过来的字符1 也被接收, 再往里面看,看小范围些,假设在接收完b后的发送过程中c也接收完了,RI置一,而字符1仍在接收中,但问题出现在,判断完由数据c 所置位的RI(RI=1)后,字符
4000
数据1也刚好接收完成,然后在进入 if(RI)  后也将RI置一,接着软件清零RI=0,但mcu 正在处理的数据是 c, 所以 数据 字符1 就被丢弃了,并没有被mcu接收成功。所以这时发送
abc1 后,返回的数据会出现第一种情况:61 01 62 01 63 01(axbxcx)

再有,就是数据c还没被处理完成时,就被接收过来的数据 字符1 造成数据帧重叠,替换掉数据c ,所以这时发送abc1 后,返回的数据出现第二种情况(这种较少出现)61 01 62 01 31 01(axbx1x)

总结:

问题的原因:接收数据的时间快,但处理数据的时间慢,造成数据的丢弃或重叠。

学习串口后,让我印象深刻的一点是,mcu在工作时,不单单只是在代码执行,也就是说,当代码在执行的时候,硬件上某个地方也在变化中,且代码是来不及处理,所以才有可能代码是没错,但是执行的结果不达预期。也就是这个问题,一直困扰,现在才总结记录下来。 

对于上面的假设,是真实存在的,请教了一位网友(如果需要,再发链接吧,不敢擅自转载),他是用逻辑分析仪专门查看了串口的收发数据时序。  

我想说的是,原来除了软件有未知的错误意外,硬件上也会有类似让人不可以抓到根本点的错误出现,这里说的模糊,就是通信的时间、频率、速度等吧,所以写程序时还是要避免这些问题吧,当然,懂得避免,应该是要知道问题也许是出现在哪里,即使未能精确地知道问题就是出在哪一个点上。

最后,记录文是我边学习边理解和总结出来的,如果有地方不正确,希望能指出,本人定虚心受教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: