OpenEdv-开源电子网

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

FreeRTOS任务处于就绪态但一直没有被调度运行是怎么回事?

[复制链接]

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
发表于 2020-5-19 11:23:17 | 显示全部楼层 |阅读模式
5金钱
本帖最后由 ZhuMX 于 2020-5-19 11:33 编辑

如题,程序中有一个CAN总线发送任务(任务名为vCanTxTask),优先级最高(设置的10),通过读取发送队列中的数据,将数据发送至CAN总线。读取方式为调用xQueueReceive,设置了阻塞时间(1000ms);其他任务调用vCanTx()函数将数据发送至CAN发送队列,vCanTx函数中通过__get_CONTROL()返回值判断该函数是否处于中断模式,从而调用xQueueSend或xQueueSendFromISR函数;

测试时程序只是周期性发送1个TPDO和CANOpen心跳,周期均是3s。
测试时发现刚开始都很正常的运行,但是过了几十分钟(有时几个小时)就不再发送CAN帧了,调试后发现以下信息:
1、查询CAN控制器的各个寄存器,发现CAN控制器并没有任何错误产生。
2、在vCanTxTask中多处设置断点,发现程序不再运行该任务,但是其他任务都很正常的运行。
3、在另一个任务中查询vCanTxTask任务状态,其状态始终处于eReady就绪状态,且堆栈也没有溢出。
4、其他任务发送数据至CAN发送队列的结果均是入队失败,推测应该队列已经满了,vCanTxTask没有运行所以一直没有数据出队。
综上现象,现在很疑惑为什么任务明明就绪了却一直没有被调度运行?且该任务优先级是最高的,希望各位坛友能帮助分析下,不胜感激!
下面分别为vCanTxTask任务函数,vCanTx函数的原码,以及另一个任务vBoardLedTask(用于查询vCanTxTask状态)
  1. /*****************************************************************
  2. * 函数名称 : vCanTxTask
  3. * 功    能 : 将CAN发送队列中的数据发送至CAN总线
  4. * 参    数 : 无
  5. * 返 回 值 : 无
  6. ******************************************************************/
  7. void vCanTxTask(void *pvPara)
  8. {
  9.         static CanTxFrameTypeDef can_tx;
  10.         static uint32_t uxHighWaterMarkCan;
  11.     static uint32_t txerr;
  12.     BaseType_t r;
  13.     uint8_t txcnt=0;
  14.     eTaskState TaskState;
  15.    
  16.         while (1)
  17.         {

  18.         DEBUG_PRINTF(" CAN Transmit Task Start! \r\n");
  19.         r = xQueueReceive(CanTxQueue, &can_tx, pdMS_TO_TICKS(1000));
  20.         DEBUG_PRINTF(" CAN Transmit Task Wait End! \r\n");
  21.         if ( r )
  22.         {
  23.             DEBUG_PRINTF(" CAN Transmit Bsp Strat!  \r\n");
  24.             txcnt = vBspCanTx1(&can_tx);   
  25.             if(txcnt>=64)
  26.             {
  27.                 xQueueReset(CanTxQueue);
  28.                 DEBUG_PRINTF(" CAN Retransmit Cnt>64 \r\n\r\n");
  29.             }
  30.             else
  31.             {
  32.                 DEBUG_PRINTF(" CAN Transmit OK! \r\n\r\n");
  33.             }
  34.         }
  35.         //vCanErrorProcess();
  36.         TaskState=eTaskGetState(CanTxTaskHandle);
  37.         switch((int)TaskState)
  38.         {
  39.             case eRunning:
  40.                 DEBUG_PRINTF(" CANTxTask State ==  eRunning \r\n");
  41.                 break;
  42.             case eReady:
  43.                 DEBUG_PRINTF(" CANTxTask State ==  eReady \r\n");
  44.                 break;
  45.             case eSuspended:
  46.                 DEBUG_PRINTF(" CANTxTask State ==  eSuspended \r\n");
  47.                 break;
  48.             case eDeleted:
  49.                 DEBUG_PRINTF(" CANTxTask State ==  eDeleted \r\n");
  50.                 break;
  51.             case eInvalid:
  52.                 DEBUG_PRINTF(" CANTxTask State ==  eInvalid \r\n");
  53.                 break;
  54.         }
  55.                 uxHighWaterMarkCan = uxTaskGetStackHighWaterMark(CanTxTaskHandle);
  56.         
  57.         //vTaskDelay(pdMS_TO_TICKS(CAN_TASK_PERIOD_MS));

  58.                 (void)uxHighWaterMarkCan;
  59.         }
  60. }
