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(基础)相关推荐

  1. FreeRTOS基础以及UIP之协程--C语言剑走偏锋

    在FreeRTOS中和UIP中,都使用到了一种C语言实现的多任务计数,专业的定义叫做协程(coroutine),顾名思义,这是一种协作的例程, 跟具有操作系统概念的线程不一样,协程是在用户空间利用程序 ...

  2. FreeRTOS基础(二):STM32G4系列运行FreeRTOS驱动8路PWM波控制多个路舵机

    一.TIM2和TIM3配置,基于STM32CubeMX HCLK主时钟配置成72MHz 二.8路PWM初始化配置,50Hz PWM输出 注意:添加启动命令 /* TIM2 init function ...

  3. FreeRTOS及其应用,万字长文,基础入门

    嵌入式系统不只是ARM+Linux,不是只有安卓,凡是电子产品都可称为嵌入式系统.物联网行业的兴起,也提升了FreeRTOS市场占有率.本文就是介绍FreeRTOS基础及其应用,只是个人整理,可能存在 ...

  4. freeRTOSConfig.h文件对FreeRTOS进行系统配置

    FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制.每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核.这个配置文件是针 ...

  5. 【STM32】FreeRTOS系统配置

    00. 目录 文章目录 00. 目录 01. 概述 02. FreeRTOS配置文件 03. INCLUDE开始的宏 04. config开始的宏 05. 其它 06. 附录 07. 参考 01. 概 ...

  6. 2.STM32F407ZGT6 学习笔记-移植 FreeRTOS

    程序移植的代码: https://gitee.com/chejia12/free-rtos_-f407.git 1. 在工程下建议FreeRTOS文件夹 2. 在FreeRTOS文件夹下建立 src ...

  7. FM33LC02X FreeRTOS MDK 移植记录总结

    文章目录 Demo下载 1.获取FreeRTOS源码 2.代码移植 3.工程配置 4.修错改错 5.中断链接 6.运行代码 7.使用案例 8.后续调试 8.1 OS vTaskDelay延时函数不准问 ...

  8. FreeRTOS——静态与动态内存分配

    FreeRTOS 基础系列文章  基本对象   FreeRTOS--任务   FreeRTOS--队列   FreeRTOS--信号量   FreeRTOS--互斥量   FreeRTOS--任务通知 ...

  9. FreeRTOS之freeconfig.c(S32k144)

    #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H#include "sys.h" #include "usart.h ...

  10. FreeRTOS——软件计时器

    FreeRTOS 基础系列文章  基本对象   FreeRTOS--任务   FreeRTOS--队列   FreeRTOS--信号量   FreeRTOS--互斥量   FreeRTOS--任务通知 ...

最新文章

  1. 为什么说Java是2021年最值得学的技术?
  2. 方法重写(override)注意事项和使用细节
  3. 一个html有几个css,几个CSS的黑科技_html/css_WEB-ITnose
  4. 使用fastjson进行json字符串和List的转换
  5. LeetCode 2169. 得到 0 的操作数
  6. 【Excel】函数DateDif查看两个日期之间的间隔
  7. 灵魂拷问,SQL 查询语句先执行 SELECT吗?
  8. 【Kettle】血统分析
  9. c 语言min max 归一化,归一化方法 Normalization Method
  10. 各个领域中的经典论文,看看你都读过哪些 - 易智编译EaseEditing
  11. Vue3中的setup前加上async后页面不显示
  12. html超链接并可以返回,返回到上一页的html代码的几种写法
  13. 骨骼的动作识别数据集_基于骨骼数据的人体行为识别
  14. 计算机视觉(CV)领域的公司
  15. echarts案例大全,echarts的Demo网站有哪些
  16. java中用swing做一个windows计算器
  17. mysql中图书编号类型,数据库课后习题参考答案
  18. c语言计次循环首,【图片】今天写几个性能测试,为什么C语言跑得这么慢呢??【c语言吧】_百度贴吧...
  19. 2022-2028年中国网红电商行业市场调查研究及投资策略研究报告
  20. echarts 其他样式 折线 重叠_Vue + echarts 折线图各种样式设置

热门文章

  1. 编辑PDF文件的两种方法
  2. Webpack详细打包步骤
  3. 虚拟主播怎么做出来的?建议收藏这些方法
  4. 航天信息: 打造政企服务体系
  5. iOS - 直播流程,视频推流,视频拉流,简介,SMTP、RTMP、HLS、 PLPlayerKit
  6. 谷歌浏览器设置自动播放视频(转)
  7. 关于push数组,然后遍历数组遇到的坑,遍历显示函数
  8. Replica Island 学习笔记 03 - Activity分析
  9. IHS 负载均衡配置
  10. SpringBoot扩展机制——spring factories