标题: 请教单片机如何避免串口接收数据丢失? [打印本页]

作者: happy2058    时间: 2021-10-13 00:17
标题: 请教单片机如何避免串口接收数据丢失?
单片机与触控屏通信  按下屏幕下发 AA 79 ** ** 33 cc c3 3c  抬起屏幕下发 AA 78 ** ** 33 cc c3 3c  中间两个字节用户定义相同指令
以下部分代码
uchar buf[16];      //接收缓存区     这里因为上电握手最大长度,所以给了16  下面程序只用到8个字节
uchar rp = 0;       //缓存区地址

void interrupt_uart() interrupt 4 //using 3   //串口接收,定时器2 115200
{
                if (RI)  
                        {  
                        RI = 0 ;               
                        buf[ rp++ ] = SBUF;
                        if(SBUF==0X3C)                      //接收到尾 地址复位
                                rp=0;               
                        }
        }



void key_service()                //放在大循环        while(1) 里一直调用                                                
{        
switch(buf[1])                         //对应该按下 指令 79后进行比较                                       
                        {
                                case 0X79:
                                
                                if(        buf[3]==0x01 && buf[7]==0x3c)             //buf[3]==0x01 是用户指令01 只判定buf[3]                                       
                                 {
                                        memset(buf, 0, 16)
                                       **********此处省略**********
                                }
                                if(        buf[3]==0x02 && buf[7]==0x3c)                                                
                                {
                                           memset(buf, 0, 16)
                                        **********此处省略**********        
                                }
                                if(        buf[3]==0x03 && buf[7]==0x3c)                                                
                                {        
                                          memset(buf, 0, 16)
                                        **********此处省略**********
                                }
                                if(        buf[3]==0x04 && buf[7]==0x3c)                                                               
                                {
                                          memset(buf, 0, 16)
                                      **********此处省略**********
                                }
                                
                                ......................        
                               总共15个IF判断
                        
                                break;        
                        
                        case 0X78:             //对应该抬起 指令 78后进行比较        
               
                                if(buf[0]==0xAA && buf[7]==0x3c)               //   接收完成
                        {        
                                for(i=0;i<16;i++)                                   //清空缓存区
                                {
                                        buf[ i]=0;
                                }
                                                               
                                //memset(buf, 0, 16)                              //清空缓存区   感觉这个函数比较费时,所以没用 ,求指教
                        }
                                
                                  break;  
                                default:break;
                        }
}


目前程序运行正常。
请问,如果数据接收慢,当case 0X79: 跑完了,用户指令才来,或者我要比较指令01 。但可能跑到03去比较了。这时候 01 才到。那么这一次不执行。退出 case 0X79: 这时候缓存区未被清空,(此处为单次点击)
当抬起屏幕的时候指令78来了,会覆盖缓存区 ,然后 switch(buf[1]) 在while(1) 里一直调用。直到清空
(正常操作点击屏幕按下抬起不作停留 。屏幕下发数据是  AA 79**********   AA 78 ********** 中间有很短的间隔)
这次点击那就无效了。
如果在case 0X79后面加上while (buf[7]!=0x3c) 防止没接收完就判断,会有多大影响。谢谢大家

作者: ucmic    时间: 2021-10-13 07:45
参考宋老师的串口接收部份。百度金沙滩工作室
作者: ly1972001    时间: 2021-10-13 08:00
再加缓存,就不怕buf[]的变化了。当一帧数据接收完毕,置标志位,放入缓存,再进行数据处理。
作者: npn    时间: 2021-10-13 08:09
请提供下波特率和晶振频率确定是否为误码率高。
作者: 18701931930    时间: 2021-10-13 08:21
如果你的单片机处理速度比较慢,那就降低波特率。或者采用闭环控制的方式。
作者: xuyaqi    时间: 2021-10-13 08:35
应该是一帧数据接收完设置标志,再进行判断,不应该收一个判断一个。
作者: happy2058    时间: 2021-10-13 09:51
npn 发表于 2021-10-13 08:09
请提供下波特率和晶振频率确定是否为误码率高。

24M 1T  115200
作者: xstong    时间: 2021-10-13 10:16
总体思路:中断仅缓存接收数据,接收完毕唤醒任务处理数据。
使用一个定时器,每次串口中断接收到一个字节,缓存数据后更新定时器延后一段时间产生定时器超时中断,只要串口连续接收到数据,超时中断不会产生,反之只要定时器发生超时中断,则判定为一帧连续数据接收完毕。
整个串口数据接收过程,全部由串口和定时器中断完成,无需任务参与,任务只需要在接收完毕后由定时器中断唤醒后做数据帧解析处理。
如果其它功能应用对中断占用时间不敏感,可以直接在定时器超时中断里面处理数据帧。全程任务完全无需参与了。
作者: npn    时间: 2021-10-13 11:00
happy2058 发表于 2021-10-13 09:51
24M 1T  115200

串口需要用 22.1184Mhz 或 33.1776Mhz 才可以的。
作者: lengrudie    时间: 2021-10-13 11:50
增加数据缓存是比较好的方法,可以的话最好做个环形队列,先进先出。
作者: 笨笨兔    时间: 2021-10-13 14:12
建议改变整个程序结构,那样更简单,更有效。
作者: yzwzfyz    时间: 2021-10-13 17:10
所有的中断程序处理时间,不大于1个字节的串行拼装时间,你能做到就可以。
作者: xiao_yyp    时间: 2021-10-13 17:17
加缓存, 数据接收完毕,设置标志位,放入缓存后再进行数据处理

作者: 188610329    时间: 2021-10-13 20:46
做缓冲池,比如你一个指令8个字节,你做一个128字节的缓冲池,最多保存16个指令,那么,应该就没啥问题了。




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1