ESP32队列整数组发送而非逐字节传输的定时器功能异常求助
问题与代码分析
我尝试将UART接收的数组传入hex_to_bin函数,数据接收正常且已传入队列。希望队列每次仅发送一个字节,以便在turn_on_off任务中提取比特并执行定时器功能。使用二进制信号量后比特提取成功,但定时器功能无法正常运行,附上代码:
#include "main.h" QueueHandle_t data_queue; void turn_on_off(void *pvParameters) { uint8_t bit; int data_index = 0; timer_start(TIMER_GROUP, TIMER_INDEX); gpio_set_level(GPIO_NUM_2, true); int bit_check = 0; int prev_bit_check; UartDataStruct UartDataStruct_Onewire; timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0); while (true) { if ((xQueueReceive(data_queue, &UartDataStruct_Onewire, portMAX_DELAY) == pdPASS)) { // printf("Received data is : %s | len : %d\r\n",&UartDataStruct_Onewire.UartDataBuffer[0],UartDataStruct_Onewire.len); timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0); while (true) { timer_get_counter_value(TIMER_GROUP, TIMER_INDEX, &task_counter_value); // printf("Task counter value: %lld",task_counter_value); if (bit_check == 0) { if (task_counter_value > 200000) // 1000 count per ms { gpio_set_level(GPIO_NUM_2, false); if (task_counter_value > 256000) { gpio_set_level(GPIO_NUM_2, true); bit_check++; timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0); } } } else { for (data_index = 0; data_index < UartDataStruct_Onewire.len - 1; data_index++) { for (int itr = 7; itr >= 0; itr--) { bit = (UartDataStruct_Onewire.UartDataBuffer[data_index] >> itr) & 0x01; // ESP_LOGI("Onewire","Bit extracted: %d", bit); if (bit == 1) { for (prev_bit_check = bit_check; bit_check > prev_bit_check;) { if (task_counter_value > 30000) // 1000 COUNT PER ms { gpio_set_level(GPIO_NUM_2, false); if (task_counter_value > 38000) { gpio_set_level(GPIO_NUM_2, true); bit_check++; timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0); } } } } else { for (prev_bit_check = bit_check; bit_check > prev_bit_check;) { if (task_counter_value > 6000) // 1000 COUNT PER ms { gpio_set_level(GPIO_NUM_2, false); if (task_counter_value > 26000) { gpio_set_level(GPIO_NUM_2, true); bit_check++; timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0); } } } } } printf("---------------\r\n"); } } if (data_index == UartDataStruct_Onewire.len - 1) { bit_check = 0; break; } } } } }
问题根源分析
- 死循环阻塞任务:内层
for (prev_bit_check = bit_check; bit_check > prev_bit_check;)是死循环,只有定时器计数满足条件时bit_check才会递增,否则会持续占用CPU,既无法更新定时器计数值,也无法触发任务切换,导致定时器逻辑完全无法执行。 - 定时器计数值未实时更新:
task_counter_value仅在最外层while(true)中读取一次,后续循环始终使用旧值,永远无法满足定时器触发条件。 - 队列设计不符合需求:当前队列传递的是包含多字节数组的
UartDataStruct结构体,但需求是每次发送单个字节,队列元素类型应改为uint8_t。 - 嵌套循环逻辑混乱:内层
while(true)与外层for循环的退出条件衔接错误,可能导致任务无法正常退出当前数据处理流程。
解决方案
- 调整队列类型:初始化队列时指定元素为
uint8_t,UART接收回调中每次发送一个字节到队列:// 队列初始化示例 data_queue = xQueueCreate(10, sizeof(uint8_t)); - 替换轮询为FreeRTOS定时API:使用
vTaskDelayUntil实现精确定时,避免轮询占用CPU,同时确保GPIO电平切换的时间精度。 - 简化比特处理逻辑:去掉冗余嵌套,直接按比特顺序处理每个字节。
修改后的代码示例
#include "main.h" QueueHandle_t data_queue; void turn_on_off(void *pvParameters) { uint8_t current_byte; uint8_t bit; TickType_t last_wake_time; // 初始化定时器(确保已正确配置计数模式、时钟源等) timer_start(TIMER_GROUP, TIMER_INDEX); gpio_set_level(GPIO_NUM_2, true); while (true) { // 从队列接收单个字节 if (xQueueReceive(data_queue, ¤t_byte, portMAX_DELAY) == pdPASS) { // 处理起始位(对应原逻辑的200ms低+56ms高) gpio_set_level(GPIO_NUM_2, false); vTaskDelay(pdMS_TO_TICKS(200)); gpio_set_level(GPIO_NUM_2, true); vTaskDelay(pdMS_TO_TICKS(56)); last_wake_time = xTaskGetTickCount(); // 提取当前字节的每一位(从高位到低位) for (int itr = 7; itr >= 0; itr--) { bit = (current_byte >> itr) & 0x01; if (bit == 1) { // 比特1:8ms低电平 + 22ms高电平(总30ms) gpio_set_level(GPIO_NUM_2, false); vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(8)); gpio_set_level(GPIO_NUM_2, true); vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(22)); } else { // 比特0:6ms低电平 + 20ms高电平(总26ms) gpio_set_level(GPIO_NUM_2, false); vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(6)); gpio_set_level(GPIO_NUM_2, true); vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(20)); } } printf("---------------\r\n"); } } }
内容的提问来源于stack exchange,提问作者Balaji Baski
相关产品推荐
相关产品推荐

