FreeRTOS 的官网为:https://www.freertos.org/
FreeRTOS 的内核支持抢占式, 合作式和时间片调度。任务与任务、 任务与中断之间可以使用任务通知、消息队列、二值信号量、数值型信号量、 递归互斥信号量和互斥信号量进行通信和同步。
RTOS 系统的核心就是任务管理, FreeRTOS 是一个抢占式的实时多任务系统, 其任务调度器也是抢占式的。高优先级的任务可以打断低优先级任务的运行而取得 CPU 的使用权,这样就保证了那些紧急任务的运行。 这样我们就可以为那些对实时性要求高的任务设置一个很高的优先级。 高优先级的任务执行完成以后重新把 CPU 的使用权归还给低优先级的任务,这个就是抢占式多任务系统的基本原理。
2.任务状态介绍
● 运行态
当一个任务正在运行时, 那么就说这个任务处于运行态, 处于运行态的任务就是当前正在使用处理器的任务。 如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。
● 就绪态
处于就绪态的任务是那些已经准备就绪(这些任务没有被阻塞或者挂起), 可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!
● 阻塞态
如果一个任务当前正在等待某个外部事件的话就说它处于阻塞态, 比如说如果某个任务调用了函数 vTaskDelay()的话就会进入阻塞态, 直到延时周期完成。任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间任务就会退出阻塞态,即使所等待的事件还没有来临!
● 挂起态
像阻塞态一样,任务进入挂起态以后也不能被调度器调用进入运行态, 但是进入挂起态的任务没有超时时间。任务进入和退出挂起态通过调用函数 vTaskSuspend()和 xTaskResume()。
————————————————
版权声明:本文为CSDN博主「温人之周.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xxxx123041/article/details/122229384
链接: https://blog.csdn.net/weixin_43930521/article/details/124432875
链接: https://img-blog.csdnimg.cn/20200313171835198.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjEyMDky,size_16,color_FFFFFF,t_70
BaseType_t xTaskCreate
(
TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为 word,10 表示40 字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask
); // 任务句柄, 以后使用它来操作这个任
务
void vTask1( void *pvParameters )
{
const char *pcTaskName = "T1 run\r\n";
volatile uint32_t ul; /* volatile 用来避免被优化掉 */
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务 1 的信息 */
printf( pcTaskName );
/* 延迟一会(比较简单粗暴) */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
}
}
}
void vTask1( void *pvParameters )
{
const char *pcTaskName = "T1 run\r\n";
volatile uint32_t ul; /* volatile 用来避免被优化掉 */
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务 1 的信息 */
printf( pcTaskName );
/* 延迟一会(比较简单粗暴) */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
}
}
}
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为 word,10 表示
40 字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任
务
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
创建两个任务,但是两个任务调用一个函数,并传入不同参数。
void vTaskFunction( void *pvParameters )
{
const char *pcTaskText = pvParameters;
volatile uint32_t ul; /* volatile 用来避免被优化掉 */
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf(pcTaskText);//pcTaskText来自pvParameters,
/* 延迟一会(比较简单粗暴) */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
}
}
}
static const char *pcTextForTask1 = "T1 run\r\n";
static const char *pcTextForTask2 = "T2 run\r\n";
int main( void )
{
prvSetupHardware();
xTaskCreate(vTaskFunction, "Task 1", 1000, (void *)pcTextForTask1, 1, NULL);
xTaskCreate(vTaskFunction, "Task 2", 1000, (void *)pcTextForTask2, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
只需要一个函数就可实现删除任务,可以删除自己也可以删除其他人
void vTaskDelete( TaskHandle_t xTaskToDelete )
void vTask1( void *pvParameters )
{
const TickType_t xDelay100ms = pdMS_TO_TICKS( 100UL );
BaseType_t ret;
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("Task1 is running\r\n");
ret = xTaskCreate( vTask2, "Task 2", 1000, NULL, 2, &xTask2Handle );
if (ret != pdPASS)
printf("Create Task2 Failed\r\n");
// 如果不休眠的话, Idle 任务无法得到执行
// Idel 任务会清理任务 2 使用的内存
// 如果不休眠则 Idle 任务无法执行, 最后内存耗尽
vTaskDelay( xDelay100ms );
}
}
void vTask2( void *pvParameters )
{
/* 打印任务的信息 */
printf("Task2 is running and about to delete itself\r\n");
// 可以直接传入参数 NULL, 这里只是为了演示函数用法
vTaskDelete(xTask2Handle);
}
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
相当于排队,谁排队靠前,谁优先级高
FreeRTOS 会确保最高优先级的、可运行的任务,马上就能执行
对于相同优先级的、可运行的任务,轮流执行
Task3优先级最高,只有它运行 vTaskDelay();休眠函数时其他任务才可以运行;
void vTask1( void *pvParameters )
{
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T1\r\n");
}
}
void vTask2( void *pvParameters )
{
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T2\r\n");
}
}
void vTask3( void *pvParameters )
{
const TickType_t xDelay3000ms = pdMS_TO_TICKS( 3000UL );
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T3\r\n");
// 如果不休眠的话, 其他任务无法得到执行
vTaskDelay( xDelay3000ms );
}
}
int main(void)
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);
xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
如果优先级高的任务,不进入休眠状态。则其他的低优先级的任务就处于:阻塞状态;
字面意思就是停下任务,并没有删除,还可以重启;
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
要退出暂停状态,只能由别人来操作:
别的任务调用:vTaskResume
中断程序调用:xTaskResumeFromISR
就是可运行状态。可以通过Delay 函数,决定它什么时候好准备好,直白一点就是延时多久时间可以运行这个函数;
vTaskDelay:至少等待指定个数的 Tick Interrupt 才能变为就绪状态;(就比如单片机的延时函数)
vTaskDelayUntil:等待到指定的绝对时刻,才能变为就绪态。(就比如单片机,自动重装载定时中断)
##if 1
vTaskDelay(xDelay50ms);
##else
vTaskDelayUntil(&xLastWakeTime, xDelay50ms);
##endif
钩子函数,把这个宏定义为 1:configUSE_IDLE_HOOK
任务优先级为0,最低优先级,要么有同级任务,轮询执行;要么就,有休眠函数
{
1.vTaskDelay(xDelay50ms);
2.vTaskDelayUntil(&xLastWakeTime, xDelay50ms);
}
或者不运行;
void vApplicationIdleHook(void)
{
flagIdleTaskrun = 1;
flagTask1run = 0;
flagTask2run = 0;
flagTask3run = 0;
/* 故意加入打印让 flagIdleTaskrun 变为 1 的时间维持长一点 */
printf("Id\r\n");
}
(了解就行)
// 实验 1:抢占
##define configUSE_PREEMPTION 1
##define configUSE_TIME_SLICING 1
##define configIDLE_SHOULD_YIELD 1
// 实验 2:不抢占
##define configUSE_PREEMPTION 0
##define configUSE_TIME_SLICING 1
##define configIDLE_SHOULD_YIELD 1
// 实验 1:时间片轮转
##define configUSE_PREEMPTION 1
##define configUSE_TIME_SLICING 1
##define configIDLE_SHOULD_YIELD 1
// 实验 2:时间片不轮转
##define configUSE_PREEMPTION 1
##define configUSE_TIME_SLICING 0
##define configIDLE_SHOULD_YIELD 1
// 实验 1:空闲任务让步
##define configUSE_PREEMPTION 1
##define configUSE_TIME_SLICING 1
##define configIDLE_SHOULD_YIELD 1
// 实验 2:空闲任务不让步
##define configUSE_PREEMPTION 1
##define configUSE_TIME_SLICING 1
##define configIDLE_SHOULD_YIELD 0
在这里插入代码片