复制代码
  1. /*****************************************************************
  2. * 函数名称 : vCanTx
  3. * 功    能 : 将发送帧写入CAN发送队列
  4. * 参    数 : ptx-CAN发送帧
  5. * 返 回 值 : 无
  6. ******************************************************************/
  7. extern struct sExtRunType sExtRun;
  8. void vCanTx(CanTxFrameTypeDef *ptx)
  9. {
  10.     BaseType_t r;
  11.     BaseType_t xHigherPriorityTaskWoken;
  12.     CanRxFrameTypeDef rx;

  13.     if(sExtRun.eExtMode!=eNoConnect)
  14.     {
  15.         rx.RXHeader.IDE = ptx->TxHeader.IDE;
  16.         rx.RXHeader.ExtId = ptx->TxHeader.ExtId;
  17.         rx.RXHeader.StdId = ptx->TxHeader.StdId;
  18.         rx.RXHeader.DLC = ptx->TxHeader.DLC;
  19.         rx.RXHeader.RTR =  ptx->TxHeader.RTR;
  20.         for(uint8_t i=0;i<ptx->TxHeader.DLC;i++)
  21.             rx.Data[i] = ptx->Data[i];
  22.         
  23.     }

  24.     /* 判断是否在执行中断 */
  25.     if(0 == __get_CONTROL())
  26.     {
  27.         r = xQueueSendFromISR(CanTxQueue, ptx, &xHigherPriorityTaskWoken);
  28.         if(sExtRun.eExtMode!=eNoConnect && sExtRun.ExtCanRxQueue!=NULL)
  29.             r = xQueueSendFromISR(sExtRun.ExtCanRxQueue, &rx, &xHigherPriorityTaskWoken);
  30.         portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
  31.     }
  32.     else
  33.     {
  34.         r = xQueueSend(CanTxQueue, ptx, pdMS_TO_TICKS(4));//等待时间不能太长,以免影响20ms周期的读取
  35.         if(sExtRun.eExtMode!=eNoConnect && sExtRun.ExtCanRxQueue!=NULL)
  36.             r = xQueueSend(sExtRun.ExtCanRxQueue, &rx, pdMS_TO_TICKS(4));
  37.     }

  38.         if ( r )
  39.         {
  40.         }
  41.     else
  42.     {
  43.         DEBUG_PRINTF("Send CanTxQueue Failed ! return=%d\r\n",r);
  44.     }
  45. }
复制代码
  1. void vBoardLedTask(void*para)
  2. {
  3.    
  4.     static eTaskState CanTaskState;
  5.    
  6.     while(1)
  7.     {
  8.         CanTaskState=eTaskGetState(CanTxTaskHandle);
  9.         switch((int)CanTaskState)
  10.         {
  11.             case eRunning:
  12.                 DEBUG_PRINTF(" CANTxTask State ==  eRunning \r\n");
  13.                 break;
  14.             case eReady:
  15.                 DEBUG_PRINTF(" CANTxTask State ==  eReady \r\n");
  16.                 break;
  17.             case eSuspended:
  18.                 DEBUG_PRINTF(" CANTxTask State ==  eSuspended \r\n");
  19.                 break;
  20.             case eDeleted:
  21.                 DEBUG_PRINTF(" CANTxTask State ==  eDeleted \r\n");
  22.                 break;
  23.             case eInvalid:
  24.                 DEBUG_PRINTF(" CANTxTask State ==  eInvalid \r\n");
  25.                 break;
  26.             case eBlocked:
  27.                 DEBUG_PRINTF(" CANTxTask State ==  eBlocked \r\n");
  28.                 break;
  29.         }
  30.         
  31.         if(hcan1.ErrorCode == HAL_CAN_ERROR_NONE)
  32.         {
  33.             io_pin_write(PIN_LED_TST,0);
  34.             vTaskDelay(pdMS_TO_TICKS(10));
  35.             io_pin_write(PIN_LED_TST,1);
  36.         }
  37.         else
  38.         {
  39.             io_pin_write(PIN_LED_TST,0);
  40.             vTaskDelay(pdMS_TO_TICKS(300));
  41.             io_pin_write(PIN_LED_TST,1);
  42.             HAL_CAN_ResetError(&hcan1);            
  43.         }
  44.         
  45.         
  46.         
  47.         vTaskDelay( pdMS_TO_TICKS(LED_TASK_PERIOD_MS) );
  48.     }
  49.    
  50. }
