FreeRTOS(基础)
FreeRTOS(基础)
- 基本概念
- ROTS
- 可剥夺内核
- 为什么学习FreeRtos
- FreeRTOS 特点
- FreeRTOS 任务状态
- FreeRTOS资料与源码下载
- FreeRTOS移植
- 1、添加 FreeRTOS 源码
- 2、向工程分组中添加文件
- 3、添加相应的头文件路径
- 4、修改 SYSTEM 文件
- 1、修改 sys.h 文件
- 2、修改 usart.c 文件
- 3、修改 delay.c 文件
- 任务动态创建
- 任务静态创建
基本概念
ROTS
RTOS全称:Real time OS,就是实时操作系统,强调的是:实时性。实时操作系统又分为软实时和硬实时。硬实时要求在规定时间内必须完成操作,硬实时不允许超时,软实时里面处理过程超时的后果就没有那么严格。
在实时操作系统中,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。
RTOS操作系统:FreeRTOS,UCOS,RTX,RT-THread,DJYOS等
RTOS操作系统的核心内容在于:实时内核。
可剥夺内核
RTOS的内核负责管理所有的任务,内核决定了运行那个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。多任务管理给人的感觉就是芯片有多个CPU,多任务管理实现了CPU资源的最大化利用,多任务管理有助于实现程序的模块化开发,能够实现复杂的实时利用。
可剥夺性内核顾名思义就是可以剥夺其他任务的CPU使用权,他总是运行就绪任务中优先级最高的任务。
为什么学习FreeRtos
1 因为Freertos开源
2 Freertos免费
3 Freertos是很多第三方组件钦定的系统
FreeRTOS 特点
FreeRTOS 是一个可裁剪的小型 RTOS 系统,其特点包括:
1 任务简单
2 任务没有数量使用限制
3 任务支持抢占
4 任务支持优先级
5 每个任务都拥有堆栈导致了RAM使用量大
6 如果使用抢占的话必须仔细考虑重入问题
FreeRTOS 任务状态
对于单内核的芯片而言,任一任务要么处于运行态,要么处于非运行态。但同一时刻只能有一个任务处于运行态。这也是为什么这个图中①画的任务框是多个叠起来的,而②所示的任务只有一个框的原因。
任务从非运行态转移到运行态被称为”切换入或切入(switched in)”或”交换入(swapped in)”。相反,任务从运行态转移到非运行态被称为”切换出或切出(switched
out)”或”交换出(swapped out)”。FreeRTOS 的调度器是能让任务切入切出的唯一实体。
那么事实上,对于非运行态其内部又被划分出了几个子状态:
挂起态
就绪态
阻塞态
僵尸态
FreeRTOS资料与源码下载
要找资料,官网是最好的地方,FreeRTOS的官网是www.freertos.org。
进入 FreeRTOS 首页,就会看到download下载链接,进入后下载“FreeRTOS 202112.00”文件
FreeRTOS移植
1、添加 FreeRTOS 源码
在基础工程中新建一个名为 FreeRTOS 的文件夹。创建FreeRTOS 文件夹以后就可以将 FreeRTOS 的源码添加到这个文件夹中,我们只需要留下 keil、MemMang 和 RVDS 这三个文件夹,其他的都可以删除掉。
2、向工程分组中添加文件
打开基础工程,新建分组 FreeRTOS_CORE 和 FreeRTOS_PORTABLE,然后向这两个分组中添加文件。
3、添加相应的头文件路径
添加完 FreeRTOS 源码中的 C 文件以后还要添加 FreeRTOS 源码的头文件路径,头文件路径
头文件路径添加完成以后编译一下,看看有没有什么错误,结果会发现提示打不开“FreeRTOSConfig.h”这个文件
打开FreeRTOS 针对 STM32F103 的移植工程文件,从例程中找到这个文件复制过来。
4、修改 SYSTEM 文件
1、修改 sys.h 文件
sys.h 文件修改很简单,在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS,
我们使用了 FreeRTOS,所以应该将宏 SYSTEM_SUPPORT_OS 改为 1。
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持OS
2、修改 usart.c 文件
一个是添加 FreeRTOS.h 头文件
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h" //FreeRTOS使用
#endif
另外一个就是 USART1 的中断服务函数,在使用 UCOS 的时候进出中断的时候需要添加OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉。
3、修改 delay.c 文件
delay.c 文件修改的就比较大了,因为涉及到 FreeRTOS 的系统时钟
1 在滴答定时器中断服务函数中调用FreeRTOS 的 API 函数 xPortSysTickHandler()。
extern void xPortSysTickHandler(void);
2 在基础例程中滴答定时器的时钟频率设置的是 AHB 的 1/8,这里为了兼容 FreeRTOS 将滴答定时器的时钟频率改为了 AHB,也就是 72MHz!
void delay_init()
{u32 reload;SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLKfac_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
}
3.delay_us()是 us 级延时函数,delay_ms 和 delay_xms()都是 ms 级的延时函数,delay_us()和delay_xms()不会导致任务切换。delay_ms()其实就是对 FreeRTOS 中的延时函数 vTaskDelay()的简单封装,所以在使用 delay_ms()的时候就会导致任务切换。
4 要将 stm32f10x_it.c 中的三个函数:滴答定时器中断服务函数、SVC 中断服务函数和 PendSV 中断服务函数屏蔽掉。
//void SVC_Handler(void)
//{//}void DebugMon_Handler(void)
{}//void PendSV_Handler(void)
//{//}
//
//void SysTick_Handler(void)
//{//}
任务动态创建
动态创建任务, 调用函数内部向系统申请创建新任务所需的内存,包括任务控制块和栈。 所以调用这个函数,在内存堆空间不足或者碎片话的情况下,可能创建新任务失败,需要判断函数执行后是否成功返回。
xTaskCreat();
vTaskDelete();
将 configSUPPORT_STATIC_ALLOCATION 宏设为0
#ifndef configSUPPORT_STATIC_ALLOCATION/* Defaults to 0 for backward compatibility. */#define configSUPPORT_STATIC_ALLOCATION 0
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"//开始任务
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t StartTask_Hander ;
void start_task( void * pvParameters );//Task1任务
#define TASK1_STK_SIZE 128
#define TASK1_TASK_PRIO 1
TaskHandle_t Task1Task_Handle ;
void task1_task( void * pvParameters );//Task2任务
#define TASK2_STK_SIZE 128
#define TASK2_TASK_PRIO 1
TaskHandle_t Task2Task_Handle ;
void task2_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,(char * ) "start_task",(uint32_t) START_STK_SIZE,(void * ) NULL,(UBaseType_t) START_TASK_PRIO,(TaskHandle_t *) &StartTask_Hander );vTaskStartScheduler(); //开启任务调度
}
void start_task( void * pvParameters )
{//创建开始任务1xTaskCreate( (TaskFunction_t) task1_task,(char * ) "task1_task",(uint32_t) TASK1_STK_SIZE,(void * ) NULL,(UBaseType_t) TASK1_TASK_PRIO,(TaskHandle_t *) &StartTask_Hander );//创建开始任务2xTaskCreate( (TaskFunction_t) task2_task,(char * ) "task2_task",(uint32_t) TASK2_STK_SIZE,(void * ) NULL,(UBaseType_t) TASK2_TASK_PRIO,(TaskHandle_t *) &StartTask_Hander );vTaskDelete(StartTask_Hander); //删除任务
}
void task1_task( void * pvParameters )
{/* 可以像普通函数一样定义变量。用这个函数创建的每个任务实例都有一个属于自己的task1_num变量。但如果task1_num被定义为static,这一点则不成立 – 这种情况下只存在一个变量,所有的任务实例将会共享这个变量。 */ char task1_num = 0;/* 任务通常实现在一个死循环中。 */while(1){/* 完成任务功能的代码将放在这里。 */if(task1_num == 6 ){printf("task1 run %d\r\n",task1_num);vTaskDelete(Task1Task_Handle);}task1_num++;LED1= ~LED1;vTaskDelay(1000);printf("task1 run %d\r\n",task1_num);}/* 如果任务的具体实现会跳出上面的死循环,则此任务必须在函数运行完之前删除。传入NULL参数表示删除的是当前任务 */ //vTaskDelete( NULL );
}void task2_task( void * pvParameters )
{char task2_num = 0;while(1){task2_num++;LED0 = ~LED0;vTaskDelay(1000);printf("task1 run %d\r\n",task2_num);}
}
任务静态创建
将 configSUPPORT_STATIC_ALLOCATION 宏设为1
#ifndef configSUPPORT_STATIC_ALLOCATION/* Defaults to 0 for backward compatibility. */#define configSUPPORT_STATIC_ALLOCATION 1
#endif
vApplicationGetIdleTaskMemory() 空闲任务所需内存
vApplicationGetTimerTaskMemory() 定时器所需内存
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"//开始任务
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
StackType_t StartTaskStack[START_STK_SIZE];
TaskHandle_t StartTask_Handle ;
StaticTask_t StartTaskTCB;
void start_task( void * pvParameters );//Task1任务
#define TASK1_STK_SIZE 128
#define TASK1_TASK_PRIO 1
StackType_t Task1TaskStack[TASK1_STK_SIZE];
TaskHandle_t Task1Task_Handle ;
StaticTask_t Task1TaskTCB;
void task1_task( void * pvParameters );//Task2任务
#define TASK2_STK_SIZE 128
#define TASK2_TASK_PRIO 1
StackType_t Task2TaskStack[TASK2_STK_SIZE];
TaskHandle_t Task2Task_Handle ;
StaticTask_t Task2TaskTCB;
void task2_task( void * pvParameters );//空闲任务
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
static StaticTask_t IdleTaskTCB;
//定时器任务
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
static StaticTask_t TimerTaskTCB;//空闲任务所需内存
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,StackType_t **ppxIdleTaskStackBuffer,uint32_t *pulIdleTaskStackSize )
{*ppxIdleTaskTCBBuffer = &IdleTaskTCB;*ppxIdleTaskStackBuffer = IdleTaskStack;*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;}//定时器所需内存
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize )
{*ppxTimerTaskTCBBuffer = &TimerTaskTCB;*ppxTimerTaskStackBuffer = TimerTaskStack;*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;}int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 delay_init(); //延时函数初始化 uart_init(115200); //初始化串口LED_Init(); //初始化LED//创建开始任务StartTask_Handle = xTaskCreateStatic( (TaskFunction_t) start_task,(char * ) "start_task",(uint32_t) START_STK_SIZE,(void * ) NULL,(UBaseType_t) START_TASK_PRIO,(StackType_t *) StartTaskStack,(StaticTask_t *) &StartTaskTCB );vTaskStartScheduler(); //开启任务调度
}
void start_task( void * pvParameters )
{//创建开始任务1Task1Task_Handle = xTaskCreateStatic( (TaskFunction_t) task1_task,(char * ) "task1_task",(uint32_t) TASK1_STK_SIZE,(void * ) NULL,(UBaseType_t) TASK1_TASK_PRIO,(StackType_t *) Task1TaskStack,(StaticTask_t *) &Task1TaskTCB );//创建开始任务2Task2Task_Handle = xTaskCreateStatic( (TaskFunction_t) task2_task,(char * ) "task2_task",(uint32_t) TASK2_STK_SIZE,(void * ) NULL,(UBaseType_t) TASK2_TASK_PRIO,(StackType_t *) Task2TaskStack,(StaticTask_t *) &Task2TaskTCB );vTaskDelete(StartTask_Handle); //删除任务
}
void task1_task( void * pvParameters )
{char task1_num = 0;while(1){if(task1_num == 6 ){printf("task1 run %d\r\n",task1_num);vTaskDelete(Task1Task_Handle);}task1_num++;LED1= ~LED1;vTaskDelay(1000);printf("task1 run %d\r\n",task1_num);}
}void task2_task( void * pvParameters )
{char task2_num = 0;while(1){task2_num++;LED0 = ~LED0;vTaskDelay(1000);printf("task1 run %d\r\n",task2_num);}
}
FreeRTOS(基础)相关推荐
- FreeRTOS基础以及UIP之协程--C语言剑走偏锋
在FreeRTOS中和UIP中,都使用到了一种C语言实现的多任务计数,专业的定义叫做协程(coroutine),顾名思义,这是一种协作的例程, 跟具有操作系统概念的线程不一样,协程是在用户空间利用程序 ...
- FreeRTOS基础(二):STM32G4系列运行FreeRTOS驱动8路PWM波控制多个路舵机
一.TIM2和TIM3配置,基于STM32CubeMX HCLK主时钟配置成72MHz 二.8路PWM初始化配置,50Hz PWM输出 注意:添加启动命令 /* TIM2 init function ...
- FreeRTOS及其应用,万字长文,基础入门
嵌入式系统不只是ARM+Linux,不是只有安卓,凡是电子产品都可称为嵌入式系统.物联网行业的兴起,也提升了FreeRTOS市场占有率.本文就是介绍FreeRTOS基础及其应用,只是个人整理,可能存在 ...
- freeRTOSConfig.h文件对FreeRTOS进行系统配置
FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制.每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核.这个配置文件是针 ...
- 【STM32】FreeRTOS系统配置
00. 目录 文章目录 00. 目录 01. 概述 02. FreeRTOS配置文件 03. INCLUDE开始的宏 04. config开始的宏 05. 其它 06. 附录 07. 参考 01. 概 ...
- 2.STM32F407ZGT6 学习笔记-移植 FreeRTOS
程序移植的代码: https://gitee.com/chejia12/free-rtos_-f407.git 1. 在工程下建议FreeRTOS文件夹 2. 在FreeRTOS文件夹下建立 src ...
- FM33LC02X FreeRTOS MDK 移植记录总结
文章目录 Demo下载 1.获取FreeRTOS源码 2.代码移植 3.工程配置 4.修错改错 5.中断链接 6.运行代码 7.使用案例 8.后续调试 8.1 OS vTaskDelay延时函数不准问 ...
- FreeRTOS——静态与动态内存分配
FreeRTOS 基础系列文章 基本对象 FreeRTOS--任务 FreeRTOS--队列 FreeRTOS--信号量 FreeRTOS--互斥量 FreeRTOS--任务通知 ...
- FreeRTOS之freeconfig.c(S32k144)
#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H#include "sys.h" #include "usart.h ...
- FreeRTOS——软件计时器
FreeRTOS 基础系列文章 基本对象 FreeRTOS--任务 FreeRTOS--队列 FreeRTOS--信号量 FreeRTOS--互斥量 FreeRTOS--任务通知 ...
最新文章
- 为什么说Java是2021年最值得学的技术?
- 方法重写(override)注意事项和使用细节
- 一个html有几个css,几个CSS的黑科技_html/css_WEB-ITnose
- 使用fastjson进行json字符串和List的转换
- LeetCode 2169. 得到 0 的操作数
- 【Excel】函数DateDif查看两个日期之间的间隔
- 灵魂拷问,SQL 查询语句先执行 SELECT吗?
- 【Kettle】血统分析
- c 语言min max 归一化,归一化方法 Normalization Method
- 各个领域中的经典论文,看看你都读过哪些 - 易智编译EaseEditing
- Vue3中的setup前加上async后页面不显示
- html超链接并可以返回,返回到上一页的html代码的几种写法
- 骨骼的动作识别数据集_基于骨骼数据的人体行为识别
- 计算机视觉(CV)领域的公司
- echarts案例大全,echarts的Demo网站有哪些
- java中用swing做一个windows计算器
- mysql中图书编号类型,数据库课后习题参考答案
- c语言计次循环首,【图片】今天写几个性能测试,为什么C语言跑得这么慢呢??【c语言吧】_百度贴吧...
- 2022-2028年中国网红电商行业市场调查研究及投资策略研究报告
- echarts 其他样式 折线 重叠_Vue + echarts 折线图各种样式设置