问题1
用xTaskCreate()函数创建了一个任务,xTaskCreate(SetTask,"SetTask",4096,(void*)(&setvalue),1,xTaskHandle); 在SetTask()任务函数中调用 vTaskDelay(pdMS_TO_TICKS(2)); 想实现一个2ms的任务延时,结果延时了几个us ,这是什么原因?
分析
可能原因:1. FreeRTOS的tick rate(时钟节拍频率)设置问题:pdMS_TO_TICKS宏将毫秒转换为系统节拍(ticks)。如果系统的tick rate设置得很低,那么每个tick的时间就很长,可能导致2ms转换后的tick数很小,甚至为0。
系统tick rate设置得非常低?比如默认的100Hz(一个tick为10ms),那么2ms不足一个tick,会被转换为0,因此vTaskDelay(0)会导致任务立即让出CPU,但不会主动阻塞,这样任务会再次被调度运行,看起来就像几乎没有延时。
pdMS_TO_TICKS()宏的作用:
将毫秒转换为FreeRTOS的系统节拍(ticks)。
根据宏 #define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000U ) )
得出计算公式:
tick_count = (milliseconds * configTICK_RATE_HZ) / 1000;
若结果小于1 configTICK_RATE_HZ=100; 2ms*100<1000 ; tick_count=0;
vTaskDelay(0)的行为:
不阻塞任务,仅让出CPU给同优先级或更高优先级的任务
任务切换耗时通常在几µs级别,符合观察现象。
ESP-IDF的默认配置
configTICK_RATE_HZ默认为100(即1个tick=10ms)。此时
pdMS_TO_TICKS(2) = (2 * 100) / 1000 = 0.2 → 截断为0
因此实际调用的是vTaskDelay(0)。
问题2
esp_rom_delay_us() 忙等待
可以实现高精度的延时,但是因为是独占CPU,如果太长会触发看门狗复位等无法控制的错误,适用于低延时等待场景。
问题3
在非任务场景中,比方说main() 函数初始化,中断中,不能使用vTaskDelay()函数实现延时,因为vTaskDelay() 依赖任务调度器,它会主动让出CPU控制权,把当前任务挂到延时队列里,等时间到了再唤醒。这机制完全建立在任务上下文的基础上,得有任务控制块TCB 这些数据结构支撑。
vTaskDelay() 内部最终会调用 portYIELD() 或类似机制请求任务切换。在中断中,任务切换有专门的 API (portYIELD_FROM_ISR()),使用 vTaskDelay() 会调用错误的切换机制。在调度器启动前,根本没有任务可以切换。
1万+



被折叠的 条评论
为什么被折叠?



