我目前正在为ARM Cortex M4 MCU上的项目开发一些软件,其中需要执行三个主要的主要任务:
1) Init_all.c - Must run first and ONLY once at startup
2) Task1.c - Runs infrequently; Once every 10 seconds
3) Task2.c - Must run most frequently
我决定尝试使用FreeRTOS,看看在简单的无限While(1)
循环中使用FreeRTOS调度是否有任何好处
基于我到目前为止从文档中读到的内容(如果我错了,请纠正我),
1)FreeRTOS基于优先级运行任务 - 如果没有中断或停止条件被编码到最高优先级任务中,任何优先级较低的任务将永远不会排队并运行
2)如果在无限的for(;;)
循环中没有任何内容,该任务将只运行一次(循环外的代码,比如初始化外设一次)
由于FreeRTOS按优先级选择和排队任务,因此我在分配和创建任务时提出的初始解决方案如下:
1) Init_all.c - Highest priority; for(;;) loop only contains code to trigger LED
2) Task1.c - Second highest priority **but** I include a 10 second interrupt vTaskDelay( xDelay10000ms ) right at the start of the for(;;) loop
3) Task2.c - Lowest priority
在测试时,如果遵循FreeRTOS逻辑,我应该永远不会看到Task1.c和Task2.c排队,因为Init_all.c任务永远不会结束,因为它有代码来触发for(;;)
循环中的LED。
这引出了我的问题:当我实施上述内容时,我们看到了两个令人费解的观察结果:
观察1:
1)Init_all.c任务运行
2)然后是Task1.c,然后被中断并立即停止10秒。
3)在此期间,Task2.c运行直到10秒钟为止。然后Task1.c接管并在vTaskDelay( xDelay6000ms )
中断后运行代码。
所有这些,Init_all.c仍在运行,但idk在队列的什么位置。 LED确实每秒触发一次,但再一次,纯粹混淆了为什么Init_all.c任务正在运行。
Task1.c的代码如下所示,以提供更好的说明:
// Task1.c
void Task1(void const * argument)
{
// Timer interrupt
const TickType_t xDelay10000ms = pdMS_TO_TICKS( 10000 );
for( ;; )
{
/** Immediately block this task for 10secs upon starting it **/
vTaskDelay( xDelay10000ms );
( code below to execute AFTER the Task1 resumes from the interrupt )
}
观察2:
Task2需要1秒才能运行,所以理论上它应该在10秒窗口中运行10次,由中断给出。
但是,我会看到一个奇怪的结果,其中Task2有时会运行9次,然后运行10次。
我错误地理解了FreeRTOS概念吗?谢谢!代码如下:
Init_all.c任务:
void StartDefaultTask(void const * argument)
{
init_sensor1();
init_sensor2();
init_sensor3();
init_sensor4();
for( ; ; )
{
GREEN_LED_ON();
osDelay(50);
GREEN_LED_OFF();
osDelay(1000);
}
}
任务1:
void Task1(void const * argument)
{
// Timer interrupt
const TickType_t xDelay6000ms = pdMS_TO_TICKS( 6000 );
// All Initialisation
for( ;; )
{
// Timer interrupt this task to ensure apptasks.c finishes first?
vTaskDelay( xDelay6000ms );
takesensor1data();
takesensor2data();
}
}
任务2:
void Task2(void const * argument)
{
// Timer interrupt
const TickType_t xDelay6000ms = pdMS_TO_TICKS( 6000 );
// All Initialisation
for( ;; )
{
takesensor3data();
takesensor4data();
}
}
Init_all.c - 必须首先运行,并且只能在启动时运行一次
在此页面上搜索“Daemon Task Startup Hook”:https://www.freertos.org/a00016.html
2)如果在(;;)循环的无限中没有放置任何内容,那么该任务将只运行一次(循环外的代码,比如初始化外设一次)
如果您这样做,那么您必须在其实现结束时删除该任务(调用vTaskDelete(NULL))。 https://www.freertos.org/implementing-a-FreeRTOS-task.html
至于你的主要问题 - 你没有显示init任务的代码,所以不可能说。但是,通常这种系统实现为事件驱动,因此大多数任务大部分时间都处于阻塞状态(不使用任何CPU,因此可以执行较低优先级的任务)。
我担心你的观察是错误的