环境:keil5;
平台:STM32F103;
freertos源码:FreeRTOSv9.0.0版本
移植前准备:自己新建一个工程,用于freertos移植基础;
一:打开基础工程,确保基础工程编译没错;
二:在基础工程目录下新建“FreeRtos”文件夹,用于存放freertos相关文件;
三:在"FreeRtos"目录下新建“include”和“portable”文件夹,用于存放freertos头文件和接口文件;
四:添加源码;
①:找到官网下载的源码,找到“FreeRTOSv9.0.0\FreeRTOS\Source\include”目录下的头文件,全部复制到我们第三步新建的“include”文件夹下;
②:复制“Memmang”和“RVDS”文件到我们第三步新建的“portable”文件夹中,然后再 裁剪文夹容(F103是M3的内核,所以RVDS文件下 可以只要“ARM_CM3”的文件);
③:将“\FreeRTOSv9.0.0\FreeRTOS\Source”目录下的“.c”文件复制到我们自己建 的“FreeRtos”目录下;
④:到freertos官方源码下的Demo目录下找到我们的F103_keil工程,找到“FreeRtosconfig…h”文件,将这个文件复制到我们的“USER”目录下(也可以找到野火或者正点原子的头文件,里面注释分类都做的比较完善);
五:在工程中添加文件;
①:在工程中添加分组,并添加文件到分组;
②:添加路径;
③:编译测试看是否通过;
六:测试移植是否成功;
①:打开"FreeRtosconfig.h"文件添加SVC和pendsv中断宏定义,不然port.c中的函数无法找到中断(如果此时在“USER”目录下找不到"FreeRtosconfig.h"文件,则手动添加文件到“USER”目录中);
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
②:修改stm32f10x_it.c文件:屏蔽svc和pend中断,修改滴答定时器中中断,添加头文件;
//在stm32f10x_it.c添加头文件
#include "FreeRTOS.h"
#include "task.h"
.....
//修改滴答定时器中断
extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
③:编译查看提示,显示未定义函数,修改宏定义即可;
#define INCLUDE_xTaskGetSchedulerState 1//将宏值改为1
④:新建任务,在开发板上通过两个led的闪烁间隔不同判断移植是否成功;
结果:本实验在开发板上可以看到LED0现象为500ms亮一次,LED1为一秒钟亮一次,实验表明移植成功;
逻辑分析仪抓取截图:
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#define TASK1_PRIO 1 //任务优先级
#define TASK1_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void task1(void *pvParameters); //任务函数
#define TASK2_PRIO 1 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask2_Handler; //任务句柄
void task2(void *pvParameters); //任务函数
volatile uint8_t task1_flag=0;
volatile uint8_t task2_flag=0;
void LED_Init(void);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
//初始化io口
LED_Init();
//创建开始任务
xTaskCreate((TaskFunction_t )task1, //任务函数
(const char* )"task11", //任务名称
(uint16_t )TASK1_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )TASK1_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
xTaskCreate((TaskFunction_t )task2, //任务函数
(const char* )"task22", //任务名称
(uint16_t )TASK2_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )TASK2_PRIO, //任务优先级
(TaskHandle_t* )&StartTask2_Handler); //任务句柄
vTaskStartScheduler();
while(1)
{
}
}
//task2任务LED0(PB5)每500ms亮一次
void task1(void *pvParameters)
{
while(1)
{
task1_flag=1;
GPIOB‐>BRR=GPIO_Pin_5;//LED0亮
vTaskDelay(500);
task1_flag=0;
GPIOB‐>BSRR=GPIO_Pin_5;//LED0灭
vTaskDelay(500);
}
}
//task2任务LED1(PE5)每一秒钟亮一次
void task2(void *pvParameters)
{
while(1)
{
task2_flag=1;
GPIOE‐>BSRR=GPIO_Pin_5;//LED1灭
vTaskDelay(1000);
task2_flag=0;
GPIOE‐>BRR=GPIO_Pin_5;//LED1亮
vTaskDelay(1000);
}
}
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0‐‐>PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1‐‐>PE.5 端口配置, 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
}
七:注意事项;
我刚开始准备在keil中用keil自带的模拟器验证移植是否成功,但是可能由于自己新建工程有些许瑕疵,遇到了如下问题,记录如下:
①:新建工程时编译有问题,报错提示:“…/CMSIS/core_cm3.c(445): error: non-ASM statement in naked function is not supported”
原因:KEIL5版本更新了的缘故,使用了keil5默认的版本6的编译器,而固件库还 是支持版本5的编译器;
解决方法:将编译器修改成版本5就好了;
②:移植好freertos后,采用keil软件方式模拟,代码一直卡在“SetSysClockTo72”,运行不到main函数处;
原因:KEIL中DEBUG设置不对;
解决方法:
③:当更改DEBUG选项后测试,发现调试时一直报错:“*** error 65: access violation at 0x0000000C : no ‘read’ permission”
解决方法:
Option->Debug->Use_Simulator->Initialization_File,打开并新建一个.ini文件,里面写上map 0x40000000,0x400FFFFF read write保存即可(MAP不区分大小写,注意read和write中间是空格不是逗号),然后运行DEBUG就可以了,我按照此方法报错问题就解决了。
参考了解:https://blog.youkuaiyun.com/Maple_Leaf_15/article/details/51057991
④:当可以正常软件仿真时,打断点发现代码一直可以运行到task1和task2处,但是keil自带的逻辑分析仪上却没有变量的波形,这个问题目前也没有解决,但是在板子上跑现象是正常的,逻辑分析仪抓取也是正常的,所以可能是我自己建的工程有瑕疵,导致软件仿真的逻辑分析仪有问题。
本文章是记录自己的学习记录·,方便后续自己复习。