OpenEdv-开源电子网

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

使用原子FreeRTOS列隊歷程改寫成USART接收RTU資料,但是,每次只能收到1個byte

[复制链接]

18

主题

77

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2016-1-15
在线时间
49 小时
发表于 2021-9-1 11:38:46 | 显示全部楼层 |阅读模式
10金钱
本帖最后由 KCLin 于 2021-9-1 21:36 编辑

大家好
先說明,我是RTOS的新手,也不是資訊專業,如果用詞或是代碼錯得離譜,還請見諒

我以原子的列隊例程為基礎,以 HAL_UART_Receive_IT 做接收

寫一個在 usart6 接收 16進位 長度為 8 的 RTU 資料
例如 RTU_CMD[8]={01, 06, 10,  01,  00, 0C,  00, 00}
但是,每次中斷接收數個 byte 後就會將剩餘的BYTE拋棄

取決於波特率,波特率越小,能收到的byte就越多
例如 4800可以收到五個,

115200

115200


115200可以收到兩個
115200.png


波特率115200 連續發送4次,出現 0x1 0x6 出現四次,所以,可以推論,8 bytes 後面的 6 個bytes 都被捨棄了!


115200B.png

代碼的思路大略是使用 HAL_UART_Receive_IT 一次接收一個 BYTE,當接收完成 8 個 BYTE 後,就丟入列隊,並把 index 歸零
主要的代碼如下
  1. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  2. {
  3.         if(huart->Instance==USART1)//如果是串口1
  4.         {
  5.                 if((USART_RX_STA&0x8000)==0)//接收未完成
  6.                 {
  7.                         if(USART_RX_STA&0x4000)//接收到了0x0d
  8.                         {
  9.                                 if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始
  10.                                 else USART_RX_STA|=0x8000;        //接收完成了
  11.                         }
  12.                         else //还没收到0X0D
  13.                         {        
  14.                                 if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000;
  15.                                 else
  16.                                 {
  17.                                         USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
  18.                                         USART_RX_STA++;
  19.                                         if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收         
  20.                                 }                 
  21.                         }
  22.                 }

  23.         }
  24.       
  25.         else if (huart->Instance==USART6){

  26.                         USART6_RX_BUF[index_USART6_RX]=aRxBuffer6[0] ;
  27.                         index_USART6_RX+=1;
  28.         }
  29.         
  30. }

  31. extern QueueHandle_t USART6_remote_comm_Queue;
  32. void USART6_IRQHandler(void)                    
  33. {
  34.     u32 timeout=0;
  35.   u32 maxDelay6=0x1FFFF;
  36.     BaseType_t xHigherPriorityTaskWoken;
  37.    
  38.     HAL_UART_IRQHandler(&UART6_Handler);    //調用HAL庫中斷處理公用函數
  39.    
  40.    
  41.     timeout=0;
  42.     while (HAL_UART_GetState(&UART6_Handler)!=HAL_UART_STATE_READY)//等待就緒
  43.     {
  44.         timeout++;////超時處理
  45.         if(timeout>maxDelay6) break;        
  46.     }
  47.      
  48.     timeout=0;
  49.     while(HAL_UART_Receive_IT(&UART6_Handler,(u8 *)aRxBuffer6, RXBUFFERSIZE)!=HAL_OK)//一次處理完成之後,重新開啟中斷並設置RxXferCount為1
  50.     {
  51.         timeout++; //超時處理
  52.         if(timeout>maxDelay6) break;   
  53.     }
  54.    
  55.   printf("enter USART6_IRQHandler index_USART6_RX =%d \r\n",index_USART6_RX);
  56. //    index_USART6_RX++;
  57. //    delay_ms(1);
  58.     if((((index_USART6_RX) == 8)&& USART6_remote_comm_Queue!=NULL))  //已經接收完畢,接下來向 queue 發送數據
  59.     {
  60.         printf("RX_data :");
  61.         for(uint8_t i=0; i<8; i++){
  62.             printf("0x%x", USART6_RX_BUF[i]);
  63.         }
  64.         printf("\r\n");

  65.         index_USART6_RX =0;
  66.         xQueueSendFromISR(USART6_remote_comm_Queue,USART6_RX_BUF,&xHigherPriorityTaskWoken);//向隊列中發 送數據
  67.         memset(USART6_RX_BUF,0,USART2_REC_LEN);//清除數據接收緩衝區USART_RX_BUF,用於下一次數據接收   
  68.         portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的話進行一次任務切換
  69.         //portYIELD_FROM_ISR 用於中段的任務切換函數, portYIELD() 會強行切換任務,放棄剩餘的時間片
  70.         //xHigherPriorityTaskWoken 用來標記退出此函數是否進行任務切換,此變數由系統操作設定,用戶不必做任何設置,只須提供一個變量保存
  71.     }
  72. }

  73. void REMOTE_COMM_task(void *pvParameters){
  74.    
  75.     uint8_t data[8];
  76.     while(1){
  77.         while(xQueueReceive(USART6_remote_comm_Queue,data,100)){
  78.             printf("TASK_remote_comm : disp_data : ");
  79.             printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7] );                    
  80.             if (data[0] == 0){
  81.             mcu_comm_handle_func(data);
  82.             }
  83.         }
  84.         vTaskDelay(100);      
  85.     }
  86. }
复制代码

在USART1 ,原子的例程接收是沒有問題的
理論上,我應該也可以逐一收到8個bytes的數據
一直無法解決問題,請大神協助一下,非常感謝

附帶一個問題,因為我要與PID控制器做通訊
如果收發分別寫在兩個 task, 也會發生接收不全的問題
如果收發寫在同一個Task, 也就是發送完畢後在同一個task裡面等待接收,接收完畢後,再發出第二個資料
這樣,就可以接收到完整的資料。






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

