1. RTOS介绍FreeRTOS 是一款免费、开源、轻量级的实时操作系统RTOS专为微控制器MCU和小型嵌入式系统设计使用相当广泛同时易于使用。官网https://wap.freertos.org/官网有详细的FreeRTOS介绍包含移植教程。以下则基于官网的下图所示移植说明进行移植。2. 硬件APM32F103VB MINI板3. 移植介绍在开始移植前需确保有一个完全能正确执行的裸机代码环境。如下为本次移植的裸机代码环境官网提供最新版本的OS代码下载。部分.c源文件是必须使用的可选的.c源文件则根据自己的情况酌情添加实际代码位于FreeRTOS/FreeRTOS-Kernel目录内。此处我们将.c源文件拷贝工程的/lib/FreeRTOS/kernel目录内因为我们使用的是Keil编译环境所以port.c应该从FreeRTOS/FreeRTOS-Kernel/portable/Keil中拷贝使用但Keil目录内提示“See-also-the-RVDS-directory”所以实际从目录FreeRTOS/FreeRTOS-Kernel/portable/RVDS拷贝即可且APM32F103为Cortex-M3内核所以port最终拷贝的目录为:FreeRTOS/FreeRTOS-Kernel/portable/RVDS/ARM_CM3:代码拷贝到工程的lib/FreeRTOS/portable目录中heap_x.c位于源码的FreeRTOS/FreeRTOS-Kernel/portable/MemMang目录内此处拷贝到工程的lib/FreeRTOS/MemMang目录中.c源文件拷贝完成还有部分头文件需要拷贝将整个include文件夹拷贝到工程目录中其中配置文件FreeRTOSConfig.h位于目录FreeRTOS/FreeRTOS-Kernel/examples/template_configuration同时注意官网的提示It is therefore specific to the application, not the RTOS, and should be located in an application directory, not in one of the RTOS kernel source code directories.配置文件是应用特定的文件不是RTOS的一部分应该放到应用的文件夹内所以我们放在工程的src/app文件夹内至此文件的拷贝完成添加到工程中并添加对应的头文件路径选择使用heap_4.c其他版本可从官网查看差异并根据自己的情况选择因为是通用的配置文件因此不可能一次性编译成功还需要修改FreeRTOSConfig.h首次编译后出现多个errors都是配置文件的问题配置文件各个宏定义不理解含义则可以在官网点进去查看里面有绝大部分宏定义的解析另外也可以借助AI工具查找资料辅助理解具体FreeRTOSConfig.h如何修改大家根据编译提示和官网的解析做对应的更改即可同时功能裁剪也是配置文件的工作。最后要注意到平台移植port.c文件内部复制/** Exception handlers.*/voidxPortPendSVHandler(void);voidxPortSysTickHandler(void);voidvPortSVCHandler(void);已经实现了三个中断服务函数这三个中断服务函数非常重要我们需要屏蔽apm32f10x_int.c文件中的对应版本改为使用port.c内的代码复制/*!*briefThis function handles SVCall exception**paramNone**retvalNone**///void SVC_Handler(void)//{//}/*!*briefThis function handles PendSV_Handler exception**paramNone**retvalNone**///void PendSV_Handler(void)//{//}/*!*briefThis function handles SysTick Handler**paramNone**retvalNone**///void SysTick_Handler(void)//{//}因为startup.s启动文件的中断服务函数名与apm32f10x_int.c中是一致的所以为了改为使用port.c内的中断服务函数名需要在FreeRTOSConfig.h文件添加如下宏定义复制/* 每次任务切换都执行, 保存 / 恢复上下文完成任务切换 */#define xPortPendSVHandler PendSV_Handler/* 系统启动时仅执行一次, 启动第一个任务切换到线程模式 */#define vPortSVCHandler SVC_Handler/* cmsis_os2.c 已经实现新的版本 *//* 提供OS运行的节拍 */#define xPortSysTickHandler SysTick_Handler此时FreeRTOS的移植就已经全部完成我们可以直接按照OS的代码写法要求写代码测试即可。下面介绍一个使用FreeRTOS更便利的方案如果了解FreeRTOS会知道同一个功能在中断环境下和非中断环境下调用的OS接口是不一样的例如获取信号量中断环境下需要调用xSemaphoreTakeFromISR而非中断环境下需要调用xSemaphoreTake。ARM为此提供了一个解决方案屏蔽了这种差异让中断和非中断环境下都是调用同一个接口函数。拷贝cmsis_os2的代码到OS目录中只有3个文件打开cmsis_os2.c查看获取信号量部分的代码osSemaphoreAcquire函数内部会调用IS_IRQ检查当前是否处于中断环境如果是则调用xSemaphoreTakeFromISR接口否则调用xSemaphoreTake接口而我们在编程时不管是中断或非中断环境下都是统一调用osSemaphoreAcquire接口即可非常便利。其他的功能也有一样的处理方式。有cmsis_os加入后编程需要使用到OS的功能都统一从cmsis_os.h/cmsis_os2.h中取接口函数使用即可不用再使用原生的FreeRTOS接口。因为cmsis_os2.c中重新实现了SysTick_Handler中断服务函数所以FreeRTOSConfig.h需要屏蔽掉xPortSysTickHandler宏定义使用cmsis_os2.c中的版本即可。4. 测试测试创建两个任务分别翻转1个LED进行测试复制/* LED_D2 */TaskHandle_t *led_d2_task_handle;constosThreadAttr_t led_d2_task_att {.name LED_D2,.priority (osPriority_t)10,.stack_size (1024),};/* LED_D3 */TaskHandle_t *led_d3_task_handle;constosThreadAttr_t led_d3_task_att {.name LED_D3,.priority (osPriority_t)11,.stack_size (1024),};/** brief LED D2 任务** param None** retval None**/staticvoidled_d2_task(void*argument){(void)argument;while(1) {bsp_gpio_toggle(OUTPUT_LED2);osDelay(100);}}/** brief LED D3 任务** param None** retval None**/staticvoidled_d3_task(void*argument){(void)argument;while(1) {bsp_gpio_toggle(OUTPUT_LED3);osDelay(300);}}/** brief 任务创建** param None** retval None**/voidtask_create(void){led_d2_task_handle osThreadNew(led_d2_task,NULL, led_d2_task_att);led_d3_task_handle osThreadNew(led_d3_task,NULL, led_d3_task_att);}复制// 外设初始化voidbsp_init(void){NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);bsp_gpio_init();}复制// 应用初始化voidapp_init(void){osKernelInitialize();task_create();osKernelStart();}// 应用任务voidapp_task(void){}LED翻转的间隔时间与程序使用的osDelay延时一致。另外NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4)将优先级分组配置为4则中断优先级全部为抢占而没有子优先级方便OS管理中断。5.详细代码FreeRTOS.zip(5.94 MB, 下载次数: 0)。---------------------作者口天土立口链接https://bbs.21ic.com/icview-3509353-1-1.html来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。