文中所用到的资料下载地址 https://download.csdn.net/download/qq_20222919/87370679
最近看正点原子新录制了手把手教你学FreeRTOS的视频教程,看了一下教程发现视频里面讲的是使用HAL移植 FreeRTOS V10.4.6 版本,以前的标准库移植的是FreeRTOS V9.0 版本。而自己平时写代码使用的都是标准库,就想着能不能把FreeRTOS V10.4.6 版移植到标准库中去。
为了移植简单,直接下载正点原子的代码在上面修改。实现思路为,下载一个标准库函数的FreeRTOS V9.0版的程序,然后在下载一个HAL库函数的FreeRTOS V10.4.6 版的程序,然后将HAL库函数中FreeRTOS 相关代码直接拷贝到标准库函数中替换FreeRTOS相关代码。
准备资料
首先去正点原子网站上下载源码,下载mini开发板和战舰开发板的资料。
mini开发板里面有标准库函数的FreeRTOS代码,战舰开发板里面有HAL库函数的FreeRTOS代码。
下载mini开发板资料,在mini开发板中找到扩展程序,在里面打开FreeRTOS例程,复制第一个程序到桌面。
将文件夹重命名为FreeRTOS_demo
随便打开一个FreeRTOS相关的文件,可以看到这个FreeRTOS的版本为V9.0
下载战舰开发板资料,在战舰开发板中找到扩展程序,在里面打开FreeRTOS例程,一会要用到这些程序里面FreeRTOS相关代码。
随便打开一个FreeRTOS相关的文件,可以看到这个FreeRTOS的版本为V10.4.6
开始移植
删除main函数中无用代码
准备工作已经完成了,下面开始移植。打开桌面上FreeRTOS_demo工程。
编译工程,确保工程文件的正确,接下来删除main文件中和FreeRTOS相关的代码和头文件。
删除前代码如下:
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "FreeRTOS.h"
#include "task.h"
/************************************************ALIENTEK Mini STM32F103开发板 FreeRTOS实验2-1FreeRTOS移植实验-库函数版本技术支持:www.openedv.com淘宝店铺:http://eboard.taobao.com 关注微信公众平台微信号:"正点原子",免费获取STM32资料。广州市星翼电子科技有限公司 作者:正点原子 @ALIENTEK
************************************************///任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define LED0_TASK_PRIO 2
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);//任务优先级
#define LED1_TASK_PRIO 3
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 delay_init(); //延时函数初始化 uart_init(115200); //初始化串口LED_Init(); //初始化LED//创建开始任务xTaskCreate((TaskFunction_t )start_task, //任务函数(const char* )"start_task", //任务名称(uint16_t )START_STK_SIZE, //任务堆栈大小(void* )NULL, //传递给任务函数的参数(UBaseType_t )START_TASK_PRIO, //任务优先级(TaskHandle_t* )&StartTask_Handler); //任务句柄 vTaskStartScheduler(); //开启任务调度
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区//创建LED0任务xTaskCreate((TaskFunction_t )led0_task, (const char* )"led0_task", (uint16_t )LED0_STK_SIZE, (void* )NULL, (UBaseType_t )LED0_TASK_PRIO, (TaskHandle_t* )&LED0Task_Handler); //创建LED1任务xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}//LED0任务函数
void led0_task(void *pvParameters)
{while(1){LED0=~LED0;vTaskDelay(500);}
} //LED1任务函数
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}
删除后代码如下:
#include "led.h"
#include "delay.h"
#include "sys.h"
/************************************************ALIENTEK Mini STM32F103开发板 FreeRTOS实验2-1FreeRTOS移植实验-库函数版本技术支持:www.openedv.com淘宝店铺:http://eboard.taobao.com 关注微信公众平台微信号:"正点原子",免费获取STM32资料。广州市星翼电子科技有限公司 作者:正点原子 @ALIENTEK
************************************************/
int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 delay_init(); //延时函数初始化 LED_Init(); //初始化LED
}
再次编译工程,确保代码没有错误。
替换FreeRTOS文件
接下来替换FreeRTOS相关文件。将FreeRTOS_demo工程中FreeRTOS文件夹中的所有文件全部删除。
删除FreeRTOS V9.0 所有文件
接下来打开战舰资料中的FreeRTOS例程。文件目录为:【正点原子】战舰STM32F103开发板V4 资料盘(A盘)\4,程序源码\3,扩展例程\2,FreeRTOS例程\FreeRTOS实验例程2 FreeRTOS移植实验\Middlewares\FreeRTOS
打开FreeRTOS这个文件夹,将里面所有的文件复制到FreeRTOS_demo工程中FreeRTOS文件夹中。
复制初始化和配置文件
接下来将 战舰STM32F103开发板V4 资料盘(A盘)\4,程序源码\3,扩展例程\2,FreeRTOS例程\FreeRTOS实验例程2 FreeRTOS移植实验\User 文件夹中freertos_demo.c、freertos_demo.h、FreeRTOSConfig.h
这三个文件复制到 FreeRTOS_demo这个工程的USER文件夹中。
修改代码
打开 FreeRTOS_demo工程,可以看到此时FreeRTOS的版本已经成功替换为 V10.4.6版本了。
将freertos_demo.c文件添加到USER文件夹中
在main函数中添加 freertos_demo.h
头文件,在初始化代码中添加freertos_demo();
函数。
调试编译工程
将工程文件全部编译,此时工程里面出现了好多错误。
双击错误提示,跳转到代码中。
这里主要是头文件的路径错误,将sys.h 和 usart.h前面的路径删除掉,再次编译。
此时编译错误减少了,但是还有一个led.h的路径错误。双击错误提示,跳转到文件中。
这个freertos_demo.c文件中是FreeRTOS任务相关的代码,正点原子的示例中用到了液晶屏和LED灯,在这里删除液晶屏相关代码,只保留LED灯相关代码。同时要修改LED头文件路径。
删除文件中LCD相关的代码
修改LED相关代码,修改后代码如下:
#include "freertos_demo.h"
#include "usart.h"
#include "led.h"/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 *//* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 *//* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler; /* 任务句柄 */
void task2(void *pvParameters); /* 任务函数 *//******************************************************************************************************//*** @brief FreeRTOS例程入口函数* @param 无* @retval 无*/
void freertos_demo(void)
{xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */(const char* )"start_task", /* 任务名称 */(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */(void* )NULL, /* 传入给任务函数的参数 */(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */vTaskStartScheduler();
}/*** @brief start_task* @param pvParameters : 传入参数(未用到)* @retval 无*/
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); /* 进入临界区 *//* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char* )"task1",(uint16_t )TASK1_STK_SIZE,(void* )NULL,(UBaseType_t )TASK1_PRIO,(TaskHandle_t* )&Task1Task_Handler);/* 创建任务2 */xTaskCreate((TaskFunction_t )task2,(const char* )"task2",(uint16_t )TASK2_STK_SIZE,(void* )NULL,(UBaseType_t )TASK2_PRIO,(TaskHandle_t* )&Task2Task_Handler);vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL(); /* 退出临界区 */
}/*** @brief task1* @param pvParameters : 传入参数(未用到)* @retval 无*/
void task1(void *pvParameters)
{while(1){ LED0=!LED0; /* LED0闪烁 */vTaskDelay(100); /* 延时1000ticks */}
}/*** @brief task2* @param pvParameters : 传入参数(未用到)* @retval 无*/
void task2(void *pvParameters)
{while(1){LED1=!LED1;vTaskDelay(200); /* 延时1000ticks */}
}
修改完成后再次编译工程,这时还有一个错误。
双击错误提示,定位到代码中。
错误提示声明语句不能出现在可执行语句之后。将这行代码移动到函数开始位置处。再次编译工程。
这时候工程0错误,0警告。
下载验证
在工程中可以看到正点原子的这个芯片用的是103RC系列的芯片,LED口为PA8和PD2口,如果自己有板子的话就可以下载程序验证了。
电路板运行效果
示波器测量LED波形。
通过示波器波形可以看出,一个LED100ms闪烁一次,一个LED200ms闪烁一次。和代码中设置的一样,说明程序功能正常。FreeRTOS的移植已经成功了。
将工程移植到其他型号MCU上
这个工程用只能用到STM32F103RC系列的MCU上,但是我们自己不一定都用的是这个系类的MCU,如果我们用的是其他系列的MCU,那么此时还需要将次工程移植到我们自己的MCU上去。
下面就将这个工程移植到STM32F103C8T6芯片上去,首先将刚才的工程复制一份,并重命名。
将工程重命名为 FreeRTOS_demo_103C8T6,打开工程。
修改单片机型号
单击魔术棒按钮,选择Device选项,将单片机型号选为STM32F103C8
修改单片机类型
由于STM32F103C8系列MCU是中等容量单片机,而工程默认的STM32F103RC系列MCU是大容量单片机,这里要在C/C++ 选项中将单片机宏定义的类型修改为STM32F10X_MD
修改下载文件
选择debug选项,单击setting按钮,打开Flash Download 选项,选择这个512K的下载文件,然后单击Remove按钮,将默认的这个下载文件删除掉。
单击Add按钮,添加新的下载文件。
选择第一个128K的这个文件,然后单击下面Add按钮。
此时新的下载文件就添加进来了,单击最下面的确定按钮。
接着单击下面的OK按钮,保存设置。
替换启动文件
在工程中CORE文件夹中的 startup_stm32f10x_hd.s
文件上单击鼠标右键,选择第二个删除当前文件。这个启动文件是大容量单片机的启动文件,需要将它替换为中等容量单片机的启动文件。
在弹出的对话框中选择是
在CORE文件夹上单击鼠标右键选择第三个选项,添加存在的文件到CORE分组中。
打开当前项目中的CORE文件夹。
选择文件夹中的 startup_stm32f10x_md.s
文件,然后单击Add按钮,然后关闭窗口。
此时启动文件就替换完成了。
编译下载
编译工程
没有错误和警告,但是此时还不能直接下载,因为这个项目的的LED的端口是PA8和PD2,而STM32F103C8T6这个MCU没有PD2端口,所以还需要修改LED文件。
将LED端口初始化代码中的PD2端口修改为PC13,同时将时钟初始的PD口改为PC口。
修改led.h头文件中的宏定义
将头文件中的LED1修改为PC13,然后编译下载代码。
电路板运行效果
示波器测量LED波形
通过示波器波形可以看出,一个LED灯每隔100ms闪烁一次,一个LED每隔200ms闪烁一次。说明程序已经正常运行了。
到此为止,在标准库代码上移植FreeRTOS V10.4.6系统,和不同型号MCU的工程移植就全部完成了。