复制代码







最佳答案

查看完整内容[请看2#楼]

FreeRTOS一般常用的写法如下: 1、中断服务程序中发送信号量或消息队列 2、一个高优先级的普通任务接收中断服务程序发送的信号量或消息队列 3、多个任务给另外一个任务发送消息队列需要规划自定义协议 假设任务1、任务2、任务3分别给任务4发送消息队列,需要规划消息队列协议 假定:MSG[0]= 谁给任务4发送的消息队列 = 1--- 代表任务1给任务4发 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-5-19 11:23:18 | 显示全部楼层
本帖最后由 霸王猫 于 2020-5-20 12:03 编辑

FreeRTOS一般常用的写法如下:

   1、中断服务程序中发送信号量或消息队列
   2、一个高优先级的普通任务接收中断服务程序发送的信号量或消息队列
   3、多个任务给另外一个任务发送消息队列需要规划自定义协议
             假设任务1、任务2、任务3分别给任务4发送消息队列,需要规划消息队列协议
               假定:MSG[0]= 谁给任务4发送的消息队列
                                   = 1--- 代表任务1给任务4发送消息队列
                                   = 2--- 代表任务2给任务4发送消息队列
                                   = 3--- 代表任务3给任务4发送消息队列
                      MSG[1]=消息队列类型 (不同的类型可以接收不同的数据和长度)
                                   = 1 ---> 代表任务4接收AI数据
                                   = 2---> 代表任务4接收AO数据
                                   = 3---> 代表任务4接收DO数据
                       MSG[2]---MSG[255]=消息队列中存储的数据
           



   下面的程序说明如下:

               DI1_Task任务每隔100毫秒给MODBUS_Task任务发送DI开关量信号 (DI1,DI2)
               DI2_Task任务每隔100毫秒给MODBUS_Task任务发送DI开关量信号(DI3,DI4)
               SD2405ALPI_Task每隔1秒给MODBUS_Task任务发送时钟(年、月、日、时、分、秒)
            
               MODBUS_Task任务收到USART1的上位机请求命令,把DI1,DI2,DI3,DI4,年、月、日、时、分、秒通过MODBUS协议传输给上位机。
               USART1中断服务程序通过发送信号量唤醒 MODBUS_Task任务。
               DI1_Task任务、DI2_Task任务、SD2405ALPI_Task给MODBUS_Task任务发送消息队列时,规划了自定义协议。
               MODBUS_Task任务解析DI1_Task任务、DI2_Task任务、SD2405ALPI_Task发送的消息队列数据时,也使用了规划了自定义协议



  1. //DMA中断方式
  2. void USART1_IRQHandler(void)
  3. {
  4.         uint16_t ch;
  5.         BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  6.         
  7.         
  8.         if (USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
  9.         {               
  10.                 USART_ClearITPendingBit(USART1 , USART_IT_IDLE);        //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。
  11.                 ch =  USART_ReceiveData(USART1);                                        //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。                                
  12.                 DMA_Cmd(DMA1_Channel5 , DISABLE);                                         //关闭DMA,防止处理其间有数据
  13.                 DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_HT5 | DMA1_FLAG_TE5);
  14.                 ch = USART1_DMA_RX_BUFFER_MAX_LENGTH - DMA_GetCurrDataCounter(DMA1_Channel5);
  15.                 if (ch > 0)
  16.                 {
  17.                
  18.                         MB_USART1.receCount        = ch;
  19.                         memcpy(MB_USART1.mscomm_buffer , USART1_DMA_RX_Buffer , MB_USART1.receCount);                        
  20.                 }
  21.                 DMA_SetCurrDataCounter(DMA1_Channel5 , USART1_DMA_RX_BUFFER_MAX_LENGTH);
  22.                 DMA_Cmd(DMA1_Channel5, ENABLE);        
  23.                
  24.                 xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);//发送同步信号
  25.                 //如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行
  26.                 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  27.                
  28.         }
  29.         
  30.         else if (USART_GetITStatus(USART1,USART_IT_TC)!= RESET)
  31.         {
  32.                 USART_ClearITPendingBit(USART1, USART_IT_TC);                                

  33.                 DMA_ClearFlag(DMA1_FLAG_GL4 | DMA1_FLAG_TC4 | DMA1_FLAG_HT4 | DMA1_FLAG_TE4);
  34.                 DMA_SetCurrDataCounter(DMA1_Channel4 , 0);
  35.         }        
  36. }



  37. void DI2_Task(void *pvParameters)
  38. {
  39.         const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );        
  40.         BOOL DI2_1 = FALSE;
  41.         BOOL DI2_2 = FALSE;        
  42.         uint8_t di21_array[2];
  43.         uint8_t di22_array[2];
  44.         uint8_t Buffer[10];
  45.         
  46.                
  47.     while(1)
  48.     {
  49.                 //第一次采集:采集行程2A和行程2B
  50.                 di21_array[0] = GPIO_DI2_1();
  51.                 di22_array[0] = GPIO_DI2_2();               
  52.                 vTaskDelay(20 / portTICK_RATE_MS);
  53.                 //第二次采集:采集行程2A和行程2B
  54.                 di21_array[1] = GPIO_DI2_1();
  55.                 di22_array[1] = GPIO_DI2_2();               
  56.                                 
  57.                 if ((di21_array[0] == di21_array[1]) && (di22_array[0] == di22_array[1]))
  58.                 {        
  59.                         DI2_1 = (di21_array[0] ? TRUE : FALSE);
  60.                         DI2_2 = (di22_array[0] ? TRUE : FALSE);
  61.                 }        

  62.                 Buffer[0] = 4;        //Func
  63.                 Buffer[1] = DI2_1;
  64.                 Buffer[2] = DI2_2;
  65.                
  66.         if( xQueueSend(xQueue, (void *) &Buffer , xTicksToWait) != pdPASS )
  67.                 {
  68.                          //发送失败,即使等待了10个时钟节拍
  69.                 }
  70.                 else
  71.                 {
  72.                         // 发送成功
  73.                 }                                       
  74.                 vTaskDelay(100 / portTICK_RATE_MS);               
  75.     }
  76. }



  77. void DI1_Task(void *pvParameters)
  78. {
  79.         const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );        
  80.         BOOL DI1_1 = FALSE;
  81.         BOOL DI1_2 = FALSE;        
  82.         uint8_t di11_array[2];
  83.         uint8_t di12_array[2];        
  84.         uint8_t Buffer[10];
  85.         
  86.         
  87.     while(1)
  88.     {
  89.                 //第一次采集:采集行程1A和行程1B
  90.                 di11_array[0] = GPIO_DI1_1();
  91.                 di12_array[0] = GPIO_DI1_2();               
  92.                 vTaskDelay(20 / portTICK_RATE_MS);
  93.                 //第二次采集:采集行程1A和行程1B
  94.                 di11_array[1] = GPIO_DI1_1();
  95.                 di12_array[1] = GPIO_DI1_2();        
  96.                                 
  97.                 if ((di11_array[0] == di11_array[1]) && (di12_array[0] == di12_array[1]))
  98.                 {        
  99.                         DI1_1 = (di11_array[0] ? TRUE : FALSE);
  100.                         DI1_2 = (di12_array[0] ? TRUE : FALSE);        
  101.                 }                                


  102.                 Buffer[0] = 3;        //Func
  103.                 Buffer[1] = DI1_1;
  104.                 Buffer[2] = DI1_2;
  105.                
  106.         if( xQueueSend(xQueue, (void *) &Buffer , xTicksToWait) != pdPASS )
  107.                 {
  108.                          //发送失败,即使等待了10个时钟节拍
  109.                 }
  110.                 else
  111.                 {
  112.                         // 发送成功
  113.                 }                        
  114.                 vTaskDelay(100 / portTICK_RATE_MS);      
  115.     }
  116. }



  117. void SD2405ALPI_Task(void *pvParameters)
  118. {        
  119.         const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );        
  120.         uint8_t Buffer[10];
  121.         CLOCK_Type Clock;
  122.         


  123.         bsp_InitSD2405();
  124.         
  125.     while(1)
  126.     {        
  127.                 SD2405_I2CReadTime(&Clock.second , &Clock.minute , &Clock.hour , &Clock.week , &Clock.day , &Clock.month , &Clock.year);
  128.                

  129.                 Buffer[0] = 2;        //Func
  130.                 Buffer[1] = Clock.year;
  131.                 Buffer[2] = Clock.month;
  132.                 Buffer[3] = Clock.day;
  133.                 Buffer[4] = Clock.hour;
  134.                 Buffer[5] = Clock.minute;
  135.                 Buffer[6] = Clock.second;
  136.                 Buffer[7] = Clock.week;
  137.                
  138.         if( xQueueSend(xQueue, (void *) &Buffer , xTicksToWait) != pdPASS )
  139.                 {
  140.                          //发送失败,即使等待了10个时钟节拍
  141.                 }
  142.                 else
  143.                 {
  144.                         // 发送成功
  145.                 }                                
  146.         vTaskDelay(1000 / portTICK_RATE_MS);        
  147.     }
  148. }



  149. void MODBUS_Task(void *pvParameters)
  150. {
  151.         BaseType_t xResult;
  152.         BaseType_t xStatus;        
  153.         const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
  154.         uint8_t Buffer[10];
  155.         uint8_t Over = 0x00;
  156.         
  157.         
  158.         USART1_Configuration();
  159.         USART1_DMA_Tx_Configuration();
  160.         USART1_DMA_Rx_Configuration();        
  161.     while(1)
  162.     {        
  163.                 xResult = xSemaphoreTake(xSemaphore, portMAX_DELAY);
  164.                 if(xResult == pdTRUE)
  165.                 {

  166.                                 while (1)
  167.                                 {
  168.                                         xStatus = xQueueReceive( xQueue, &Buffer, xTicksToWait );
  169.                                         if( xStatus == pdPASS )
  170.                                         {                        
  171.                                                 switch (Buffer[0])
  172.                                                 {
  173.                                                         case 2:
  174.                                                                 Over |= 0x01;        //bit0=1,表示收到SD2405ALPI_Task任务的消息队列数据
  175.                                                                 MODBUS_Clock.year = Buffer[1];
  176.                                                                 MODBUS_Clock.month = Buffer[2];
  177.                                                                 MODBUS_Clock.day = Buffer[3];
  178.                                                                 MODBUS_Clock.hour = Buffer[4];
  179.                                                                 MODBUS_Clock.minute = Buffer[5];
  180.                                                                 MODBUS_Clock.second = Buffer[6];
  181.                                                                 MODBUS_Clock.week = Buffer[7];
  182.                                                                 break;
  183.                                                         case 3:
  184.                                                                 Over |= 0x02;        //bit1=1,表示收到DI1_Task任务的消息队列数据
  185.                                                                 MODBUS_DI1_1 = Buffer[1];
  186.                                                                 MODBUS_DI1_2 = Buffer[2];
  187.                                                                 break;
  188.                                                         case 4:
  189.                                                                 Over |= 0x04;        //bit2=1,表示收到DI2_Task任务的消息队列数据
  190.                                                                 MODBUS_DI2_1 = Buffer[1];
  191.                                                                 MODBUS_DI2_2 = Buffer[2];                                                        
  192.                                                                 break;
  193.                                                 }//switch (Buffer[0])
  194.                                        
  195.                                                 if (Over == 0x07)                //bit0=1,bit1=1,bit2=1,表示3个任务的消息队列数据都已经收到
  196.                                                 {
  197.                                                         Over = 0x00;
  198.                                                         USART1_Modbus_Slave_APP();
  199.                                                         break;
  200.                                                 }
  201.                                         }
  202.                                 }//if( xStatus == pdPASS )
  203.                         //}//if( xQueue != NULL )
  204.                 }//if(xResult == pdTRUE)
  205.     }//while(1)
  206. }
