单片机通信数据延迟问题排查

2023-09-25 8 0

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。

代码编程
赞赏

相关文章

商务电子邮箱那个安全?怎么使用163邮箱最安全?
企业邮箱邮件迁移攻略,怎么把邮件同步到新注册的企业邮箱?
公司企业邮箱开通使用,收不到邮件怎么办?
邮件撤回方法详解,一键解决发错邮件的尴尬
公司邮件怎么备份?外贸企业邮箱邮件存储知识分享
春节假期怎么看公司邮箱邮件方便,好用的外贸企业邮箱推荐