赞
踩
本文的主要内容重在应用,将FreeRTOS移植到STM32F103ZET6(其他类型的型号一样可以参考本文,只用略做一点修改就行,会在下面进行讲解,区别在哪里)上进行相关的小实验。
源码的官方下载地址为 FreeRTOS官方下载链接,本次移植的版本的是V10.3.0。
下载好后的文件如下:
其中我们只关心FreeRTOS文件夹,里面是内核所在的文件夹,包含源码和示例程序;FreeRTOS-Plus文件包含第3方中间源码及示例程序;FreeRTOS-Labs文件是V9.0及以前版本中所没有的。
其中Demo是FreeRTOS的示例,Source是FreeRTOS内核所在的文件夹。
include文件夹存放的是对应.c文件的头文件。portable文件夹是FreeRTOS和具体硬件联系在一起的桥梁,也叫移植层文件夹。
FreeRTOS在不同的编译环境,不同的硬件平台实现,需要portable文件夹对应的文件支持,因此移植层文件是进行移植的关键文件。
对于在MDK-ARM编译环境下,需要Keil,MenMang,RVDS文件。其中重点关注RVDS文件夹,它里面包含了针对不同架构的MCU实现FreeRTOS与硬件相关的操作与宏定义,不同的架构的MCU使用对于其架构相对于的文件夹。列如,STM32F1xx系列的芯片属于ARM Cortex-M3内核,使用ARM_CM3文件夹的文件就行,用STM32F4xx系列的芯片使用ARM_CM4F文件夹的文件就行,这里主要就是不同芯片移植主要的不同点之一。
到这里基本要移植需要的文件已经列举出来了。
本文采用的是MDK-ARM为编译环境,以STM32F103ZET6开发板为移植平台。先准备一个LED闪烁的基础工程。本文用的工程是以B站的江科大up主的基础模板,(只要你的工程可以点灯就行)使用的是标准库。当然,用标准库,寄存器或者HAL库都是可以的,移植和用那个库没有必要的联系,移植的过程是一样的。
基础工程的项目分组如下:
在基础工程的的文件夹下新建立一个FreeRTOS的文件夹。
将FreeRTOS源码文件夹下的Source文件夹下的全部文件复制到基础工程下新建的FreeRTOS文件夹下。
打开portable文件夹,只保留Keil,MenMang,RVDS这3个目录。
2.3 向工程中添加.c文件
点击3个小方块
这就是完整的项目工程,如果不会添加.c文件的请他其他文章。
点击魔术棒
在include paths配置头文件路径
FreeRTOS使用FreeRTOSConfig.h文件进行配置和裁剪。FreeRTOSConfig.h文件可以从下载的FreeRTOS源码G:\FreeRTOSv10.3.0\FreeRTOSv10.3.0\FreeRTOS\Demo\CORTEX_STM32F103_Keil示例程序中复制。
把FreeRTOSConfig复制到自己的FreeRTOS工程下的include目录下(复制到其他目录下也是可以的,但是要注意配置好头文件包含路径)
在stm32f1xx_it.c会生成SysTick,PendSV和SVC这3个中断服务函数,这3个中断服务函数已经在FreeRTOS中使用,会造成重复编译,所以我们要屏蔽点这3个中断服务函数。然后编译。
你应该会报一个错误
- .\stm32_freertos.axf: Error: L6218E: Undefined symbol xTaskGetCurrentTaskHandle (referred from stream_buffer.o).
解决办法是在FreeRTOS.h文件中的
- #ifndef INCLUDE_xTaskGetCurrentTaskHandle
- #define INCLUDE_xTaskGetCurrentTaskHandle 1
- #endif
把开始的0修改成1 这样就0警告0错误。
首先在main函数中包含FreeRTOS.h和task.h
- #include "FreeRTOS.h"
- #include "task.h"
3.1 编写测试任务函数
- static TaskHandle_t LedTaskHandle = NULL;//任务句柄
- //函数功能是让LED灯以1秒的间隔闪烁
- //形参pvParameters是创建该任务是传递的参数
- static void LedTask(void *pvParameters)
- {
- while(1)
- {
- LED_ON();
- Delay_ms(1000);
- LED_off();
- Delay_ms(1000);
- }
- }
-
-
-
- //---------------------------LED函数---------------------//
- void LED_init(void){
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
- GPIO_InitTypeDef GPIO_InitStruvture;
- GPIO_InitStruvture.GPIO_Mode=GPIO_Mode_Out_PP;
- GPIO_InitStruvture.GPIO_Pin=GPIO_Pin_2;
- GPIO_InitStruvture.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOA,&GPIO_InitStruvture);
-
-
- GPIO_SetBits(GPIOA,GPIO_Pin_2);
-
- }
- void LED_ON(){
-
- GPIO_ResetBits(GPIOA,GPIO_Pin_2);
-
- }
- void LED_off(){
-
- GPIO_SetBits(GPIOA,GPIO_Pin_2);
-
- }
创建任务函数的原型
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);
xTaskCreate(LedTask,"LedTask",128,NULL,4,&LedTaskHandle);
用vTaskStartScheduler()函数来开启调度器,正常情况下,函数不会执行到这语句的后面的代码。
- int main(void)
- {
-
- LED_init();
- xTaskCreate(LedTask,"LedTask",128,NULL,4,&LedTaskHandle);
-
- vTaskStartScheduler();
- //后面的while函数不会执行
- while(1)
- {
- }
- }
第一次下载程序可能LED不会闪烁,如何来排除问题的经验是很重要的,我们在开启任务调度的前面写一个打开灯的代码。
- int main(void)
- {
-
- LED_init();
- xTaskCreate(LedTask,"LedTask",128,NULL,4,&LedTaskHandle);
- LED_ON();
- vTaskStartScheduler();
- //后面的while函数不会执行
- while(1)
- {
- }
- }
会发现灯亮了,这就说明是卡死在 vTaskStartScheduler();这句代码。然后我们带着问题去百度。发现是ARM Cortex-M3,ARM Cortex-M4和ARM Cortex-M4F上的移植需要FreeRTOS处理安装的SysTick,PendSV和SVCCall中断向量,中断向量表可以分别直接使用FreeRTOS定义的xPortSysTickHandler(),xPortPendSVHandler()和vPortSVCHandler()三个函数。但是,如果中断向量表是与CMSIS兼容的话,用户需在FreeRTOSConfig.h中添加以下三行代码以使FreeRTOS和CMSIS中中断向量名字做映射。
解决方案是:
将下面的代码放到FreeRTOSConfig.h
- #define vPortSVCHandler SVC_Handler
- #define xPortPendSVHandler PendSV_Handler
- #define xPortSysTickHandler SysTick_Handler
-
-
下载后程序正是1秒的间隔闪烁,到此,FreeRTOS的移植完毕,后续将会继续编写有关FreeRTOS的小应用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。