复制代码


   
回复

使用道具 举报

109

主题

5562

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10541
金钱
10541
注册时间
2017-2-18
在线时间
1908 小时
发表于 2020-5-19 15:07:44 | 显示全部楼层
帮顶~~
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-19 15:45:07 | 显示全部楼层

谢谢哥们!
回复

使用道具 举报

7

主题

16

帖子

0

精华

新手上路

积分
43
金钱
43
注册时间
2020-5-7
在线时间
6 小时
发表于 2020-5-19 16:31:24 | 显示全部楼层
帮顶。。。
回复

使用道具 举报

1

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
142
金钱
142
注册时间
2017-12-27
在线时间
31 小时
发表于 2020-5-19 16:36:35 | 显示全部楼层
vCanTxTask  任务是否在某个地方陷入死循环,导致一直没有读取队列,你这是阻塞1s,时间到后,队列有返回继续执行吗?
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-19 23:42:59 | 显示全部楼层
Deven001 发表于 2020-5-19 16:36
vCanTxTask  任务是否在某个地方陷入死循环,导致一直没有读取队列,你这是阻塞1s,时间到后,队列有返回继 ...

这个问题我也查过,没有发现死循环。队列一直没有返回执行,但是在另外一个任务vBoardLEDTask里查询vCanTxTask任务状态时,显示vCanTxTask任务处于就绪eReady状态
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-19 23:46:45 | 显示全部楼层

