1、问题说明
笔者在最近的项目中,发现系统的响应延迟较高。经过排查,排除了单片机运行卡死的问题。
2、原因分析
具体排查过程这里就不细致说明了,直接给出排查后原因。任务执行周期规划不合理,导致freertos队列发送接收到的命令有延迟。
为了便于理解,这里就不展示代码,直接展示一段简单的示例代码会更清晰。先看下代码的框图
上图较为清晰的说明了两个任务的功能及执行周期。下面看下具体实现的代码
void task1(void *pvParameters)
{uint8_t data = 1;uint16_t count = 0;while (1){if(count==0){printf("task1 data: %d \r\n",data); }xQueueSend(txque,&data,0);count++;if(count>=100){data++; count = 0;}vTaskDelay(10);}
}
void task2(void *pvParameters)
{uint8_t data = 0;static uint8_t data_old = 0;uint32_t err =0 ;while (1){err = xQueueReceive(txque,&data,0);if(err == pdPASS){if(data!=data_old){printf("task2 data: %d \r\n",data); }data_old = data;}vTaskDelay(100);}
}
为了便于方便观察,任务1的data值,每个1s变化一次。queue长度为20。
编译运行,结果如图
处理第一次发送的1延迟了100ms左右,其他每个数据都延迟了将近2s中。这就造成了发送与接收的延迟。上文遇到的就是这个现象。原因就是发送与接收不同步,再看看下整个过程中队列内数据的变化。
第0ms,task1个空队列发送了一个1,但是此时由于task2需要延时100ms,所以等到第100ms,task2才收到task1第0ms发送的数据1.task1打印数据1
第100ms,由于task1是每隔10ms給队列发送一个1,所以此时队列中有10个1,刚好此时,任务2完成100ms延时,开始接收队列数据,就收到了第一个数据1。task2打印出数据1.
第200ms,此时task1以及向队列发送了20个1,由于在第100ms任务2接收了一个第一个数据1,所以此时队列中一共有19个1。此时task2接收到了第二个数据1. 由于值没有变化,task2不打印数据。
第220ms-999ms,此时队列中的数据全部是1,由于队列长度是20.所以第230ms的数据1实际上没有发送出去,因为队列满了。
第1000ms,此时由于task2接收到了一个数据1,队列中空出来1个位置。同时,task1中值变化为2,由于队列中空出来一位,所有任务1将数据2发送到了队列的末尾的位置。 task1打印数据2
由于队列长度为20,任务2运行周期为100ms,所以任务2要将队列中数据全部接收完毕,需要2000ms。也就是说第1000ms任务1发送的数据2,任务2在第3000ms的时候才能接收到。
通过上面的分析,可以得知,由于任务1执行的速度是任务2的10倍,所以任务2接收数据的最大延迟为20*100ms为2000ms,基本与上面的运行结果的截图一致。
3、问题解决
经过上面的分析后,问题的根本原因是,任务1和2执行的周期不协调造成。所以修改方式也比较简单,只需要将任务1的执行周期同样改为100ms,此时最大延迟也就是100ms。相当于任务1发送数据的时候,任务2刚好完成接收进入了睡眠,只有等100ms延时之后,任务2才能接收到刚刚任务1发送的数据。
最好的解决办法是,去掉任务2的运行周期延迟,改为任务2接收队列是无限等待,任务1保持不变。只要队列中有数据,立刻接收。更改后的任务2如下:
void task2(void *pvParameters)
{uint8_t data = 0;static uint8_t data_old = 0;uint32_t err =0 ;while (1){err = xQueueReceive(txque,&data,portMAX_DELAY );if(err == pdPASS){if(data!=data_old){printf("task2 data: %d \r\n",data); }data_old = data;}
// vTaskDelay(100);}
}
更改后的运行结果如下图:
发送与接收实现了同步,基本没有延迟。
注意:采用队列接收无限等待的方式,会造成任务2只有在接收到了数据的时候才会运行,没有收到数据就一直睡眠。如果任务2中有其他需要定期执行的事情的时候,该方法就不合适,只能将任务的运行周期改为100ms。