最近按照正点原子教程开始学习FreeRTOS,发现其手册的移植教程中有些地方可能不是那么详细,在此基于正点原子做一期最完整的FreeRTOS移植教程给大家。
小b将本次教程整理的资料放在网盘,以下链接供各位小伙伴下载和学习: 链接:https://pan.baidu.com/s/1z74dzFtQ198XLJwYhOVWlw 提取码:rson
-
打开FreeRTOS.exe文件,等待些许时间获取FreeRTOS源码 -
拷贝库函数一个最简单的跑马灯实验工程作为待移植工程文件,并在基础工程中新建一个名为 FreeRTOS 的文件夹 -
创建FreeRTOS文件夹之后将步骤1获取到的FreeRTOS文件下的FreeRTOSv9.0.0->FreeRTOS->Source中的全部文件全部拷贝到创建文件夹下 -
其中为了工程轻简,protable文件夹下只留下以下三个文件夹: -
用keil打开工程文件,点击所示图标新建两个分组FreeRTOS_CORE 和 FreeRTOS_PORTABLE -
创建成功后左边工程栏出现对应两个分组,双击添加对应的文件如下图所示,其中FreeRTOS_CORE中的文件为源码直接打开可看到的.c文件,FreeRTOS_PORTABLE中的文件为port.c 是 RVDS 文件 夹下的 ARM_CM3 中的文件,因为 STM32F103 是 Cortex-M3 内核的,因此要选择 ARM_CM3 中的 port.c 文件,heap_4.c 是 MemMang 文件夹中的,因为heap_4 提供了一个最优的匹配算法,选择heap_4相关API进行内存管理。 -
添加完FreeRTOS源码中的.c文件,接下来添加相应头文件的路径。点击如下图标进行设置: -
编译,发现缺少FreeRTOSConfig.h,他是FreeRTOS 的配置文件,一般的操作系统都有裁剪、配置功能,而这些裁剪及配置都是通过一个文件来完成的,基本都是通过宏定 义来完成对系统的配置和裁剪的。可以到FreeRTOS的demo里面相关的,但是不同硬件和环境配置不同,本操作采用正点原子的板子,直接拷贝一份正点原子STM32的FreeRTOSConfig.h到FreeRTOS的include目录下,再次进行编译 -
编译结果有错误,打开USER的system_stm32f0x_it.c,将以下报错两个函数屏蔽掉,编译成功 -
修改sys.h文件 在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS, 我们使用了 FreeRTOS,所以应该将宏 SYSTEM_SUPPORT_OS 改为 1。 -
更改delay.c delay.c需要修改比较多地方 函数 SysTick_Handler():
extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)
{
xPortSysTickHandler();
}
}
delay_init()函数:
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
fac_us=SystemCoreClock/1000000;
reload=SystemCoreClock/1000000;
reload*=1000000/configTICK_RATE_HZ;
fac_ms=1000/configTICK_RATE_HZ;
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;
SysTick->LOAD=reload;
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;
}
剩下三个函数都是延时函数:
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD;
ticks=nus*fac_us;
told=SysTick->VAL;
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow;
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break;
}
};
}
void delay_ms(u32 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)
{
if(nms>=fac_ms)
{
vTaskDelay(nms/fac_ms);
}
nms%=fac_ms;
}
delay_us((u32)(nms*1000));
}
void delay_xms(u32 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(1000);
}
注意:delay_ms函数改完之后和头文件声明的不对应,需要到头文件delay.h更改下u16改成u32
最后,不要忘记将”includes.h”换成头文件”FreeRTOS.h”,并添加其他头文件如下图所示 其他无关的程序如:
#if SYSTEM_SUPPORT_OS
#ifdef OS_CRITICAL_METHOD
...
OSTimeDly(ticks);
#endif
}
都可以删掉了。
- 更改usart.c
usart.c 文件有两部分要修改,一个是添加 FreeRTOS.h 头文件, 默认是添加的 UCOS 中的 includes.h 头文件,修改以后如下: 另外一个就是 USART1 的中断服务函数,在使用 UCOS 的时候进出中断的时候需要添加 OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉,修改 以后如下:
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);
if((USART_RX_STA&0x8000)==0)
{
if(USART_RX_STA&0x4000)
{
if(Res!=0x0a)USART_RX_STA=0;
else USART_RX_STA|=0x8000;
}
else
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
}
}
}
}
}
- 直接将以下代码替换到main.c中的全部程序,编译烧录到板子中,有跑马灯现象证明成功。(本次实验使用的是战舰版,如果使用其他板可能需要稍作调整)
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#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);
delay_init();
uart_init(115200);
LED_Init();
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();
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);
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();
}
void led0_task(void *pvParameters)
{
while(1)
{
LED0=~LED0;
vTaskDelay(500);
}
}
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
学完有收获的小伙伴不妨点个赞支持一下小b呀~
|