目录

FreeRTOS简介

配置FreeRTOS工程模板

FreeRTOS初体验


FreeRTOS简介

FreeRTOS是一个轻量级的实时操作系统(RTOS)内核,专为嵌入式系统而设计。

相较于裸机开发,RTOS提供了一个稳定的、结构清晰的框架,通过使用预测性调度算法使系统能够在严格定义的时间内响应外部事件,通过优先级调度和资源管理,减少了任务冲突和资源争用的可能性,从而提高了系统的稳定性和可靠性。

RTOS能够同时管理多个任务,提高了系统的并发处理能力。这使得RTOS能够轻松应对需要同时处理多个任务的场景,如智能家居系统中的多设备控制、医疗设备中的多传感器数据处理等。而裸机开发通常只能处理单个任务或简单的任务切换,难以满足复杂系统的需求。

配置FreeRTOS工程模板

如何搞出一个FreeRTOS的工程模板呢?第一种方法,你可以直接下载一个别人配置好的工程,在里面进行修改,编写自己所需的业务逻辑。第二种方法,自己学习一下如何生成FreeRTOS工程模板,以免在网上找不到与自己所用板子型号匹配的工程。下面我们以STM32的HAL库为例,生成一个FreeRTOS工程模板。(别担心,即使你用的不是STM32也无妨,其他板子是一样的道理,看完下面的配置过程你就懂了)

首先,我们需要通过CubeMX生成一个裸机工程。具体生成过程我相信大家应该都会,因为既然你来学RTOS那么一定是做过裸机开发的,不会的话可以去自行查阅一下。

需要强调几个和平时配置不同的地方:

由于FreeRTOS使用SysTick作为它的心跳,所以HAL的时基就不能再使用滴答定时器,在TIM1~4里随便选择一个即可。

在NVIC中勾选Sort by Premption Priority and Sub Priority,优先级分组选择4。

生成工程,打开后目录是这样的:

这就是一个裸机工程。接下来,我们要在这个工程里添加FreeRTOS的代码。

打开裸机工程代码文件夹,在该文件夹下添加FreeRTOS文件夹:

FreeRTOS文件夹包含如下:

include文件夹:

portable文件夹:

这些文件都可以在FreeRTOS的官网下载FreeRTOS™ - FreeRTOS™

接着在Keil里添加这些文件:

还要添加 FreeRTOSConfig.h(FreeRTOS的配置文件)。记得要添加 ../FreeRTOS/Include 路径,不然会报错。后面可能还会有一堆报错,基本都是头文件包含的问题,耐心点一个个解决就好了。

打开 stm32f1xx_it.c 中断文件,在这三个中断里

void SVC_Handler(void)
void PendSV_Handler(void)
void SysTick_Handler(void)

分别添加这三个函数

vPortSVCHandler();
xPortPendSVHandler();
xPortSysTickHandler();

这三个函数是FreeRTOS与硬件(如Cortex-M系列处理器)之间的接口的一部分,用于处理特定的中断或异常。SVC异常是一种软件触发的异常,通常用于从用户模式调用操作系统服务或执行某些特权操作。在FreeRTOS中,SVC异常可能被用来实现任务切换或触发其他内核功能。vPortSVCHandler()函数的具体实现会根据FreeRTOS的配置和硬件平台而有所不同。PendSV异常用于延迟的上下文切换或任务切换。在FreeRTOS中,当需要进行任务切换时,不是立即执行切换,而是设置一个标志并通过触发PendSV异常来延迟切换操作。这样做的好处是可以确保当前的指令序列完成,同时减少在中断处理中执行复杂操作的风险。xPortPendSVHandler()函数负责执行实际的上下文切换逻辑。xPortSysTickHandler()函数是SysTick定时器中断的服务例程,它负责更新FreeRTOS的时间基准,以及执行与时间相关的任务,如检查是否有任务应该超时或阻塞等。

编译无误后,你就得到了一个template,可以在里面写程序了。

回到我们在创建FreeRTOS工程模板最开始时候说的,即使你用的不是STM32也无妨,其他板子是一样的道理。意思就是,无论什么板子,先创建一个裸机工程,再往里面添加FreeRTOS的代码,添加FreeRTOS的异常处理函数。HAL库就是比较方便,其他环境不完善的板子类似于标准库的操作。

FreeRTOS初体验

我们来做个最经典的任务:创建两个任务,在任务一中让LED1以0.5s的间隔闪烁,在任务二中让LED2以1s的间隔闪烁。

先在CubeMX中配置两个GPIO输出引脚,用于控制LED1和LED2,在main.c中编写代码:

void Task1(void *pvParameters)
{
    while(1)
    {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
        vTaskDelay(500);
    }
}

void Task2(void *pvParameters)
{
    while(1)
    {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_7);
        vTaskDelay(1000);
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
	
	// 创建任务1
    xTaskCreate(Task1, "LED1", 500, NULL, 1, NULL);
	
	// 创建任务2
	xTaskCreate(Task2, "LED2", 500, NULL, 1, NULL);

	// 启动任务调度
    vTaskStartScheduler();

    while (1)
    {
    }
}

其中,xTaskCreate(Task1, "LED1", 500, NULL, 1, NULL) 的意思是创建一个名为"LED1"的任务,运行Task1函数。任务的堆栈大小为500字节,优先级为1(在FreeRTOS中,优先级数值越低,优先级越高),没有传递参数给任务。Task2同理。vTaskStartScheduler() 启动任务调度器后FreeRTOS便开始接管,并不会执行到while(1),而是一直执行创建的任务1、任务2。在任务1中,每隔500ms翻转一下LED1,在任务2中,每隔1000ms翻转一下LED2,两个任务交替执行,看起来就像在一起执行一样。至于具体的执行过程,后续的文章中会讲到。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