FreeRTOS之任务管理
学习/总结/工具
FreeRTOS
字数统计: 1.7k(字)
阅读时长: 7(分)
FreeRTOS学习记录第一天
一、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| int main(void) { /*主控及相关外设初始化*/ BspInit (); /* 创建任务 */ AppTaskCreate(); /* 启动调度,开始执行任务 */ vTaskStartScheduler();
/* 如果一切正常, main()函数不应该会执行到这里。但如果执行到这里,很可能是内存堆空间不足导致空闲 任务无法创建。第五章有讲述更多关于内存管理方面的信息 */ for( ;; ); }
static void vTaskTest1(void *pvParameters) { volatile unsigned long u1; for(;;) {
printf("Test 1\r\n"); for(u1=0;u1<1000000;u1++) { } } }
static void vTaskTest2(void *pvParameters) { volatile unsigned long u1; for(;;) { printf("Test 2\r\n"); for(u1=0;u1<1000000;u1++) { } } }
static void AppTaskCreate (void) {
/*测试任务*/ xTaskCreate( vTaskTest1, "vTaskTest1", 512, NULL, 1, NULL ); xTaskCreate( vTaskTest2, "vTaskTest2", 512, NULL, 1, NULL ); }
|
串口输出:
分析:
两个任务的优先级相同,因为我们开启了调度器,调度器会让任务轮流执行一个“时间片”;
如果其中一个优先级高,将一直执行优先级高的任务,优先级低的任务也就被“饿死”了,CPU在任何时刻永远执行当前优先级最高的任务;
二、
仅更改任务的优先级:
1 2 3 4 5 6 7
| static void AppTaskCreate (void) {
/*测试任务*/ xTaskCreate( vTaskTest1, "vTaskTest1", 512, NULL, 1, NULL ); xTaskCreate( vTaskTest2, "vTaskTest2", 512, NULL, 2, NULL ); }
|
串口输出如下图所示:
三、
使用vTaskDelay()延时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| static void vTaskTest1(void *pvParameters) { volatile unsigned long u1; for(;;) {
printf("Test 1\r\n"); /*调用vTaskDelay()让任务在延迟期间保持在阻塞态,延迟是以心跳周期为单位, 常量portTick_RATE_MS可以用来在毫秒和心跳周期之间相互转换。*/ vTaskDelay(250 / portTICK_RATE_MS); } }
static void vTaskTest2(void *pvParameters) { volatile unsigned long u1; for(;;) { printf("Test 2\r\n"); /*调用vTaskDelay()让任务在延迟期间保持在阻塞态,延迟是以心跳周期为单位, 常量portTick_RATE_MS可以用来在毫秒和心跳周期之间相互转换。*/ vTaskDelay(250 / portTICK_RATE_MS); } }
static void AppTaskCreate (void) {
/*测试任务*/ xTaskCreate( vTaskTest1, "vTaskTest1", 512, NULL, 1, NULL ); xTaskCreate( vTaskTest2, "vTaskTest2", 512, NULL, 2, NULL ); }
|
串口打印如下:
分析:
当程序进入阻塞态时,CPU将执行当前优先级虽然较低但是可以运行的任务,这样来回切换。
四、
补充1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #define configUSE_PREEMPTION 1 #define configSUPPORT_STATIC_ALLOCATION 0 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( SystemCoreClock ) #define configTICK_RATE_HZ ((TickType_t)1000) /*心跳中断频率为1000HZ也就是时间片长度1ms*/ #define configMAX_PRIORITIES ( 7 ) #define configMINIMAL_STACK_SIZE ((uint16_t)128) #define configTOTAL_HEAP_SIZE ((size_t)( 30 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_16_BIT_TICKS 0 #define configUSE_MUTEXES 1 #define configQUEUE_REGISTRY_SIZE 8 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configIDLE_SHOULD_YIELD 1
|
补充2:
vTaskDelayUntil()可以用于精准延时;
函数原型:
1
| void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
|
使用示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| static void vTaskTest1(void *pvParameters) { portTickType xLastWakeTime; /*变量xLastWakeTime需要被初始化为当前心跳计数值。说明一下,这是该变量 唯一一次被显式赋值,之后,xLastWakeTime将在函数vTaskDelayUntil()中自动 更新*/ xLastWakeTime = xTaskGetTickCount(); for(;;) {
printf("Test 1\r\n"); /*调用vTaskDelay()让任务在延迟期间保持在阻塞态,延迟是以心跳周期为单位, 常量portTick_RATE_MS可以用来在毫秒和心跳周期之间相互转换。*/ vTaskDelayUntil(&xLastWakeTime,(1000 / portTICK_RATE_MS)); } }
|
FreeRTOS学习记录第二天
一、钩子函数
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| unsigned long ulIdleCycleCount=0UL;//钩子函数变量初始值 static void vTaskTest1(void *pvParameters) { for(;;) {
printf("Test 1\r\n"); printf("ulIdleCycleCount=%ld\r\n",ulIdleCycleCount); /*调用vTaskDelay()让任务在延迟期间保持在阻塞态,延迟是以心跳周期为单位, 常量portTick_RATE_MS可以用来在毫秒和心跳周期之间相互转换。*/ vTaskDelay(250 / portTICK_RATE_MS); } }
static void vTaskTest2(void *pvParameters) { volatile unsigned long u1; for(;;) { printf("Test 2\r\n"); printf("ulIdleCycleCount=%ld\r\n",ulIdleCycleCount); /*调用vTaskDelay()让任务在延迟期间保持在阻塞态,延迟是以心跳周期为单位, 常量portTick_RATE_MS可以用来在毫秒和心跳周期之间相互转换。*/ vTaskDelay(250 / portTICK_RATE_MS); } }
/*钩子函数必须命名为vApplicationIdleHook,无参数也无返回值*/ void vApplicationIdleHook( void ) { ulIdleCycleCount++;
}
|
串口打印如下:
注:使用钩子函数必须把configUSE_IDLE_HOOK配置为1
分析如下:
空闲任务钩子函数会被空闲任务每循环一次就自动调用一次。
通常空闲任务钩子函数被用于:
1.执行低优先级,后台或需要不停处理的功能代码;
2.测试系统处理裕量;
3.将处理器配置到低功耗模式–提供一种自动省电的方法,使得在没有任何应用功能需要处理的时候,系统自动进入省电模式;
二、改变任务优先级
原型:void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
注:
1.改变任务优先级
2.最高优先级为configMAX_PRIORITIES-1,如果设置的值超过了最大可用优先级,则自动封顶为最大值
原型:UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )
注:
1.获取任务当前的优先级
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| /*声明变量用于保存任务2的句柄*/ xTaskHandle xTask2Handle; static void vTaskTest1(void *pvParameters) { UBaseType_t uxNewPriority; /*NULL表示获取“返回我自己的优先级”*/ uxNewPriority=uxTaskPriorityGet(NULL); for(;;) {
printf("Test 1\r\n"); printf("About to run Task2\r\n"); /*将任务2的优先级,设置为比任务1的优先级高1也就是3, 如果不改变优先级的话,就将一直运行任务1了*/ vTaskPrioritySet( xTask2Handle, (uxNewPriority+1)); } }
static void vTaskTest2(void *pvParameters) { UBaseType_t uxNewPriority; /*NULL表示获取“返回我自己的优先级”*/ uxNewPriority=uxTaskPriorityGet(NULL); for(;;) { printf("Test 2\r\n"); printf("About to lower the Task2 priority\r\n"); /*uxNewPriority-2=1即恢复原来的优先级1,任务1得以运行,否则将 一直运行任务2,任务1将被饿死*/ vTaskPrioritySet( NULL, (uxNewPriority-2)); } }
static void AppTaskCreate (void) {
/*测试任务*/ /*任务1创建在优先级2上。任务参数没有用到,设为NULL。任务句柄也不会用到,也设为NULL*/ xTaskCreate( vTaskTest1, "vTaskTest1", 512, NULL, 2, NULL ); /*任务2创建在优先级1上,此优先级低于任务1,任务参数没有用到,设为NULL。但任务2的任务 句柄会被用到,故将xTask2Handle的地址传入*/ xTaskCreate( vTaskTest2, "vTaskTest2", 512, NULL, 1,&xTask2Handle ); }
|
串口打印如下:
三、删除任务
原型:void vTaskDelete( TaskHandle_t xTaskToDelete )
注:
1.只有内核为任务分配的内存空间才会在任务被删除后自动回收。任务自己占用的内存或资源需要由应用程序自己显式地释放。