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

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。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值