找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2037|回复: 13
收起左侧

请教单片机如何避免串口接收数据丢失?

  [复制链接]
ID:734017 发表于 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) 防止没接收完就判断,会有多大影响。谢谢大家
回复

使用道具 举报

ID:460753 发表于 2021-10-13 07:45 | 显示全部楼层
参考宋老师的串口接收部份。百度金沙滩工作室
回复

使用道具 举报

ID:236035 发表于 2021-10-13 08:00 | 显示全部楼层
再加缓存,就不怕buf[]的变化了。当一帧数据接收完毕,置标志位,放入缓存,再进行数据处理。
回复

使用道具 举报

ID:57657 发表于 2021-10-13 08:09 | 显示全部楼层
请提供下波特率和晶振频率确定是否为误码率高。
回复

使用道具 举报

ID:554500 发表于 2021-10-13 08:21 | 显示全部楼层
如果你的单片机处理速度比较慢,那就降低波特率。或者采用闭环控制的方式。
回复

使用道具 举报

ID:94031 发表于 2021-10-13 08:35 | 显示全部楼层
应该是一帧数据接收完设置标志,再进行判断,不应该收一个判断一个。
回复

使用道具 举报

ID:734017 发表于 2021-10-13 09:51 | 显示全部楼层
npn 发表于 2021-10-13 08:09
请提供下波特率和晶振频率确定是否为误码率高。

24M 1T  115200
回复

使用道具 举报

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

使用道具 举报

ID:57657 发表于 2021-10-13 11:00 | 显示全部楼层

串口需要用 22.1184Mhz 或 33.1776Mhz 才可以的。
回复

使用道具 举报

ID:971661 发表于 2021-10-13 11:50 | 显示全部楼层
增加数据缓存是比较好的方法,可以的话最好做个环形队列,先进先出。
回复

使用道具 举报

ID:158375 发表于 2021-10-13 14:12 | 显示全部楼层
建议改变整个程序结构,那样更简单,更有效。
回复

使用道具 举报

ID:123289 发表于 2021-10-13 17:10 | 显示全部楼层
所有的中断程序处理时间,不大于1个字节的串行拼装时间,你能做到就可以。
回复

使用道具 举报

ID:971769 发表于 2021-10-13 17:17 | 显示全部楼层
加缓存, 数据接收完毕,设置标志位,放入缓存后再进行数据处理
回复

使用道具 举报

ID:624769 发表于 2021-10-13 20:46 | 显示全部楼层
做缓冲池,比如你一个指令8个字节,你做一个128字节的缓冲池,最多保存16个指令,那么,应该就没啥问题了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表