前言
裸机开发中,如果要延时,要使用delay等函数(博流使用:bflb_mtimer_delay_ms等函数)
这些函数有个共同点,CPU在延时中是做不了其他东东的,只能延时,CPU的利用率太低了
所以就有了RTOS这种多任务系统
但是,多任务中,有个函数需要延时,怎么处理呢?
这就引入了vtaskdelay函数
首先说明,vtaskdelay(1000) 严格意义上说,这里不是延时1000ms,而是延时1000ticks
心跳速率(tick rate)是FreeRTOS操作系统中的一个重要参数,它决定了系统的时间分辨率和任务调度的频率。每个心跳周期(tick)代表着一个固定的时间片(time slice),任务调度器会根据这个时间片来分配CPU时间给各个任务。
vtaskdelay延时的是时间长度,单位是系统时钟节拍周期
所以,在FreeRTOS中,正常需要延时1ms,需要这样写
vTaskDelay(1000/portTICK_RATE_MS);
portTICK_RATE_MS常量是用于将毫秒(ms)为单位的时间值转换为以心跳周期(Ticks)为单位的时间值。
这样才是延时1000ms,只是小安派里配置的 1Ticks 等于1ms,所以vTaskDelay(1000); 也是可以的
这是小安派配置文件
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#ifdef __riscv64
#define configTICK_RATE_HZ ((TickType_t)1000)
正常使用的时候,还可以用这个宏命令转换,也会把毫秒转换成Ticks
pdMS_TO_TICKS( 1000 );
vtaskdelay是如何执行延时的
- 当vtaskdelay传的值为0的时候,系统会触发一次任务调度,但不会使当前任务进入阻塞状态
- 如果延时时间大于0,系统会先将当前任务从就绪列表中移除,并将其加入到所谓的"delayed task"链表中。这个过程表示当前任务已经被挂起,并且将在指定的延时时间后恢复执行。
- 当达到指定的延时时间后,系统会遍历"delayed task"链表,并将所有挂起的任务从链表中移除,然后将其重新加入到就绪列表中。这表示这些任务现在又可以被任务调度器选中并执行了。
- 在恢复所有挂起的任务后,系统会触发一次任务调度。如果这次调度导致了一个任务切换,那么系统会设置一个标志位,以确保在后续的时钟中断中不再触发任务调度。如果没有发生任务切换,那么系统会再次触发任务调度。
总结
vTaskDelay()函数用于实现任务的阻塞延时,即让出CPU的控制权。在延时期间,任务不会执行任何代码,也不会消耗CPU资源。延时结束后,任务会重新进入就绪状态,等待被任务调度器选中并执行。 |