OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2080|回复: 10

请问UCOS II中串口收到的数据如何发送给主任务?

[复制链接]

18

主题

34

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2019-5-29
在线时间
148 小时
发表于 2022-8-12 10:47:49 | 显示全部楼层 |阅读模式


现有系统对串口数据的处理方式如下,具体代码在最后面。
1、系统串口每隔100ms左右会收到50个BYTE的数据,目前是定义了一个200BYTE的全局数组usart_rxbuf和一个全局变量作为接收标志位rec_flag,每次串口有收到数据就会往里面存,并且标志位置2,在主任务较忙的情况下,最多可以缓存四块数据(每块数据50个BYTE,BYTE0如果等于0xff,则代表这一块50BYTE数据已经被处理过了,可以往里面存入有效数据)。
2、主任务在while循环里面不断判断rec_flag标志位,如果等于2,则把usart_rxbuf数据中有效的数据赋给内部缓存,并且把对应数据块的BYTE0给置成0xff,这样串口中断里面判断到0xff,就可以继续存入。之后就是对收到的串口数据进行处理。
3、主任务比较空闲的时候,基本上都是串口存入数据块1,然后主任务处理数据块1,串口存入数据块1.....依此流程循环下去


系统在跑了几万个循环后会无缘无故卡死了,系统完全停止,串口调试信息也不输出,也不是进入数组溢出等HardFault_Handler错误,目前比较怀疑是usart_rxbuf全局数组在两个任务里面都有读写,会不会是usart_rxbuf数组在主任务里面正在被读取,这时串口中断来了,又进入串口中断去读写usart_rxbuf全局数组,就导致系统无故卡死了。哪位大哥有什么办法可以处理掉这种同时读写的情况的,这样轻微改动后解决这个问题最好。
如果上面这种方式铁定不行,请问大伙在UCOS II系统中都是怎么处理串口接收到的数据的,有例程最好,谢谢!




/********************串口中断处理函数*******************************/
volatile u8 usart_rxbuf[200];
volatile u8 rec_flag=0;
volatile u8 USART2_RX_BUF[100];                                 //接收缓冲

void USART2_IRQHandler(void)
{
        u8 res;
        u8 i=0,j=0;
        u8 temp=0;
        u16 crc_check=0;        
        OSIntEnter();   
        if(USART2->SR&(1<<5))//接收到数据
        {         
                res=USART2->DR;         
                if((res==0xAA)&&(start_rev==0))
                {
                        rev_num=0;
                        start_rev=1;
                }
                if(start_rev==1)
                {
                        USART2_RX_BUF[rev_num]=res;
                        rev_num++;
                        if(rev_num>63)
                        {
                                if(USART2_RX_BUF[1]==0x55)
                                {
                                        if(USART2_RX_BUF[3]==0x5C)        //采集模块数据上报
                                        {
                                                crc_check=cal_crc(&USART2_RX_BUF[0],63);
                                                temp=crc_check&0x00ff;
                                                if(temp==USART2_RX_BUF[63])        //必须校验和正确  才会执行写入动作
                                                {               
                                                        rec_flag=2;                 
                                                        UART2_SEND(0xAA);               
                                                        UART2_SEND(0x55);
                                                        UART2_SEND(0x02);
                                                        UART2_SEND(0x5D);                //数据上报接收应答 在串口中断里面发送串口数据会不会也会导致系统卡死?
                                                        UART2_SEND(0xFF);                                

                                                        for(j=0;j<4;j++)
                                                        {
                                                                temp=j*50;
                                                                if(usart_rxbuf[temp]==0xff)        //0xff代表本段没数据  可以存入
                                                                {
                                                                        for(i=5;i<45;i++)
                                                                                usart_rxbuf[4+i+temp]=USART2_RX_BUF;        

                                                                        usart_rxbuf[temp]=USART2_RX_BUF[52];                //点数
                                                                        usart_rxbuf[temp+1]=USART2_RX_BUF[53];
                                                                        usart_rxbuf[temp+2]=USART2_RX_BUF[45];                //周期
                                                                        usart_rxbuf[temp+3]=USART2_RX_BUF[46];
                                                                        usart_rxbuf[temp+4]=USART2_RX_BUF[47];        
                                                                        usart_rxbuf[temp+5]=USART2_RX_BUF[54];                //范围1~4        

                                                                        usart_rxbuf[temp+6]=USART2_RX_BUF[57];                //电池电量高位
                                                                        usart_rxbuf[temp+7]=USART2_RX_BUF[58];                //电池电量低位
                                                                        usart_rxbuf[temp+8]=USART2_RX_BUF[59];               
                                                                        break;
                                                                }
                                                        }
                                                }
                                                else
                                                {
                                                        errtime+=1;                                                                                                               
                                                }
                                        }                                       
                                        start_rev=0;
                                        rev_num=0;                                       
                                }                                
                                else
                                {
                                        start_rev=0;
                                        rev_num=0;
                                }
                        }
                }
        }                                 
        OSIntExit();  
}



