前言
最近正在学习和FreeRTOS相关的知识,在此记录一下,学习资料来自正点原子
在学习之前,我也有一个和很多初学者共同的疑惑----Why RTOS?
在探究这个问题之前,我想先回顾一下什么是RTOS
RTOS介绍
RTOS即为Real Time Operating System(实时操作系统)在以往的裸机编程中我们会通过定时器中断结合while循环来控制单片机
这样造成的现象就是不能多个任务同时进行,必须要执行完上一个任务才能执行下一个,可能有些朋友会想:靠定时器中断回调就可以了啊,但是中断是不能执行长时间的任务的,稍有帮助的一种思路就是在中断回调函数中挂起对应的工作标志位,while中检测到后就会开始执行,但这样还是会浪费很多时间在等待上一个任务中
这个时候RTOS的优势就展现出来了
RTOS可以控制CPU不断地工作,充分利用CPU的所有性能,简单来说就是给每个任务分片对应的运行时间,时间到了就进入下一个任务,上一个任务的节点会通过堆栈指针保留起来,等下次轮到它的时候会从上一次开始执行,Unix系统也是如此,而笔者选用FreeRTOS的原因是因为其免费且是ST官方钦定的RTOS,可以在CUBEMX中一键配置(不得不感叹大厂才做环境啊)
相关原理
这次我只打算讨论动态任务的创建和删除,这里简单带过一下原理
任务调度
FreeRTOS支持三种任务调度方式:抢占式调度、时间片调度以及协程式调度,我们前面提到了RTOS中的任务是可以连续执行的,每个任务有对应的工作周期,这里就重点介绍一下抢占式和时间片调度
抢占式调度
抢占式调度针对的是优先级不同的任务,每个任务都被分配了一个优先级,优先级高的可以抢占优先级低的任务
这里的优先级和中断机制类似,FreeRTOS的工作方式有两种:特殊方法&通用方法,在通用方法下的优先级算法是通过软件配置,理论上可以有很多个,相反的特殊方法则是基于32位MCU硬件,对应的优先级数有0~31,两者的区别是后者的运行速度高于前者,数值越大的优先级越大,这是和中断机制不同的,还需要注意的一点是:中断的优先级比RTOS中的任何任务都要高
时间片调度
和上面不同,时间片调度针对的是同一个优先级下的任务
当多个任务的优先级相同时,任务调度器会在每一次系统时钟节拍到(1MS)的时候切换任务
任务状态
FreeRTOS中的任务有四种状态:运行态、就绪态、阻塞态、挂起态
并且除了运行态其他三种状态都有自身对应的任务状态列表:就绪列表、阻塞列表、挂起列表
在一个线程中只能有一个任务处于运行态,其他的任务会处于另外的三种状态,如下图所示
只有就绪态可以和运行态相互转换,运行态可以进入任意一种其他形态,换句话说就是所有的任务要先从挂起态&阻塞态进入就绪态才可以顺利开始线程
![在这里插入图片描述](https://img-blog.csdnimg.cn/ba843be50be945a391ba127569e518c9.png#pic_center)
抢占式流程
具体的抢占式流程可以看这张图
![在这里插入图片描述](https://img-blog.csdnimg.cn/3cf43b4c58884d0db190c0be1918fc52.png#pic_center)
这里的优先级顺序为Task3>Task2>Task1,因此可以看出当Task1处在运行态且Task2处在阻塞&挂起态时Task1可以正常工作,但当Task2处在就绪态后Task1会被优先级高的Task2抢占,此时堆栈会记录Task1的工作进度并等到下一次Task2&Task3均被阻塞&挂起时再重新执行完剩下的工作
时间片流程
若创建的三个任务Task1、Task2、Task3均为同一个优先级,这就代表它们处在就绪列表的同一个位置处,此时会按照分配的顺序从Task1执行1ms->Task2执行1ms->Task3执行1ms->Task1执行1ms往复工作
工程搭建
接下来就可以进入CUBEMX配置了,我所使用的开发板是正点的基于F103ZET6的精英板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传![在这里插入图片描述](https://img-blog.csdnimg.cn/951df2c960684bc5a5c6c48bad1ce7f5.png#pic_center)
一些简单的配置就不多介绍了
下面我们来看FreeRTOS的配置
关于其他的配置可以参考正点的资料或者查看别的文章,有很多详细的介绍,这里就只介绍最简单的创建一个任务
![在这里插入图片描述](https://img-blog.csdnimg.cn/2aa035ee611346a597c6361a21356861.png#pic_center)
接下来就可以学习相关的代码了,下面这些代码是FreeRTOSConfig.h中的,关于各种宏的说明我已加上了中文注释,可自行阅读
配置代码
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#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)
#define configMAX_PRIORITIES ( 32 )
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configTOTAL_HEAP_SIZE ((size_t)3072)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xQueueGetMutexHolder 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_eTaskGetState 1
#define USE_FreeRTOS_HEAP_4
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS#else
#define configPRIO_BITS 4
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#endif
点灯代码
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#define LED1_ON() HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET)
#define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET)
#define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET)
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.priority = (osPriority_t) osPriorityLow1,
.stack_size = 128 * 4
};
osThreadId_t MYTASK01Handle;
const osThreadAttr_t MYTASK01_attributes = {
.name = "MYTASK01",
.priority = (osPriority_t) osPriorityLow1,
.stack_size = 128 * 4
};
void StartDefaultTask(void *argument);
void myTask01(void *argument);
void MX_FREERTOS_Init(void);
void MX_FREERTOS_Init(void) {
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
MYTASK01Handle = osThreadNew(myTask01, NULL, &MYTASK01_attributes);
}
void StartDefaultTask(void *argument)
{
for(;;)
{
osDelay(100);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4) == GPIO_PIN_RESET)
{
vTaskDelete(&MYTASK01Handle);
}
}
}
void myTask01(void *argument)
{
for(;;)
{
LED1_ON();
vTaskDelay(500);
LED1_OFF();
osDelay(520);
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)