μc/OS-Ⅲ串口接收丢数据

2020-01-11 18:13发布

本帖最后由 SUPER_CRJ 于 2018-1-15 12:22 编辑

使用μc/OS-Ⅲ,其中串口4接收丢数据,但是在裸机上就没有这样的问题,同样的硬件,使用裸机的时候,正常,也就排除了是硬件问题,但是使用μc/OS-Ⅲ的时候,串口中断接收的数据就会丢失,而且有如下规律:
1:波特率越高,丢的越明显,大概的情况会是:2M波特率下,每40个数据,就会丢失一个。但是在1.5M的时候,就大概第100多个丢失。
但是想不明白的是:我觉得写的这个程序没有发现问题,之前使用460800的时候,也是同样的程序,没有发现问题(但是最近客户反应存在丢的情况),于是个人认为是软件问题!
怀疑的问题如下:是μc/OS-Ⅲ的任务切换导致任务调度的时候出现关中断行为~但是查找网上搜索资料,把:调度器使用上锁的方式,而不是关中断的方式,同样也是出现同样的问题!

本函数如下:就是串口接收到数据就把数据放到数组中,同时写指针+1,然后用信号量同步任务。
发现的问题是:每次发送40个字节,但是接收到有时候没有40个字节(波特率2M时,几乎每次都丢,1.5M的时候几百个丢一个!(不要怀疑波特率高!实测裸机没有问题!)),但是如果去掉操作系统相关的,就是只留下中断接收保留到数组就没有这样的问题!

#define COMBUF_MAXBUFF_SIZE 1024        // 1024个字节
#define COMMSG_MINLEN       40          // 40帧的报文

extern OS_MUTEX USART2_SendUseRight_Mutex;
extern OS_SEM   USART2_HadReceiveData_Sem;  

typedef struct
{
__IO        u8 Buf[COMBUF_MAXBUFF_SIZE];
__IO  u16 pRead;
__IO        u16 pWrite;
}ComBuf;
ComBuf Com4;   // 本函数使用了,串口4
/**
* @brief UART4 中断函数
*/

void UART4_IRQHandler()
{
        OS_ERR err;
       
        OSIntEnter();   // 使用μC/OS系统
        if( UART4->SR.ReadDataRegisterNotEmpty_RCW0 == TRUE )
        {
                Com4.Buf[Com4.pWrite++] = UART4->DR.Data_RW;
                Com4.pWrite %= COMBUF_MAXBUFF_SIZE;
        }
        OSSemPost ( (OS_SEM  *)&USART2_HadReceiveData_Sem,
                                                        (OS_OPT   )OS_OPT_POST_1,
                                                        (OS_ERR  *)&err );
        OSIntExit();
}

/**
* @brief 处理串口接收到命令的函数,显然需要用信号量同步处理
*/
void  USARTDataProcess_Task( void *p_arg )
{
        OS_ERR err;
        CPU_TS ts;
        while( DEF_ON )
        {
                OSSemPend(  (OS_SEM  *)&USART2_HadReceiveData_Sem,  // 等待信号量用来同步
                                                                (OS_TICK  )0,
                                                                (OS_OPT   )OS_OPT_PEND_BLOCKING,
                                                                (CPU_TS  *)&ts,
                                                                (OS_ERR  *)&err);
                if( err != OS_ERR_NONE ) {  // 出错就卡住
                        while(1);
                }
                        {
                                // 报文处理函数,大于报文开始处理,报文处理函数优先级是除了SWD函数的第二高的优先级
                                if( ((( Com4.pWrite + COMBUF_MAXBUFF_SIZE ) - Com4.pRead ) % COMBUF_MAXBUFF_SIZE ) >= COMMSG_MINLEN )
                                {
                                        do        {
                                                        for( u8 i=0;i<COMMSG_MINLEN;i++ )
                                                        {
                                                                dataBuf = Com4.Buf[(Com4.pRead+i)%COMBUF_MAXBUFF_SIZE];
                                                        }
                                                        if( (dataBuf[0] == 0x55)&&(dataBuf[1] == 0xAA)&&(dataBuf[COMMSG_MINLEN-1]==0x88) ) //报文开始和结束正确
                                                        {
                                                                if( GetSum((u8*)dataBuf,(u8)(COMMSG_MINLEN-2)) == dataBuf[COMMSG_MINLEN-2])  // 校验正确
                                                                {
                                                                        switch( dataBuf[2] )  // 这样的方式,需要
                                                                        {
                                                                                case 0x00:
                                                                                        break;
                                                                                case 0x01:
                                                                                        break;
                                                                                case 0x02:
                                                                                        break;
                                                                                case 0x03:
                                                                                        NVIC_SystemReset();
                                                                                        break;
                                                                        default:
                                                                                break;
                                                                        }
                                                                        Com4.pRead += COMMSG_MINLEN;
                                                                        Com4.pRead %= COMBUF_MAXBUFF_SIZE;
                                                                }
                                                                else // 报文特征和不正确
                                                                {
                                                                        Com4.pRead ++;
                                                                        Com4.pRead %= COMBUF_MAXBUFF_SIZE;
                                                                }
                                                        }
                                                        else  // 报文特征不正确,减少一位后
                                                        {
                                                                Com4.pRead ++;
                                                                Com4.pRead %= COMBUF_MAXBUFF_SIZE;
                                                        }
                                                } while(((( Com4.pWrite + COMBUF_MAXBUFF_SIZE ) - Com4.pRead ) % COMBUF_MAXBUFF_SIZE ) >= COMMSG_MINLEN );  // 仍在报文长度内继续处理
                                        }
                        }
                }
        }
}

2018-1-15 10:19:11编辑:
        本人当前这样认为:使用2M的波特率,但是单片机本身也就:72M的运行频率,加上μc/OS-Ⅲ实际上这个2M的频率也就是:每次进入中断频率太高了,所以准备采用DMA的方式(本人是没用用过DMA~所以一开始设计的时候就没有考虑用。)。

2018年1月15日12:19:09编辑:
        问题已经解决,串口接收使用了DMA的方式,这样可以减少中断频率,因为2M波特率,每秒200K次的中断,实在是太多了,现在改为40个字节一个帧,开启半传输中断,当前中断频率大约在:10K左右~,运行30min没有发现丢帧~
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
17条回答
tkggsai2008
1楼-- · 2020-01-11 20:39
 精彩回答 2  元偷偷看……
D.lovers
2楼-- · 2020-01-11 22:03
DMA处理?
ljt80158015
3楼-- · 2020-01-12 02:45
μc/OS  我们最高只做到 38400, 裸跑多大波特率都没问题

磊磊映画
4楼-- · 2020-01-12 08:16
串口接收中断和DMA属于单片机硬件中断,优先级比UCOS2运行程序优先级高
2201
5楼-- · 2020-01-12 08:33
如果方便硬件仿真或打印的话, 直接查串口错误标志位,一查你就会明白。
tkggsai2008
6楼-- · 2020-01-12 12:07
 精彩回答 2  元偷偷看……

一周热门 更多>