今天来总结一下C51单片机串口驱动层丢包的几种情况.
---C51单片机串口收发数据的原理---
1、串口驱动模块组成
(1)串口数据收发器,串口收发数据时,底层执行实际收发动作的硬件单元;
(2) 串口相关寄存器,
SBUF:串口数据寄存器,当有数据收或发时,用来装载收或发的数据,实际底层是分开收和发两个不同寄存器的,用户(程序员)只用SBUF就可以了;
RI:串口接收中断标志,告诉CPU现在串口收到数据了
TI:串口发送中断标志,告诉CPU现在串口有数据要发了;
TI和RI都是系统产生用户软件清零的。
(3)串口中断服务函数;串口收数据和发数据的中断是一个,收和发在同一个中断服务函数进行,在RI为1时把寄存器SBUF里的数据拷贝到用户缓存里,在TI为1 时,把用户要发的数据装载到SBUF里。
2、收数据过程
(1)对端串口发送器发了1byte数据
(2) 串口接收器收到1byte数据,存到SBUF寄存器,并把寄存器中RI位置1
(3)系统产生一个中断,CPU内核轮询发现RI为1是串口中断,从用户程序跳转至串口中断服务函数
(4)串口中断服务函数中,把SBUF寄存器中的这1byte数据拷贝至用户缓存
收数据过程是1byte产生一个中断,也就是说数据是1byte 1byte收的。
数据流向过程如下图:
3、发数据过程
(1)用户把TI置1
(2) 系统产生中断,内核轮询到TI为1,跳转至串口中断服务函数
(3) 用户把1byte要发的数据装载至SBUF
(4)硬件发送器发送数据,发送完成自动把TI置1
(5)系统产生中断,重复(2)~(4)
(6) 当用户不再往SBUF装数据时,发送数据过程结束
发数据也是1byte 1byte发,每1byte先产生中断再装载数据。
数据流向过程如下图:
---串口丢包总结---
说明下,这是无操作系统的单片机程序。
我 = 串口硬件收发器+串口软件中断服务函数+串口相关寄存器。
用户 = 应用程序
1、我的硬件收发器在收发数据,用户把系统总中断关了
先说收数据的情况,系统中断被用户关了,我的硬件部分还是能收数据的,我仍然会把RI置1,但是现在总中断关了,就不会产生中断了,不会去调起我的软件中断服务函数了,那这样就会造成我放到SBUF里的数据还没有传给用户,如果关中断期间,我又收到了新的1byte数据,我就会把新的数据放到SBUF里,覆盖了老的数据了。
这样老的那1byte数据就丢掉了。
举例:串口正在收数据时,用户要写一些掉电记忆的参数到Flash,操作Flash会关总中断,此时如果串口在收数据可能会丢包。
解决:关总中断之前判断一下串口是不是在忙,串口无数据收到连续累计一段时间才认为闲。
发数据的情况会不会有问题?如果我的硬件在发数据,用户把总中断关了,我发完这1byte数据仍然会把TI置1,但是此时不会产生中断,不会再进入我的软件中断服务函数继续发数据,等中断恢复了,CPU会马上进入我的中断服务函数,又会继续发数据,所以发数据过程关总中断不会造成发数据丢包。
2、有人在中断服务函数里待太久,耽误我的软件收数据
我的硬件收到了数据,我把他放到了SBUF里,同时也置起了RI标志位,但不巧,这时候CPU在另一个中断服务函数里在执行代码,更不巧,这个中断服务函数很长,有很多代码要执行,要很久很久!
这不就误事了吗,CPU还没从那个中断服务函数出来,我的硬件又收到了新的1byte数据,我又把他装到了SBUF里,置起了RI,老的那1byte数据还在SBUF,没传给用户缓存呢,新的把他覆盖掉了。
举例:某MCU LED驱动用调光模式(即可调亮度模式),由于其中断服务函数太长,造成串口收数据丢包
解决:设置串口中断优先级高于LED中断优先级,C51中高优先级中断可以抢断低优先级中断,这样串口就不会丢包了。
3、大量数据又收又发,我的软件部分不够聪明,忙不过来了
同时有数据在收和发,我也是能应付的,因为咱是全双工的啊,收数据和发数据可以同时进行,是不同的硬件单元;此时RI和TI都会被我置成1,系统会进去中断服务函数,但系统是不知道这次进去是TI还是RI事件的,只管其中一个为1就进去了。
我的软件中断服务函数进去一次可以把收和发的数据都处理了,出来后就不会再次进中断服务函数了,
如果程序员把我的软件写成进一次中断服务函数只处理RI或者TI一个事件,那就效率很低啊!数据很多时极有可能会丢包!
比如如果优先处理TI事件,下次再进来想处理RI了但此时TI事件又有了,RI事件就又没处理到了。
如果优先处理RI事件,收到的数据不会丢,但是下次进来RI事件又产生了,又要处理RI事件,想发的数据一直没机会发。
所以,串口中断服务函数里要能同时处理RI 和TI 中断事件,下图中的else if 应改成if。
又如果,串口中断服务函数里面太长,前一次还没处理完,新的中断又到了,就会自己耽误自己。
4、当前数据还没发完,用户又把新数据装到我的SBUF中
我的硬件在发数据,此时TI已经被用户程序清0了,
如果程序员逻辑不够清晰,马上又要发一包新数据,把TI置1 了,那么CPU会马上进入中断服务函数,中断服务函数马上会把新的1byte 数据装到我的SBUF里,我刚刚正在发的那1byte 数据还没发完就被新数据覆盖弄丢了。
解决:程序串口驱动层接口发数据前,先判断当前是否处于发送数据过程中,若正在发送过程中,不用再将TI置1.
5、 我们这里总中断关了,对方还发数据给我
总中断关了,对方给我发数据,我的硬件还是能收到数据的,我也会把RI置1,但是此时就不会产生中断,不会进入中断服务函数了,如果对方马上又给我发了新的1byte数据,用户这时还是没有把总中断打开,刚刚那1byte数据还在SBUF中会被新来的数据覆盖,用户没取走丢掉了。
解决:对方增加重发逻辑。
6、我硬件能力不够,收发速度跟不上
用户竟然选择了系统时钟才2M,我的波特率却被设置成了115200这么大,
此时我的波特率发生器产生的波特率已经不能达到115200了,数据还是能1byte 1byte的发出去,只是就是发出去的数据电平的长度可能不对了,
标准串口每1byte数据 = 1bit起始位+ 8bit数据位+奇偶校验位(1或1.5或2或无)+停止位(1bit),起始电平是低电平,无数据时是高电平。
波特率115200即115200 bit/s,波特率决定了电平0/1的长度,波特率确定了1bit电平的长度就确定了,波特率越大,长度越短。
如果电平长度不对了,对方串口接收器收到这一串电平后经过解析可能就不认为这是一包正确的数据来了,因此丢弃了(底层电路具体是怎么样不是很了解)。
1.外媒谈英伟达-Arm并购案~
2.这里聚焦了全球嵌入式技术风景~
3.航天器、导弹喜欢用单片机?
4.工程师的硬核单片机编程思想~
5.嵌入式开发需要架构设计吗?
6.【技术转管理必备】嵌入式产品的研发流程
免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。