FreeRTOS基础教程第一章创建任务
1.硬件初始化本章创建的任务需要用到开发板上的 LED所以先要将 LED 相关的函数初始化好 为了方便以后统一管理板级外设的初始化我们在 main.c 文件中创建一个 BSP_Init()函数 专门用于存放板级外设初始化函数/*********************************************************************** * 函数名 BSP_Init * 功能说明 板级外设初始化所有板子上的初始化均可放在这个函数里面 * 参数 * 返回值 无 *********************************************************************/ static void BSP_Init(void) { /* * STM32中断优先级分组为4即4bit都用来表示抢占优先级范围为0~15 * 优先级分组只需要分组一次即可以后如果有其他的任务需要用到中断 * 都统一用这个优先级分组千万不要再分组切忌。 */ NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); /* LED 初始化 */ LED_GPIO_Config(); /* 串口初始化 */ USART_Config(); }执行到 BSP_Init()函数的时候操作系统完全都还没有涉及到即 BSP_Init()函数所做 的工作跟我们以前编写的裸机工程里面的硬件初始化工作是一模一样的。运行完 BSP_Init () 函数接下来才慢慢启动操作系统最后运行创建好的任务。有时候任务创建好整个系 统跑起来了可想要的实验现象就是出不来比如 LED 不会亮串口没有输出LCD 没 有显示等等。如果是初学者这个时候就会心急如焚四处求救那怎么办这个时候如 何排除是硬件的问题还是系统的问题这里面有个小小的技巧即在硬件初始化好之后 顺便测试下硬件测试方法跟裸机编程一样/*********************************************************************** * 函数名 BSP_Init * 功能说明 板级外设初始化所有板子上的初始化均可放在这个函数里面 * 参数 * 返回值 无 *********************************************************************/ static void BSP_Init(void) { /* * STM32中断优先级分组为4即4bit都用来表示抢占优先级范围为0~15 * 优先级分组只需要分组一次即可以后如果有其他的任务需要用到中断 * 都统一用这个优先级分组千万不要再分组切忌。 */ NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); /* LED 初始化 */ LED_GPIO_Config(); /* 测试硬件是否正常工作 */ LED1_ON; /* 让程序停在这里不再继续往下执行 */ while(1); /* 串口初始化 */ USART_Config(); }2.创建单任务—SRAM静态内存这里我们创建一个单任务任务使用的栈和任务控制块都使用静态内存即预先定 义好的全局变量这些预先定义好的全局变量都存在内部的 SRAM 中。2.1定义任务函数任务实际上就是一个无限循环且不带返回值的 C 函数。目前我们创建一个这样的任 务让开发板上面的 LED 灯以 500ms 的频率闪烁/********************************************************************** * 函数名 LED_Task * 功能说明 LED_Task任务主体 * 参数 * 返回值 无 ********************************************************************/ static void LED_Task(void* parameter) { while (1) { LED1_ON; vTaskDelay(500); /* 延时500个tick */ printf(LED_Task Running,LED1_ON\r\n); LED1_OFF; vTaskDelay(500); /* 延时500个tick */ printf(LED_Task Running,LED1_OFF\r\n); } }2.2空闲任务与定时器任务堆栈函数实现当我们使用了静态创建任务的时候configSUPPORT_STATIC_ALLOCATION 这个宏 定 义 必 须为 1 在 FreeRTOSConfig.h 文 件 中 并且 我 们需 要 实 现两 个 函数 vApplicationGetIdleTaskMemory()与 vApplicationGetTimerTaskMemory()这两个函数是用 户设定的空闲Idle任务与定时器Timer任务的堆栈大小必须由用户自己分配而 不能是动态分配/* 空闲任务任务堆栈 */ static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE]; /* 定时器任务堆栈 */ static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH]; /* 空闲任务控制块 */ static StaticTask_t Idle_Task_TCB; /* 定时器任务控制块 */ static StaticTask_t Timer_Task_TCB; /** ********************************************************************** * brief 获取空闲任务的任务堆栈和任务控制块内存 * ppxTimerTaskTCBBuffer : 任务控制块内存 * ppxTimerTaskStackBuffer : 任务堆栈内存 * pulTimerTaskStackSize : 任务堆栈大小 * date 2018-xx-xx ********************************************************************** */ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { *ppxIdleTaskTCBBufferIdle_Task_TCB;/* 任务控制块内存 */ *ppxIdleTaskStackBufferIdle_Task_Stack;/* 任务堆栈内存 */ *pulIdleTaskStackSizeconfigMINIMAL_STACK_SIZE;/* 任务堆栈大小 */ } /** ********************************************************************* * brief 获取定时器任务的任务堆栈和任务控制块内存 * ppxTimerTaskTCBBuffer : 任务控制块内存 * ppxTimerTaskStackBuffer : 任务堆栈内存 * pulTimerTaskStackSize : 任务堆栈大小 ********************************************************************** */ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { *ppxTimerTaskTCBBufferTimer_Task_TCB;/* 任务控制块内存 */ *ppxTimerTaskStackBufferTimer_Task_Stack;/* 任务堆栈内存 */ *pulTimerTaskStackSizeconfigTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */ }2.3 定义任务栈目前我们只创建了一个任务当任务进入延时的时候因为没有另外就绪的用户任务 那么系统就会进入空闲任务空闲任务是 FreeRTOS 系统自己启动的一个任务优先级最 低。当整个系统都没有就绪任务的时候系统必须保证有一个任务在运行空闲任务就是 为这个设计的。当用户任务延时到期又会从空闲任务切换回用户任务。 在 FreeRTOS 系统中每一个任务都是独立的他们的运行环境都单独的保存在他们 的栈空间当中。那么在定义好任务函数之后我们还要为任务定义一个栈目前我们使用 的是静态内存所以任务栈是一个独立的全局变量具体见代码清单 14-5。任务的栈占用 的是 MCU 内部的 RAM当任务越多的时候需要使用的栈空间就越大即需要使用的 RAM 空间就越多。一个 MCU 能够支持多少任务就得看你的 RAM 空间有多少。/* AppTaskCreate任务任务堆栈 */ static StackType_t AppTaskCreate_Stack[128]; /* LED任务堆栈 */ static StackType_t LED_Task_Stack[128];2.4定义任务控制块定义好任务函数和任务栈之后我们还需要为任务定义一个任务控制块通常我们称 这个任务控制块为任务的身份证。在 C代码上任务控制块就是一个结构体里面有非常 多的成员这些成员共同描述了任务的全部信息/* AppTaskCreate 任务控制块 */ static StaticTask_t AppTaskCreate_TCB; /* AppTaskCreate 任务控制块 */ static StaticTask_t LED_Task_TCB;2.5 静态创建任务一个任务的三要素是任务主体函数任务栈任务控制块那么怎么样把这三个要素 联合在一起FreeRTOS 里面有一个叫静态任务创建函数 xTaskCreateStatic()它就是干这 个活的。它将任务主体函数任务栈静态的和任务控制块静态的这三者联系在一 起让任务可以随时被系统启动/* 创建 AppTaskCreate 任务 */ AppTaskCreate_Handle xTaskCreateStatic((TaskFunction_t )AppTaskCreate, //任务函数 (const char* )AppTaskCreate, //任务名称 (uint32_t )128, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )3, //任务优先级 (StackType_t* )AppTaskCreate_Stack, //任务堆栈 (StaticTask_t* )AppTaskCreate_TCB); //任务控制块 if(NULL ! AppTaskCreate_Handle)/* 创建成功 */ vTaskStartScheduler(); /* 启动任务开启调度 */2.6 启动任务当任务创建好后是处于任务就绪Ready在就绪态的任务可以参与操作系统的调度。 但是此时任务仅仅是创建了还未开启任务调度器也没创建空闲任务与定时器任务如果使 能了 configUSE_TIMERS 这个宏定义那这两个任务就是在启动任务调度器中实现每个操 作系统任务调度器只启动一次之后就不会再次执行了FreeRTOS 中启动任务调度器的函 数是 vTaskStartScheduler()并且启动任务调度器的时候就不会返回从此任务管理都由 FreeRTOS管理此时才是真正进入实时操作系统中的第一步vTaskStartScheduler(); /* 启动任务开启调度 */2.7 main.c文件内容全貌现在我们把任务主体任务栈任务控制块这三部分代码统一放到 main.c 中我们在 main.c 文件中创建一个 AppTaskCreate 任务这个任务是用于创建用户任务为了方便管 理我们的所有的任务创建都统一放在这个函数中在这个函数中创建成功的任务就可以 直接参与任务调度了/* FreeRTOS头文件 */ #include FreeRTOS.h #include task.h /* 开发板硬件bsp头文件 */ #include bsp_led.h #include bsp_usart.h static void AppTaskCreate(void);/* 用于创建任务 */ static void LED_Task(void* pvParameters);/* LED_Task任务实现 */ static void BSP_Init(void);/* 用于初始化板载相关资源 */ /**************************** 任务句柄 ********************************/ /* * 任务句柄是一个指针用于指向一个任务当任务创建好之后它就具有了一个任务句柄 * 以后我们要想操作这个任务都需要通过这个任务句柄如果是自身的任务操作自己那么 * 这个句柄可以为NULL。 */ /* 创建任务句柄 */ static TaskHandle_t AppTaskCreate_Handle; /* LED任务句柄 */ static TaskHandle_t LED_Task_Handle; /********************************** 内核对象句柄 *********************************/ /* * 信号量消息队列事件标志组软件定时器这些都属于内核的对象要想使用这些内核 * 对象必须先创建创建成功之后会返回一个相应的句柄。实际上就是一个指针后续我 * 们就可以通过这个句柄操作这些内核对象。 * * 内核对象说白了就是一种全局的数据结构通过这些数据结构我们可以实现任务间的通信 * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数 * 来完成的 * */ /******************************* 全局变量声明 ************************************/ /* * 当我们在写应用程序的时候可能需要用到一些全局变量。 */ /* AppTaskCreate任务任务堆栈 */ static StackType_t AppTaskCreate_Stack[128]; /* LED任务堆栈 */ static StackType_t LED_Task_Stack[128]; /* AppTaskCreate 任务控制块 */ static StaticTask_t AppTaskCreate_TCB; /* AppTaskCreate 任务控制块 */ static StaticTask_t LED_Task_TCB; /* 空闲任务任务堆栈 */ static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE]; /* 定时器任务堆栈 */ static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH]; /* 空闲任务控制块 */ static StaticTask_t Idle_Task_TCB; /* 定时器任务控制块 */ static StaticTask_t Timer_Task_TCB; /** * 使用了静态分配内存以下这两个函数是由用户实现函数在task.c文件中有引用 * 当且仅当 configSUPPORT_STATIC_ALLOCATION 这个宏定义为 1 的时候才有效 */ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize); void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize); /***************************************************************** * brief 主函数 * param 无 * retval 无 * note 第一步开发板硬件初始化 第二步创建APP应用任务 第三步启动FreeRTOS开始多任务调度 ****************************************************************/ int main(void) { /* 开发板硬件初始化 */ BSP_Init(); printf(这是一个[野火]-STM32全系列开发板-FreeRTOS-静态创建单任务!\r\n); /* 创建 AppTaskCreate 任务 */ AppTaskCreate_Handle xTaskCreateStatic((TaskFunction_t )AppTaskCreate, //任务函数 (const char* )AppTaskCreate, //任务名称 (uint32_t )128, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )3, //任务优先级 (StackType_t* )AppTaskCreate_Stack, //任务堆栈 (StaticTask_t* )AppTaskCreate_TCB); //任务控制块 if(NULL ! AppTaskCreate_Handle)/* 创建成功 */ vTaskStartScheduler(); /* 启动任务开启调度 */ while(1); /* 正常不会执行到这里 */ } /*********************************************************************** * 函数名 AppTaskCreate * 功能说明 为了方便管理所有的任务创建函数都放在这个函数里面 * 参数 无 * 返回值 无 **********************************************************************/ static void AppTaskCreate(void) { taskENTER_CRITICAL(); //进入临界区 /* 创建LED_Task任务 */ LED_Task_Handle xTaskCreateStatic((TaskFunction_t )LED_Task, //任务函数 (const char* )LED_Task, //任务名称 (uint32_t )128, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )4, //任务优先级 (StackType_t* )LED_Task_Stack, //任务堆栈 (StaticTask_t* )LED_Task_TCB); //任务控制块 if(NULL ! LED_Task_Handle)/* 创建成功 */ printf(LED_Task任务创建成功!\n); else printf(LED_Task任务创建失败!\n); vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务 taskEXIT_CRITICAL(); //退出临界区 } /********************************************************************** * 函数名 LED_Task * 功能说明 LED_Task任务主体 * 参数 * 返回值 无 ********************************************************************/ static void LED_Task(void* parameter) { while (1) { LED1_ON; vTaskDelay(500); /* 延时500个tick */ printf(LED_Task Running,LED1_ON\r\n); LED1_OFF; vTaskDelay(500); /* 延时500个tick */ printf(LED_Task Running,LED1_OFF\r\n); } } /*********************************************************************** * 函数名 BSP_Init * 功能说明 板级外设初始化所有板子上的初始化均可放在这个函数里面 * 参数 * 返回值 无 *********************************************************************/ static void BSP_Init(void) { /* * STM32中断优先级分组为4即4bit都用来表示抢占优先级范围为0~15 * 优先级分组只需要分组一次即可以后如果有其他的任务需要用到中断 * 都统一用这个优先级分组千万不要再分组切忌。 */ NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); /* LED 初始化 */ LED_GPIO_Config(); /* 测试硬件是否正常工作 */ LED1_ON; /* 让程序停在这里不再继续往下执行 */ while(1); /* 串口初始化 */ USART_Config(); } /** ********************************************************************** * brief 获取空闲任务的任务堆栈和任务控制块内存 * ppxTimerTaskTCBBuffer : 任务控制块内存 * ppxTimerTaskStackBuffer : 任务堆栈内存 * pulTimerTaskStackSize : 任务堆栈大小 * date 2018-xx-xx ********************************************************************** */ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { *ppxIdleTaskTCBBufferIdle_Task_TCB;/* 任务控制块内存 */ *ppxIdleTaskStackBufferIdle_Task_Stack;/* 任务堆栈内存 */ *pulIdleTaskStackSizeconfigMINIMAL_STACK_SIZE;/* 任务堆栈大小 */ } /** ********************************************************************* * brief 获取定时器任务的任务堆栈和任务控制块内存 * ppxTimerTaskTCBBuffer : 任务控制块内存 * ppxTimerTaskStackBuffer : 任务堆栈内存 * pulTimerTaskStackSize : 任务堆栈大小 ********************************************************************** */ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { *ppxTimerTaskTCBBufferTimer_Task_TCB;/* 任务控制块内存 */ *ppxTimerTaskStackBufferTimer_Task_Stack;/* 任务堆栈内存 */ *pulTimerTaskStackSizeconfigTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */ } /********************************END OF FILE****************************/注意在使用静态创建任务的时候必须要将 FreeRTOSConfig.h 中 的 configSUPPORT_STATIC_ALLOCATION 宏配置为 1。下载后可以看到板子上面的 LED 灯已经在 闪烁说明我们创建的单任务使用静态内存已经跑起来了。本篇内容摘自野火《FreeRTOS内核实现与应用开发》

相关新闻

最新新闻

日新闻

周新闻

月新闻