使用道具 举报

7

主题

480

帖子

0

精华

高级会员

Rank: 4

积分
771
金钱
771
注册时间
2021-4-15
在线时间
304 小时
发表于 2021-9-1 16:24:21 | 显示全部楼层
帮顶!是想用空闲中断等方式去接受那行数据等?这种玩法没见过
日常敲键--头秃一片
回复

使用道具 举报

2

主题

592

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1458
金钱
1458
注册时间
2019-7-28
在线时间
137 小时
发表于 2021-9-1 17:20:29 | 显示全部楼层
帮顶   
回复

使用道具 举报

13

主题

644

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1960
金钱
1960
注册时间
2021-4-16
在线时间
500 小时
发表于 2021-9-1 17:21:04 | 显示全部楼层
帮顶     
回复

使用道具 举报

18

主题

77

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2016-1-15
在线时间
49 小时
 楼主| 发表于 2021-9-1 21:33:05 | 显示全部楼层
日渐秃兀 发表于 2021-9-1 16:24
帮顶!是想用空闲中断等方式去接受那行数据等?这种玩法没见过

這。。。原子給的例程就是這樣的結構
usart1 就是原子的例程我沒改過
我只是把原子例程中判斷接收結束的條件改成接收8個byte就結束
但是,我的卻無法正確動作

我不知道這是不是利用空閒等中斷
我的理解不知對不對
當外部資料送到,中斷無論如何都會發生
也或許您的看法是對的
但是,因為不知哪時外部資料會送到
給一個task去等中斷,和利用空閒等中斷
在"等中斷"意義似乎是一樣的?!

無論如何,感謝您的建議!
回复

使用道具 举报

120

主题

7877

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2021-9-5 22:12:46 | 显示全部楼层
HAL_UART_Receive_IT(&UART6_Handler,(u8 *)aRxBuffer6, RXBUFFERSIZE)!=HAL_OK这样写确定对了???
回复

使用道具 举报

70

主题

6697

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
12687
金钱
12687
注册时间
2012-11-26
在线时间
3710 小时
发表于 2021-9-6 09:49:47 | 显示全部楼层
串口接收不要用原子的例程架构,那个只是用来演示的,实际项目意义不大  
学无止境
回复

使用道具 举报

18

主题

77

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2016-1-15
在线时间
49 小时
 楼主| 发表于 2021-9-6 10:09:59 | 显示全部楼层
八度空间 发表于 2021-9-5 22:12
HAL_UART_Receive_IT(&UART6_Handler,(u8 *)aRxBuffer6, RXBUFFERSIZE)!=HAL_OK这样写确定对了???

不就和原子的一樣?
回复

使用道具 举报

18

主题

77

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2016-1-15
在线时间
49 小时
 楼主| 发表于 2021-9-6 10:11:39 | 显示全部楼层
jermy_z 发表于 2021-9-6 09:49
串口接收不要用原子的例程架构,那个只是用来演示的,实际项目意义不大

我想,原子的能跑,沒有由用在其他例子不能跑呀!
不過現在考愈改DMA就是了!

回复

使用道具 举报

70

主题

6697

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
12687
金钱
12687
注册时间
2012-11-26
在线时间
3710 小时
发表于 2021-9-6 10:29:24 | 显示全部楼层
KCLin 发表于 2021-9-6 10:11
我想,原子的能跑,沒有由用在其他例子不能跑呀!
不過現在考愈改DMA就是了!

嗯   DMA+空闲中断
学无止境
回复

使用道具 举报

70

主题

6697

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
12687
金钱
12687
注册时间
2012-11-26
在线时间
3710 小时
发表于 2021-9-6 10:30:44 | 显示全部楼层
KCLin 发表于 2021-9-6 10:11
我想,原子的能跑,沒有由用在其他例子不能跑呀!
不過現在考愈改DMA就是了!

另外freertos的消息队列,直接0xffffffff一直阻塞就行。没必要弄个超时,然后还在那轮询
学无止境
回复

使用道具 举报

70

主题

6697

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
12687
金钱
12687
注册时间
2012-11-26
在线时间
3710 小时
发表于 2021-9-6 10:31:43 | 显示全部楼层
KCLin 发表于 2021-9-6 10:11
我想,原子的能跑,沒有由用在其他例子不能跑呀!
不過現在考愈改DMA就是了!

串口的中断处理流程,还是按照标准库来。不要用HAL库的接收模式,会把自己搞死
学无止境
回复

使用道具 举报

18

主题

77

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2016-1-15
在线时间
49 小时
 楼主| 发表于 2021-9-6 16:22:42 | 显示全部楼层
jermy_z 发表于 2021-9-6 10:31
串口的中断处理流程,还是按照标准库来。不要用HAL库的接收模式,会把自己搞死

恩,謝謝您,真的很感謝(其實在我周圍很難遇到寫STM32的)
USART 暫時用 1by1 的方式發出,可以先撐著用
不過我現在被 CubeMX 6 +FreeRTOS+SD+FATFS 搞死了!
大神可以救我
大概是這樣
f_mount(&fs, "0:", 0) ; 可以 mount 成功,但是不能 open 返回錯誤碼 3 FR_NOT_READY,
f_mount(&fs, "0:", 1) ; 不能 mount 成功, 返回錯誤碼 3 FR_NOT_READY,
SD, FreeRTOS 全部都是 CubeMX 生成,SD 開啟 DMA
據我所知, CubeMX 6 已經修正相關回調函數為空的問題!
不加入 FreeRTOS 到是很正常
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-22 18:10

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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