HAL库+CubeMX freeRTOS闪烁LED
1、概述
操作系统 (Operating System) 的本质是一个帮助用户进行功能管理的软件。操作系统运行在硬件之上,为其他工作的软件执行资源分配等管理工作。
一般称呼不使用操作系统的单片机开发方式为“裸机开发”,当进行裸机开发时,需要自己设计循环,中断,定时等功能来控制各个任务的执行顺序。而使用操作系统进行开发时,只需要创建任务,操作系统会自动按照一些特定的机制自动进行任务的运行和切换。
除了任务管理之外,操作系统还可以提供许多功能,比如各个任务之间的通信,同步,任务的堆栈管理,控制任务对重要资源的互斥访问等。
由于单片机的资源比较少,显然无法运行如Windows,MacOS等计算机操作系统,一般在单片机上运行的是经过专门设计的嵌入式实时操作系统 (RTOS)。
freeRTOS就是其中一种,其他比较常见的嵌入式实时操作系统还有uCOSⅡ,RTThread等。freeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行,并且有着庞大的社区和生态。
2、cubeMX中freeRTOS的配置
- 首先打开Middleware标签,选中其中的FREERTOS选项,进入FREERTOS的配置页面。
- 在Mode页面下,选择Interface的版本,这里选择CMSIS_V1。CMSIS是由Keil提供的一套特殊的函数接口,他对freeRTOS的功能函数进行了封装,使其变得更加易用,在使用freeRTOS时,不需要再去直接调用freeRTOS的函数,只需要调用CMSIS为我们提供的函数即可,目前CMSIS有V1和V2两个版本。
- 通过以上方式就可以完成freeRTOS的开启,在生成代码之后,freeRTOS会自动被移植到工程中。接着在Configuration页面下进行freeRTOS的配置
在页面中,可以配置freeRTOS的一些重要的属性,包括是否支持抢占机制,freeRTOS的系统时钟速率,最大优先级数量,最小任务栈尺寸,最大任务名称长度等。针对一些比较重要的配置列表如下:
3、cubeMX中创建任务
首先在freeRTOS的配置页面中的Configuration下,选中Tasks and Queues标签页,存在一个已经创建的默认任务为“defaultTask”,点击进入配置选项修改为如下图所示。
如果需要增加一个新任务,点击Add,就可以创建一个新的任务。
在弹出的页面中,可以配置任务名称,优先级,栈大小,入口函数等。各个参数的具体功能见下表:
设置完毕之后点击OK,就可以看到列表中多出了自己创建的任务。
在freertos.c中也可以找到修改的默认任务函数。
__weak void red_led_task(void const * argument) {
/* USER CODE BEGIN red_led_task */
/* Infinite loop */
for(;;) {
osDelay(1);
}
/* USER CODE END red_led_task */
}
由于选择了通过__weak修饰符创建一个弱函数,可以再在别处实现该任务函数。程序执行时会自动寻找到这个另外实现的任务函数。
void red_led_task(void const * argument) {
while(1) {
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET);
osDelay(500);
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET);
osDelay(500);
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET);
osDelay(500);
}
}
由于新建了任务“LED_GREEN”,并且设置为As external,故而需要再在别处实现任务函数。程序执行时会自动寻找到实现的任务函数。
void green_led_task(void const * argument){
while(1) {
HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_RESET);
osDelay(500);
HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_SET);
osDelay(500);
HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_RESET);
osDelay(500);
}
}
4、程序中创建任务
打开freertos.c文件,在MX_FREERTOS_Init中,找到创建两个进程的代码,分别是LED_RED和LED_GREEN。可以看到要创建任务时,只需要调用osThreadDef和osThreadCreate即可,创建“LED_BLUE”任务。
/* Create the thread(s) */
/* definition and creation of LED_RED */
osThreadDef(LED_RED, red_led_task, osPriorityNormal, 0, 128);
LED_REDHandle = osThreadCreate(osThread(LED_RED), NULL);
/* definition and creation of LED_GREEN */
osThreadDef(LED_GREEN, green_led_task, osPriorityHigh, 0, 128);
LED_GREENHandle = osThreadCreate(osThread(LED_GREEN), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
osThreadDef(LED_BLUE, blue_led_task, osPriorityHigh, 0, 128);
led_blue_handle = osThreadCreate(osThread(LED_BLUE), NULL);
/* USER CODE END RTOS_THREADS */
4.1、osThreadDef
首先介绍osThreadDef,实际上这不是一个函数,而是一个由CMSIS提供的宏定义,用于对要创建的任务进行设置
#define osThreadDef(name, thread, priority, instances, stacksz) \
extern const osThreadDef_t os_thread_def_##name
4.2、osThreadCreate函数
接着通过CMSIS提供的osThreadCreate函数来创建任务
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument);
通过以上两步,一个任务就成功创建了,创建一个名称和osThreadDef中的thread参数一致的函数,操作系统会自动找到该函数并将其作为一个进程来执行。比如声明thread为blue_led_task,则还需要执行函数void blue_led_task(void const * argument),while(1)循环中的内容为用户自己的代码。