/************主任务程序*****************/
while(1)
{
        if(rec_flag==2)
        {
                rec_flag=0;
               
                for(i=0;i<4;i++)
                {
                        temp=i*50;
                        if(usart_rxbuf[temp]!=0xff)        //代表该位置存在数据
                        {
                                //INTX_DISABLE();
                                for(j=0;j<50;j++)        
                                {
                                        //usart_rxbuffer数组是while循环内部定义的局部变量
                                        usart_rxbuffer[j]=usart_rxbuf[temp+j];                                       
                                }
                                usart_rxbuf[temp]=0xff;        //该条数据处理完成后第一个BYTE置FF  代表数据已处理过了
                                //INTX_ENABLE();

                                //后面是对收到的数据进行处理和显示

                        }
                }
        }
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

113

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2509
金钱
2509
注册时间
2019-10-18
在线时间
397 小时
发表于 2022-8-12 18:12:41 | 显示全部楼层
这种使用信号量啊.有了系统就要使用系统的api函数来操作.全局变量又读又写的肯定不成.夜路走多了总会碰到鬼的.除非是原子操作.读改写的不能有.一定要用全局数组那也可以用互斥信号量来保护.把全局数组当作一个资源.
回复 支持 反对

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2022-8-15 10:08:11 | 显示全部楼层
老兄啊,你在uCOS II系统中还在用前后台编程模式进行编程呀!
  
          1、对于通信用等待信号量触发报文分析
                不要使用在任务中判断标识的方法呀
                       while(1)
                      {
                           if(rec_flag==2)    ---> 在任务中判断标识
                           {
             2、对于通信缓冲区中的数据(在串口中断中写,在任务中读),可将其视作资源,
                    为防止原子性,可以使用下面的方式
                    (1)、在任务中使用关中断
                                  例如:
                                           关中断
                                           将通信缓冲区中的数据  送到另外一个临时缓冲区
                                           开中断
                                           以下代码使用临时缓冲区进行处理
                     
                             
回复 支持 反对

使用道具 举报

18

主题

34

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2019-5-29
在线时间
148 小时
 楼主| 发表于 2022-8-15 14:08:11 | 显示全部楼层
霸王猫 发表于 2022-8-15 10:08
老兄啊,你在uCOS II系统中还在用前后台编程模式进行编程呀!
  
          1、对于通信用等待信号量触发 ...

大神您好
1、请问在主任务中判断标识会导致什么问题啊?
2、如果在主任务中关串口中断,我怕刚好在关中断时,串口收到数据,这时会不会就被漏掉了
回复 支持 反对

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2022-8-16 14:47:44 | 显示全部楼层
本帖最后由 霸王猫 于 2022-8-16 14:51 编辑
HXHNTTXLLA1121 发表于 2022-8-15 14:08
大神您好
1、请问在主任务中判断标识会导致什么问题啊?
2、如果在主任务中关串口中断,我怕刚好在关中 ...



   使用嵌入式操作系统编程
        一般在串口通信中断中使用:
                1、发送信号量
                2、发送消息队列
           唤醒【串口处理任务】

        【串口处理任务】任务优先级设置的比较高,确保中断一结束,就可以立即切换到【串口处理任务】中执行。

       请问在主任务中判断标识会导致什么问题啊?
                判断标识无法确保  【串口处理任务】和串口中断同步运行,即:串口中断一结束,无法保证立即切换到【串口处理任务】中进行报文解析工作


              用信号量和消息队列, 相当于线上挂一个铃铛,当线一动,铃铛就响。
              你用标识就无法保证。


        如果在主任务中关串口中断,我怕刚好在关中断时,串口收到数据,这时会不会就被漏掉了

               不会漏掉滴。单片机硬件串口都有缓存。

               为防止长时间关闭中断,一般使用拍照功能减少关中断占用时间。
                什么是拍照功能?

                     1、关中断
                     2、把串口中断缓冲区的数据拷贝到【临时缓冲区】   --->  这就是拍照
                     3、开中断
                     4、解析报文。                           使用的是【临时缓冲区】中存储的数据进行解析,而不是串口中断缓冲区的数据进行解析哈!   
                      这就是拍照功能的精髓,又不长时间关闭中断,又防止同时读写共享资源,一举两得哈。








回复 支持 反对

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2022-8-16 15:09:34 | 显示全部楼层
我建议你学习一下MODBUS协议和STM32F103的串口通过空中断使用DMA接收不定长报文方面的知识

    1、根据你的描述,你100毫秒收到一帧报文

            完全可以根据MODBUS协议的要求,设置一个超时定时器,超时时间=0.5毫秒
              当收到一个字符,就重新初始化并开启超时定时器,当超时定时器溢出,就表示一帧报文接收完毕,
   就可以在定时器溢出中断中发送信号量唤醒串口接收任务,同时关闭超时定时器
         没有必须像你的程序搞得那么复杂,定义4个区域,来回倒腾。

   2、STM32F103的串口通过空中断使用DMA接收不定长报文

           也是根据上述原理。
回复 支持 反对

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2022-8-16 15:20:53 | 显示全部楼层
1、串口中断
  {
                if (接收中断)
                {
                      1、接收字符
                      2、T1定时器关闭
                      3、T1定时器初值=(0.5)毫秒
                      4、T1定时器开启
                }

   }


2、T1溢出中断
{
        T1定时器关闭
         发送信号量唤醒串口处理任务
}


    0.5毫秒可以根据通信波特率改变,MODBUS协议规定,当超时时间为3.5字符时间。  不财的波特率3.5字符时间不同,可以计出来

                对于波特率9600 bps  
                     1秒=9600位   假如数据位8位,起始位1位,停止位=1位  ,也就是说  1秒钟传输960字节

                          1000毫秒                        X
                         ------------         =   ----------------
                               960字节                 3.5


                     X=3.5*1000/960=3500/960=3.645毫秒

               当9600BPS时,超时定时器可以设置为4毫秒
              当38400BSP时,超时定时器可以设置为1毫秒

回复 支持 反对

使用道具 举报

18

主题

34

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2019-5-29
在线时间
148 小时
 楼主| 发表于 2022-8-21 15:06:27 | 显示全部楼层
霸王猫 发表于 2022-8-16 14:47
使用嵌入式操作系统编程
        一般在串口通信中断中使用:
                1、发送信号量


大神您好,您说在串口中断里面置位标志位,无法保证中断结束后立即切换到串口处理任务里面去解析,但是串口中断里面不是不能发送信号量吗?

而且我的串口处理任务里面还有很多其它函数(触摸检测、界面修改等等),没办法卡在某个地方一直等待信号量,请问这样得怎么操作比较合理啊。
回复 支持 反对

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2022-8-25 11:15:07 | 显示全部楼层
HXHNTTXLLA1121 发表于 2022-8-21 15:06
大神您好,您说在串口中断里面置位标志位,无法保证中断结束后立即切换到串口处理任务里面去解析,但是 ...

用消息队列呀

     假如:

              定义消息队列格式如下:

                  msg[0] = 功能码
                  msg[1] = 消息队列长度
                  msg[2] = 消息队列内容

          一、按键任务消息
                   msg[0] = 1   ---> 表示按键任务发送的消息
                  msg[1] = 1
                  msg[2] = 2

          二、GUI消息
                   msg[0] = 2   ---> 表示GUI坐标
                  msg[1] = 2
                  msg[2] = 3,5


         三、AD采集任务消息
                 msg[0] = 3   ---> 表示AD采集任务发送的消息
                  msg[1] = 2
                  msg[2] = 3,5



     这样串口接收任务就可以只需要等待一个消息队列,当接收到消息队列,取出功能码,就知道是哪个任务给它发送的消息啦!




回复 支持 反对

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2022-8-25 11:22:41 | 显示全部楼层
HXHNTTXLLA1121 发表于 2022-8-21 15:06
大神您好,您说在串口中断里面置位标志位,无法保证中断结束后立即切换到串口处理任务里面去解析,但是 ...

谁告诉你

   串口中断里面不是不能发送信号量?


      1、任务里可以发送信号量或消息队列
      2、中断里也可以发送信号量或消息队列
      3、任务里使用的是任务级的信号量或消息队列API函数
      4、中断里使用的是中断级的信号量或消息队列API函数
回复 支持 反对

使用道具 举报

0

主题

441

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2911
金钱
2911
注册时间
2016-3-19
在线时间
753 小时
发表于 2022-8-25 13:25:12 | 显示全部楼层
霸王猫 发表于 2022-8-25 11:15
用消息队列呀

     假如:

学习了

解释得很清晰

谢谢分享
Nothing is impossible
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-11 02:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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