感谢哥们
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-20 09:29:35 | 显示全部楼层
Deven001 发表于 2020-5-19 16:36
vCanTxTask  任务是否在某个地方陷入死循环,导致一直没有读取队列,你这是阻塞1s,时间到后,队列有返回继 ...

发生问题的时候检查过,没有陷入死循环。队列阻塞后就没返回,但任务处于就绪态
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-20 09:30:44 | 显示全部楼层

感谢哥们!
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-5-20 11:39:06 | 显示全部楼层
本帖最后由 霸王猫 于 2020-5-20 13:36 编辑

我第一次看见楼主这样编写任务。

  1、FREERTOS要求:xQueueSendFromISR只能在中断服务程序中调用
   2、
FREERTOS要求xQueueSend只能在任务中调用
   3、楼主写的void vCanTx(CanTxFrameTypeDef *ptx),只是一个普通的函数,而不是一个任务,普通的函数中怎么可以调用引起任务切换的API函数呢?      
   4、另外楼主竟然在void vCanTx(CanTxFrameTypeDef *ptx)这个函数中在某种条件成立时调用xQueueSendFromISR,在另一个条件成立时调用xQueueSend,我第一次看到。


回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2020-5-21 01:30:28 | 显示全部楼层
帮顶
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-21 09:29:32 | 显示全部楼层

