RTOS入门
RTOS是什么?
RTOS是一款操作系统,相当于Windows\Linux
分为ucos FreeRTOS RT-Thread LiteOS
比裸机开发的优势在于,多任务系统,不必串行
临界区
- 临界区就是一段执行时不可被打断的代码
- 操作全局变量不可被打断
- 临界区的不可被打断机制,导致他不能运行太久,否则会阻塞程序
目录结构
源码放在FreeRTOS/Source文件夹下
- portable是需要特殊处理适配的
- include是包含的头文件
代码规范
数据结构
对常见的c语言数据结构重定义
1. #define portCHAR char
2. #define portFLOAT float
3. #define portDOUBLE double
4. #define portLONG long
5. #define portSHORT short
6. #define portSTACK_TYPE uint32_t
7. #define portBASE_TYPE long
1. typedef int int32_t;
2. typedef short int16_t;
3. typedef char int8_t;
4. typedef unsigned int uint32_t;
5. typedef unsigned short uint16_t;
6. typedef unsigned char uint8_t;
事实上,上述都是定义在stdint.h中的,因不同的系统Linux\Window\MacOS\RTOS有所不同,作用就是确保不同平台上都精确的占对应的位,占对应的字节(8位一字节)
变量定义
-
char 型变量的前缀是 c
-
short 型变量的前缀是 s
-
long 型变量的前缀是 l
-
复杂的结构体,句柄等定义的变量名的前缀是 x
-
变量是无符号型的再加前缀 u,是指针变量则加前缀 p
函数取名
-
私有函数前加prv
-
返回值void,前缀v
#define taskYIELD()
表示宏定义在task.h下
任务
概念
单片机写在一个while(1)里,RTOS是内核调度执行。
每一个内核都是一个处理单元,一个内核同时只能处理一个任务
- 还有一个挂起状态,挂起状态下调度器不可见,如果一个任务较长时间不运行就把他挂起,否则阻塞的话还加个超时判断
创建任务
ret = xTaskCreate((TaskFunction_t) master_task_main, /* 任务入口函数 */(1)
“MASTER”, /* 任务名字 */(2)
64*1024, /* 任务栈大小 */(3)
NULL, ,/* 任务入口函数参数 */(4)
TASK_PRIORITY_NORMAL, /* 任务的优先级 */(5)
&task_master_handler); /* 任务句柄指针 */(6)
-
任务入口函数,是个函数指针,指向要执行的任务。
-
任务描述名称,字符串形式,最大长度由 FreeRTOSConfig.h 中定义的 configMAX_TASK_NAME_LEN 宏指定,多余部分会被自动截掉,只是方便调试。
-
任务堆栈大小,单位为字, 4 个字节 uint32_t,这个要注意,否则系统内存紧缺。
-
任务入口函数形参,不用的时候配置为 0 或者NULL 即可。
-
任务的优先级,数值越大优先级越高,0 代表最低优先级。基于其SDK开发,可将自定义的所有业务功能task设为同一个优先级,按时间片轮询调度。
-
任务句柄指针,作用是可以恢复、挂起、删除等等,目前还不知道怎么实现的,也可以直接NULL。
迷糊的一点
void func(){};
void (*p) () = func;
后面可以用p代替func,func代替不了p
- 但不可以直接void (* p)(){}写函数体,因为这样函数就没名字了
任务调度的时候第一个参数可以填p或&func
任务调度
创建成功后就进入了就绪状态,等待被调度
操作系统的任务调度器只启动一次,且启动了就不返回了,自此之后都由它调度
vTaskStartScheduler()
-
执行后自动创建空任务和定时器任务。
-
高优先级的任务可打断低优先级任务,低优先级任务必须在高优先级任务阻塞或结束后才能得到调度
-
相同优先级的任务采用时间片轮转方式进行调度
-
三个用于任务启动和切换的异常SVC、PendSV 和SysTick,分别用于任务启动、切换、获取时间片
启动方式
都要现在main中初始好硬件和RTOS系统
-
所有任务创建完成,启动调度
-
创建一个任务,启动调度器,然后在这个任务里创建其他任务,所有任务都创建完成,第一个任务把自己删掉
-
为什么要空闲(idle)任务?因为一旦启动就不能停,设置一个优先级最低的空闲任务
状态切换
-
vTaskSuspend(任务函数指针)挂起一个任务
-
vTaskSuspendAll()挂起所有任务
-
vTaskResume(任务函数指针)取消挂起
-
xTaskResumeFromISR(任务函数指针)用于中断,不管被嵌套挂起几次都能解除
-
vTaskDelete(任务函数指针)用于一个任务删除另一个任务。如果是自己删除自身就不用填形参
-
一般中断服务函数只做标记事件,然后通知其他任务完成其他的事情防止阻塞。
队列
概念
队列是用于任务间通信的特定数据结构
注意:消息空间已满仍在发或者消息空间NULL仍在读,都需要当前任务阻塞等待。
创建
xQueueGenericCreate()
申请内存,传入队列占用单元、每个单元字节、队列类型
xQueueGenericReset()
初始化,传入队列句柄
发消息
-
xQueueSend()
消息拷贝入队,如果是中断里需要用xQueueSendfromISR() -
参数依次为:队列句柄、消息、队列满时阻塞超时时间
-
xQueueSendToFrant()
队首插入 -
xQueueGenericSend()
多个参数,第四个参数表示位置 -
如果不确定是不是fromISR,就只管发送,让内部判断是系统服务还是中断服务
收消息
xQueueReceive()
接收消息并从消息空间删除,记得写阻塞超时的参数
查询
uxQueueMessagesWaiting(句柄)
查询队列消息数量
uxQueueSpacesAvailable()
查询队列空闲数量
定时器
分类
分为软件定时器、硬件定时器,硬件触发中断且精度高,软件是操作系统封装的接口,基于硬件
-
通常软件定时器以系统节拍周期为计时单位。系统节拍配置为configTICK_RATE_HZ,该宏在 FreeRTOSConfig.h 中,一般是100或者1000
-
系统节拍越小开销越大,但也越精确
创建
TimerHandle_t xTimerCreate( const char * const pcTimerName, //定时器名称
const TickType_t xTimerPeriodInTicks, //定时时间
const UBaseType_t uxAutoReload, //是否自动重载
void * const pvTimerID, //回调函数的参数
TimerCallbackFunction_t pxCallbackFunction ) //回调函数
- 创建成功后处于休眠状态。
xTimerStart()、
xTimerReset()、
xTimerStartFromISR() 、xTimerResetFromISR()
xTimerChangePeriod()、xTimerChangePeriodFromISR()
xTimerStop(),xTimerStopfromISR()
xTimerDelete()
- 队列和任务都是按需创建一直使用,一般不用删除,但是定时器用完一定要删,而且置句柄NULL
信号量
信号量(Semaphore)是一种实现任务间通信的机制 可以简单认为是为支持多任务同时操作的全局变量
二值信号量
- 二值信号量看作只有一个消息的队列,因此这个队列只能为空或满
计数信号量
- 计数信号量则可以被认为长度大于 1 的队列,信号量使用者依然不必关心存储在队列中的消息,只需关心队列是否有消息即可
互斥信号量
优先级翻转问题:假设有任务H,任务M和任务L三个任务,优先级逐次降低。低优先级的任务L抢先占有资源,导致高优先级的任务H阻塞等待,此时再有中等优先级的任务M,它不需要该资源,且优先级高于任务L,它优先执行;之后再执行任务L,最后才执行任务H。看起来就是高优先级的任务反而不如低优先级的任务,即优先级翻转。
任务L先占用资源,任务H申请不到资源会进入阻塞态,同时系统就会把当前正在使用资源的任务L的优先级临时提高到与任务H优先级相同,即使任务M被唤醒了,因为它的优先级比任务H低,所以无法打断任务L,因为任务L的优先级被临时提升到 H;任务L使用完该资源,任务H优先级最高,将接着抢占 CPU 的使用权,这样保证任务H在任务M前优先执行。
事件
计数信号量处理多任务、多中断、多任务与中断同步比较麻烦,引入事件
- 事件是一种实现任务间通信的机制,可以一对多,多对多,一个任务等待多个事件的触发就叫一对多
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)