FreeRTOS实时操作系统
简介
RTOS 全称是 Real Time Operating System,FreeRTOS是一个免费的 RTOS 类系统,还有其他种类的实时操作系统,例如 UCOS,UCOSII,RTX,RT-Thread 等;FreeRTOS的体量相对其他RTOS要小很多,这也造就了它可以在很多小容量的MCU中运行。
再来说一下实时操作系统:FreeRTOS是软实时操作系统,通过配置去控制有多任务且具有不同优先级的进程线。
定义:
当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统做出快速响应,调度一切可利用的资源完成实时任务,并控制所有实时任务协调一致运行的操作系统。提供及时响应和高可靠性是其主要特点。
实时操作系统特点:
1.高精度计时系统:
实时应用系统中,需要精确确定实时地操作某个设备或执行某个任务,或精确的计算一个时间函数。所以高精度计时是必要的。
2.多级中断机制:
多任务与外部设备关联,系统需要去响应外部的信息或事件,根据优先级的不同建立多级中断嵌套处理机制,以确保对紧迫程度较高的实时事件进行及时响应和处理。
3.实时调度机制:
在不同时间节点上需要去运行不同的实时任务,需要对进程进行切换;调度策略和算法上保证优先调度实时任务;二是建立更多“安全切换”时间点,保证及时调度实时任务。
需要了解的概念:
代码临界段
资源与共享资源
任务与任务切换
内核与内核调度
优先级
互斥
中断响应时间
FreeRTOS的特点:
1.FreeRTOS的内核支持抢占式,合作式和时间片调度
2.用于低功耗的 Tickless模式
3.系统的组件在创建时可以选择动态或者静态的 RAM
4.FreeRTOS系统简单、小巧、易用,大概占用4~9K空间
5.任务与任务、任务与中断之间可以使用任务通知、消息队列、二值信号量、数值型信 号量、递归互斥信号量和互斥信号量进行通信和同步
6.具有优先级继承特性的互斥信号量
7.高效的软件定时器
8.强大的跟踪执行功能
9.堆栈溢出检测功能
10.任务数量与优先级不限
下载源码准备移植(这里以STM32F1为例)
Demo中有针对不同MCU有对应的例程,可以提供参考
Source中的文件就是我们要进行移植的源码了
在我们已有的一个工程文件下加入FreeRTOS文件
按源码的文件copy过来
理所当然include放头文件啦
接下来对portable中的文件提炼一下
为啥留这三个呢?
Keil是因为我们用keil来编程,但你会发现Keil中的是指向了RVDS,你用其他的例如IAR,GCC你就要用对应的配置文件了,这很好理解。
MemMang中是五种不同的内存管理方法,根据需要进行选择
RVDS是存放ARM系列的内核的。
新建好工程文件
添加.c和.h文件
编译后发现缺失文件
这个文件咱可以在对应的MCU和编译软件例程中拖过来直接使用。
编译后的又一个问题
Undefined symbol xTaskGetCurrentTaskHandle (referred from stream_buffer.o).
解决方法是在官方提供的FreeRTOS.h文件中找到这个条件编译
#ifndef INCLUDE_xTaskGetCurrentTaskHandle
#define INCLUDE_xTaskGetCurrentTaskHandle 0
#endif
把这里的0改为1
这样就把所有的文件都添加好了,但还需要对文件更改一下
增加一个条件编译
#define SYSTEM_SUPPORT_OS 1
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h" //os 使用
#endif
FreeRTOS 的心跳由滴答定时器产生,根据 FreeRTOS 的系统时钟节拍设置好滴答定时器的周期,这样就会周期触发滴答定时器中断。在滴答定时器中断服务函数中调用FreeRTOS 的 API 函数 xPortSysTickHandler()。
SYSTICK 的时钟频率直接用AHB 的频率
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //选择外部时钟HCLK
fac_us=SystemCoreClock/1000000; //不论是否使用 OS,fac_us 都需要使用
reload=SystemCoreClock/1000000; //每秒钟的计数次数 单位为 M
reload*=1000000/configTICK_RATE_HZ; //根据 configTICK_RATE_HZ 设定溢出
//时间 reload 为 24 位寄存器,最大值:
//16777216,在 72M 下,约合 0.233s 左右
fac_ms=1000/configTICK_RATE_HZ; //代表 OS 可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启 SYSTICK 中断
SysTick->LOAD=reload; //每 1/configTICK_RATE_HZ秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK
}
中断配置
extern void xPortSysTickHandler(void);
//systick 中断服务函数,使用 OS 时用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
延时函数
//这个延时ms不会引起任务调度
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //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; //时间超过要延迟的时间,则退出.
}
}
}
//这个延时ms会引起任务调度
void delay_ms(u32 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
if(nms>=fac_ms) //延时的时间大于 OS 的最少时间周期
{
vTaskDelay(nms/fac_ms); //FreeRTOS 延时
}
nms%=fac_ms; //OS 已经无法提供这么小的延时了,
//采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时
}
//这个延时ms不会引起任务调度
void delay_xms(u32 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(1000);
}
SysTick_Handler()、SVC_Handler()和 PendSV_Handler(),这三个函数分别为滴答定时器中断服务函数、SVC 中断服务函数和 PendSV 中断服务函数,与stm32f10x_it.c 中的三个函数重定义了,所以将32里面的屏蔽掉
到这里就移植完成,这是针对32的移植,其他的大同小异,如果有问题就根据实际情况去修改