感谢原子哥!
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-21 10:02:55 | 显示全部楼层
霸王猫 发表于 2020-5-20 11:39
我第一次看见楼主这样编写任务。

   1、FREERTOS要求:xQueueSendFromISR只能在中断服务程序中调用

你好哥们,感谢你的回复!
你说的第1、2点完全正确,FreeRTOS确实是这么规定的。
第3点:普通函数为什么不能调用引起任务切换的API函数?例如:某个任务调用这个vCanTx函数向队列发送消息,由于队列满了,所以这个任务也阻塞等待了几ms时间,我觉得这没什么问题,至少在现在的程序中没有逻辑问题。
第4点:你说的某种条件应该是if(0 == __get_CONTROL()),这个是用来判断该vCanTx函数是否在中断中被调用的,因为vCanTx既可能在任务中被调用,也有可能在中断服务函数中被调用,所以在函数中需要判断本函数是在任务中被调用还是在中断中被调用,然后再根据第1、2点规则,调用相应的队列发送函数
其实这个函数也是参考的微信公众号strongerhuang写的CANFestival例程修改的。
关于__get_CONTROL()的应用也可以参考以下博文:
https://blog.csdn.net/dp29sym41zygndvf/article/details/82392553
回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-21 10:17:31 | 显示全部楼层
霸王猫 发表于 2020-5-20 12:00
FreeRTOS一般常用的写法如下:

   1、中断服务程序中发送信号量或消息队列

非常感谢你的代码分享!
可能应用场景不同,所以在我的应用中,CAN发送任务并不需要知道发送队列里的队列项是哪个任务发送的,它只管把队列里的CAN帧发送出去就行了,所以也就不需要消息协议了,我只定义了一个CAN帧结构体,并把这个结构体的大小作为队列项的长度。如:
  1. CanTxQueue = xQueueCreate(CANTX_Q_NUM, sizeof(CanTxFrameTypeDef));
复制代码

回复

使用道具 举报

39

主题

131

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1439
金钱
1439
注册时间
2015-12-26
在线时间
208 小时
 楼主| 发表于 2020-5-24 21:19:22 | 显示全部楼层
发现代码中有个Timer1的中断优先级是0,高于FreeRTOS管理的最高中断优先级5,而在Timer1中有可能会调用vCanTx函数,从而进一步调用了FreeRTOS入队API函数,;改进后测试几天下来再也没有发现CAN任务停止现象。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-22 22:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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