【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在工作时,不单单只是在代码执行,也就是说,当代码在执行的时候,硬件上某个地方也在变化中,且代码是来不及处理,所以才有可能代码是没错,但是执行的结果不达预期。也就是这个问题,一直困扰,现在才总结记录下来。
对于上面的假设,是真实存在的,请教了一位网友(如果需要,再发链接吧,不敢擅自转载),他是用逻辑分析仪专门查看了串口的收发数据时序。
我想说的是,原来除了软件有未知的错误意外,硬件上也会有类似让人不可以抓到根本点的错误出现,这里说的模糊,就是通信的时间、频率、速度等吧,所以写程序时还是要避免这些问题吧,当然,懂得避免,应该是要知道问题也许是出现在哪里,即使未能精确地知道问题就是出在哪一个点上。
最后,记录文是我边学习边理解和总结出来的,如果有地方不正确,希望能指出,本人定虚心受教。
问题代码:
#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在工作时,不单单只是在代码执行,也就是说,当代码在执行的时候,硬件上某个地方也在变化中,且代码是来不及处理,所以才有可能代码是没错,但是执行的结果不达预期。也就是这个问题,一直困扰,现在才总结记录下来。
对于上面的假设,是真实存在的,请教了一位网友(如果需要,再发链接吧,不敢擅自转载),他是用逻辑分析仪专门查看了串口的收发数据时序。
我想说的是,原来除了软件有未知的错误意外,硬件上也会有类似让人不可以抓到根本点的错误出现,这里说的模糊,就是通信的时间、频率、速度等吧,所以写程序时还是要避免这些问题吧,当然,懂得避免,应该是要知道问题也许是出现在哪里,即使未能精确地知道问题就是出在哪一个点上。
最后,记录文是我边学习边理解和总结出来的,如果有地方不正确,希望能指出,本人定虚心受教。
相关文章推荐
- 【51单片机学习过程记录】16 中断之 串口中断的应用2(中断方式)
- 【51单片机学习过程记录】13中断 之串口中断应用前的了解过程(较详细)
- 【51单片机学习过程记录】11 中断之外部中断的应用
- 使用51单片机采用查询方式进行串口通信的学习记录
- 【51单片机学习过程记录】9 中断之定时计数器0的使用2
- 【51单片机学习过程记录】8 中断 之定时计数器0的使用
- 【51单片机学习过程记录】12中断 之外部中断的应用2
- 使用51单片机采用中断方式进行串口通信的学习记录:
- 【51单片机学习过程记录】10 中断之定时计数器1的应用
- 【51单片机学习过程记录】7 中断之 定时计数器0 操作前理解过程
- 关于串口通讯查询与中断两种方式
- 从今天起,我要记录学习过程中遇到的所有问题
- 使用autotools工具制作Makefile过程可能出现问题与解决方式
- 51学习之定时器中断的两种方式——查询和中断
- 最近学习过程中遇到的问题,记录一下
- 今天学习asp.net mvc的过程中出现了一点问题,是有关浏览器的,一个疑问?
- 学习使用Jpcap抓取数据包过程中的一些记录和问题
- C++ 学习拾遗 —— 点滴记录C++学习过程中遇到的问题以及整理
- C++ 学习拾遗 —— 点滴记录C++学习过程中遇到的问题以及整理
- C++学习过程中的问题记录