RTOS基础知识笔记

RTOS

RTOS属于操作系统(OS)

软件和硬件之间的桥梁,

本质

专用设备:C51单片机、STM32、嵌入式

OS:硬件驱动(内存管理、GPIO、Timer)

应用:直接调用驱动,开发应用逻辑

OS的使用场景

外设资源多、有并行的需求(多任务)、实时性

所以OS的本质就是一种分工的思想

逻辑系统:主程序在while(1)循环中,有中断机制

main( ){

//硬件初始化while(1){//应用}

}

xxx handler(){

//处理中断

}

多任务系统:任务去处理程序、中断

main( ){

//硬件初始化//RTOS初始化//多种任务初始化//开启任务:while(1)//这是每个任务中的whilewhile(1)//程序不能执行到这里

}

逻辑系统和多任务系统的区别:

逻辑系统主程序在while循环里面,实时性是中断保证的;

多任务是用任务去处理事件,每个事件对于每个任务而言都是主逻辑,实时性也是靠中断保证的;

程序结构 事件处理 紧急处理 特点:

裸机 主程序中轮询 中断 轮询+中断

多任务 任务为主 中断 任务+中断

正常的操作系统,其实也是有实时性的,但是性能稍微差点,主要去管理庞大的底层资源,内核特别大

RTOS对实时性要求非常高,对于管理底层资源可是可以做到了,因为单片机底层资源很少;

RTOS特点:

稳定性;开源协议;开发成本;外部扩展资源:有丰富的第三方资源库

(LOT:物联网) 实时性;市场占有率(bug少,学习资源多,产品推广方便)

以前的RTOS,追求稳定和实时,实现多任务和中断,设备的每个地址是实地址绑定的;

现在的RTOS加了第三方物联网组件(因为万物互联的趋势LOT)

RTOS学什么

应用开发、内核开发(kernel):kernel,port是具体的板卡资源,需要单独移植(软件控制硬件)、LOT开发:第三方资源

RTOS怎么学

RTOS的概念:任务、空闲、抢占、消息等等、RTOS的设计思路:就绪队列中如何去挑出最适合运行的任务(任务的优先级)、RTOS的接口使用:常见的API用熟

最终目标:会看(看懂源码)、会用(会用API)、会改(遇到的bug)

CMSIS标准

CMSIS: Cortex-M(微处理器)定义的一套标准

通用的数据类型;通用API:RTOS、Driver

(GPIO、Timer、ADC、DMA)

用这套标准打造一个生态

FreeRTOS

起源:一个英国公司发起的,被亚马逊看中,被收购,(电商,云计算:部署一些LOT设备,用rtos能够扩大团队、优化程序,开源用来推广产品)

特性:开源、商用免费、市场占有率高

组成:kernel、port、第三方库

任务;IPC;内存

内存管理:

五个策略:正常使用第四个就足够了;

1、可申请,不释放;

2、可申请,可释放,不整理;

3、2+线程安全优化

4、可申请,可释放,可整理

5、4+识别外扩的内存芯片

编程规范:

变量名:数据类型+单词(见名知意)

函数名:返回值类型+文件名+单词

宏名:文件名+单词

数据类型:标准数据类型和非标准数据类型

例:定义一个char类型的无符号计数值

uint8-t uccount;

定义一个赋值函数:

void vtimGetCNT( ){ }

接口API:

FreeRTOS的原生API

符合CMSIS标准的API

符合HAL库的API

配置:

FreeRTOS的Config.h(程序员根据应用去做配置,自定义Kernel)

FreeRTOS.h:默认文件 ifdef define

任务管理:

什么是任务:

竞争系统资源的最小单位;

每个任务都有属于自己的私有栈;

每个任务都在各自的while(1)中去死循环;

时间点上是串行;时间段上是并行;

任务的状态切换:

创建、删除、挂起、恢复、阻塞

Task1:每隔1s 打印一次 “task1删除”

Task2:每隔1s 打印一次 “task2创建”

Task3:{

while(1){if("1"){删除}if("2"){创建}if("3"){挂起}if("4"){恢复}}

}

1任务管理

概念、

状态切换流程

相关函数

系统启动

空闲任务

任务切换

2状态切换:创建、就绪、运行、阻塞、挂起

3相关函数:

1、创建、

2、删除、

3、挂起、

4、恢复挂起

1、可在任务中恢复

函数:vTaskResume( )

可以有多次挂起,但只需要在最后恢复一次即可;

不可以在中断中使用;

2、可在中断中恢复

vTaskResumeFromISR()

(fromISR:在中断中使用的API)

xxx–callback ( ){

BaseType-t temp;(判断是否挂起成功)

temp=vTaskResumeFromISR(句柄)

if(temp==pdtrue){

portYIEID–from–ISP( ) //在中断中主动进行任务切换

}

}

4系统启动:

osKernelStart() -> vTaskStartScheldmr( )

1、启动RTOS多任务

2、创建空闲任务和可选的软件定时器;

3、正常状态下无返回值,如果出现返回值,要么是空闲任务的创建异常,要么是软件定时器的创建异常;

5空闲任务:

1、主要是用来回收要被删除的任务的资源;

2、实现低功耗;

6任务切换

1阻塞:延时阻塞/条件阻塞;

2时间片时间到了,让出CPU(本质上是触发中断:pendSV(优先级是15,这个中断优先级数字越大,优先级越低,所以这个触发中断的优先级是最低的)->触发中断)

任务调度:

三种方式:

合作式调度:上一个结束,下一个才开始

时间片调度:同等任务优先级的时候,使用时间片来进行任务切换

抢占式调度:高优先级任务-> 低优先级任务;当前运行的任务是低优先级,如果来了一个高优先级任务,CPU会立刻将低的停下,让高任务去运行;

任务栈:

常用的栈:满减栈,满增栈;空减栈;空增栈;

sp指向的位置有没有数据,有的话,再看往大的地址加入数据还是往小的数据加入数据

每个任务都会有一个私有栈:

如何确定栈的大小:

首先,是估计可能的栈的大小:

函数:局部变量,形参,返回地址,状态;

中断;

任务切换

以上是可以评估的;

不可评估的:

printf( )

函数指针 ->接口

递归代码

先给一个大的栈空间

通过调试函数,得到剩余栈空间(真是利用的栈的大小)

栈的大小乘1.5或者 乘2

栈溢出检测:

有一个配置, xxx-stack-overflow,它的值分为1和2,代表两个不同的检测标准;1:看sp的地址是否超出;2:将整个栈都赋值为一个特殊的值:0xa5,每次都去查看最后16位是否为0xa5;如果是,那就说明还有一些值没有用;

配置:vApplicationStartOverFlowHook( ){ }

硬件错误:中断:HandFault-handler(void){}

中断优先级

任务优先级:

配置:MAX-priority

值越大,等级越高

不同优先级的任务:抢占式调度

同一优先级的任务:时间片调度

明确抢占时的场景

2个API:配置

设置优先级/获取优先级

uxRTaskpritorityGet( )

vTaskpritoritySet( )

6、临界区

当前运行的代码不可被高优先级的中断打断;

何时用临界区:全局可写变量和全局函数

实现:

7、调度锁、中断锁、任务锁

调度锁:防止当前任务被其他更高优先级的任务切换,将其他人都挂起

阻塞延时:相对延时/绝对延时

IPC:

中断和任务之间的通讯;

重点在于API函数的调用;

首先是消息队列(先进先出,用来存放消息)

在任务与任务或者中断与任务之间传递不固定长度的信息;

全局数组 VS 消息队列 使用消息队列的好处:

消息队列可以防止多任务同时操作;

还有超时的机制,可以帮助RTOS更好地管理任务;

先进先出,后进后出-----可以更好地管理数据;

内部的数据都是直接复制的,并非引用的;如果给消息队列传数据进去,并不是传的引用,虽然传地址省空间,但是消息队列本身为了安全性,所以直接传消息数据本身,并非传引用;

执行流程:

消息队列的TCB(控制块(也就是所谓的句柄)消息队列也是有句柄的)

有一个头指针,一个尾指针;要将数据不断插入;插入的数据,就在消息空间;发送方就是任务,中断,任务1,任务2,接收中断(Rx中断–>中断函数)也可以发送数据;

任务和中断都可以接收数据(可以是字符串,数组,结构体等等,都能发送)

应用场景:

双方发送一个不定长的消息

消息队列的API :

1、创建消息队列

□ xQueueCreate(消息队列的大小,每个消息的内存大小)

返回值就是消息队列的句柄

基本使用:

首先就是要创建一个消息队列

Queuehandle-t temp;

temp;=xQueueCreate(2,10);

if(temp==pdtrue){

成功;

}else{

失败;

}

2、删除消息队列

xQueueDelete(句柄)

删除消息队列

删除队列中的数据

3、发送消息队列(任务中发送/中断中发送)

xQueueSend(句柄,数据地址,)

数据是复制而不是引用进去;不能中断使用;

若第三个参数=0,返回

if(xQueueSend…==pdturn){

消息队列写入成功;

}else{

消息队列写入失败;	

}

中断里:

xxx-Callback( ){

BaseType-t temp;xQueueSendFromISR( ,,&temp){portYIEID-From-ISR(temp);//temp的值就决定要不要把值传入进去

}

}

4、获取消息队列

2、信号量

消息队列 ->数组

信号量 ->标志位

三大用途:

同步应用;二值信号量

资源管理;计数信号量

临界资源的互斥访问;互斥信号量

二值信号量取值:0/1

计数信号量取值:0到N

互斥信号量数值就是真或假

0代表信号量中没有数据,想要获取数据就要一直等待,这就是一种阻塞;如果是1或者N,那就是有数据了,接触阻塞

专业术语:

0代表信号量为空,任务要获取必须先阻塞延时;有两种退出的情况:一是超时;二是其他任务主动释放资源

二值信号量本质是一个长度为1,消息大小为0的消息队列;

整个状态就2种:空/满

0:当前二值信号量未被获取,此时再次获取信号量的任务,就必须阻塞;

1:可以正常获取

应用:

有数据变化 LCD刷新

无数据变化 LCD不刷新

运行流程:

二值信号量的API:

创建二值信号量:

□ xSemaphoreCreate( ){

osSemaphoreID temp;temp=xSemaphoreCreate( );

if(temp==pdture){

成功

}else失败

}

删除二值信号量:

xSemaphoreDelete( 句柄){

}

释放二值信号量

xSemaphoreGive( 句柄){

//调用此函数时,句柄要存在//不可用于中断

}

中断:

xSemaphoreGiveFromISR( ){

BaseType-t temp;xSemaphoreGiveFromISR(句柄,&temp);portYIEID-From-ISR(temp);

}

获取二值信号量:

xSemaphoreTake(句柄,等待时间){

//等待时间为0:

}

计数信号量:

取值>1的特殊的二值信号量(长度为1,消息大小为0的特殊的消息队列)

应用场景:允许多任务访问同一资源,但是又限制了任务的个数

运行流程:

释放资源后,task1可以继续运行,资源不够的时候,task1是阻塞的,task1占用资源之后也是要释放资源的;task2也需要调用资源,如果无法调用到资源,那么task2就是原地打转;

计数信号量的API:

创建:

xSemaphoreCreateCounting(支持的最大数,初始值 )

创建句柄;

句柄函数;

if(句柄,成功)else

删除:

xSemaphoreDelete(句柄)

释放:

xSemaphoreGive(句柄)

还有中断的函数

互斥信号量本质上也是一个特殊的二值信号量;

区别在于:二值信号量

task1和task2都要打印数据,共用串口资源(只有一个串口)

二值信号量在做同步 出现一个优先级问题,违反了抢占式调度的原则

原因:低优先级抢占资源,不放手,高优先级任务去获取时被阻塞,此时若有次高优先级任务加入,则当高优先级条件无法满足,出现次高先行的情况->抢占原则

解决:将正在使用的资源的低优先级任务,临时将其优先级提升至和阻塞的任务平级,当资源释放后,恢复

互斥信号量的API:

创建互斥信号量

删除互斥信号量

获取互斥信号量

释放互斥信号量

创建: □(互斥句柄) xSemaphoreMutux( )

句柄变量,赋值,判断是否成功

删除:vSemaphoreDelete(句柄)

释放:vSemaphoreGive(句柄)

vSemaphoreGiveFromISR(句柄,高优先级的状态唤醒)

portYIEID-From-ISR

获取:xSemaphoreTask( )

事件:

任务与任务之间,任务与中断中的一种同步机制;

应用:一些危险的(机器)启动,要经过很多的检测(校验),每个或者部分条件满足才可启动;

运行流程:

Task1 Task2 Task3等等

     事件组

中断1 中断2

task1的启动,几个条件都要满足,如果有一个条件不满足,那么task1只能打转;

事件可以做到一对多,多对多;

而且没有一个具体的数据的传输,只有一个标志位;

32位的,只用到了低的24位,整个事件组用到了0到23位;

事件发生了,就置为1,如果四个都置为1,就说明了条件都满足了,就可启动。

事件的API:

创建事件组:

□(事件句柄) xEventGroupCreate( )

创建句柄;句柄赋值;判断成功/失败

删除事件组:

xEventGroupDelete(句柄)

置位事件组:

xEventGroupSitBits(句柄,事件标志位)

事件标志位:

在中断里的置位:

xEventGroupSitBitsFromISR(句柄,事件标志位,唤醒状态位)//用守护任务,去负责给事件组置位;因为freeRTOS有个原则:在中断里不能去处理不确定的任务(不知道事件组给谁用,给哪些任务或者中断去用)守护任务其实就是软件定时器

等待事件组:

xEventGroupWaitBits(句柄,等待被设置的标志位,选择清零,选择是否满足所有事件,超时等待)

//3:如果不清除,表示以后会反复被触发(和中断一样,如果中断标志位不清除的话,就会一直被触发)

//4:事件组中有几个标志位已经被设置为1了,选择满足几个条件事件才触发,其实就是一个满足规则

freeRTOS的软件定时器

介绍:

基于SYSTick实现的

与硬件无关

可以创建N个 -->软件定时器组

应用:当有多个定时需求而硬件定时器资源不多时,就要用软件定时器在一些对精准要求不高的定时场景下(SYSTick负责计时,但是中断优先级不高)

运行流程:RTOS启动------守护任务(prvTimertask/Daemon),在这个守护进程中,主要做的事:获取到定时器相关的回调函数;将所有的定时器指令放到定时器命名队列(定时器指令:开启、停止、恢复、删除等等,这些指令会被放到特殊的队列里,Time Commod queue定时器命名队列)(定时器指令下发时机在守护进程创建之后)

定时器的API:

创建定时器:

□定时器的句柄 xTimerCreate (定时器名字,定时时间,模式,ID,回调函数)

//模式分为:单次模式和周期模式

//回调函数:当前定时器要执行的业务(可能是lcd屏幕的刷新,也可能是DHT11的数据读取)

开启定时器:

停止定时器:

删除定时器:

这三个是一组函数:

pdfault/pdpass(两种返回值,前者是指令发送失败,后者是指令通过) xTimer Delete/Start/Stop(句柄,超时)

//超时:有两层含义:

1、具体的任务执行由守护进程去做;

2、当定时器消息队列已满,当前指令要等待队列有空位才能加入

获取定时器的ID:

ID prTimerGetTimerIDC(句柄)

//返回的是ID

独立看门狗:

这里的看门狗与STM32中的是同一个,但是用法不同;

在STM32中的应用:喂狗,改变OVT

在freeRTOS中的应用:

监控任务

监控任务由独立看门狗去监控自身;

只有规定的任务事件发生了,才回去喂狗

注意:监控任务的优先级必须最高—发条件满足,立即喂狗;

当前项目中的所有任务,不可阻塞/挂起/删除

(所有核心任务)

喂狗给的时间要足够长—被监控任务重最长发送事件标志位的时间

被监控的任务最多有24个(事件组只有24个标志位可用)

动态内存管理:

任务、消息队列、信号量、定时器都需要RAM(内存空间),所以就需要动态内存管理

主要管理:

空间申请,释放,合并

5种管理策略:

1、只申请,不释放

2、申请然后释放,但是不合并

3、2+线程安全(malloc/free)

4、申请,释放,合并

5、4+支持将动态内存设置在不连续的区域上

Tickless低功耗模式:

电池类电子产品–>低功耗

低功耗的核心思想:如果不工作,就停止运行;就不去耗电;

睡眠模式:CPU不工作,其他外设工作

停止:时钟总线不工作,杀死了所有外设

待机模式:切断CPU的供电(1.8V)

freeRTOS中的低功耗

Tickless模式:

工作原理:

减少SYSTick的节拍运行

Tickless的低功耗模式使我们现在所有小型的RTOS中通用的;

触发时机:当所有任务都被阻塞/挂起时,由空闲任务去执行低功耗

低功耗主要针对的对象是SYSTick,让其在无任务时尽量不工作;

运行流程:

1、在空闲任务中关闭SYSTick中断(坏处:只让任务一阻塞一秒钟–osDelay(1000),然而systick被关闭,这个任务就无法被唤醒了)–因此这个方案不可行;

2、当进入空闲任务后,计算出下一个执行的高优先级任务还剩多少阻塞时间,以此去改变SYSTick的重装载值,作为这段时间的唤醒时间;

Tickless-IDIE设置为1,自动进入低功耗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/880260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu 安装minikube,并拉取k8s镜像

虚拟机是vmware17, 系统是ubuntu20.4, minikube是1.23.1, docker是24.0.7, 为什么要装minikube,通常k8s集群是要3台机子以上,而通过minikube,可以在一台机子上搭建出k8s集群,minikube采用的是D…

【深入学习Redis丨第六篇】Redis哨兵模式与操作详解

〇、前言 哨兵是一个分布式系统,你可以在一个架构中运行多个哨兵进程,这些进程使用流言协议来接收关于Master主服务器是否下线的信息,并使用投票协议来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。 文章目录 〇、…

【环境踩坑系列】centos7安装python3.10.X

前言 虽然centOS8已经发布了相当一段时间了,但是基于稳定性、成熟的社区等原因,大家在选择centOS作为服务器操作系统的时候仍然会选择centOS7作为首选。但是centOS7自带的是python2.7.5,当前大量的python程序要用到的又是python3&#xff0c…

基于SSM的“银发在线教育云平台”的设计与实现(源码+数据库+文档)

基于SSM的“银发在线教育云平台”的设计与实现(源码数据库文档) 开发语言:Java 数据库:MySQL 技术:SSM 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 首页页面图 健身养生详情页面 在线课堂界面 …

RocketMQ实战与集群架构详解

目录 一、MQ简介 MQ的作用主要有以下三个方面 二、RocketMQ产品特点 1、RocketMQ介绍 2、RocketMQ特点 三、RocketMQ实战 1、快速搭建RocketMQ服务 2、快速实现消息收发 1. 命令行快速实现消息收发 2. 搭建Maven客户端项目 3、搭建RocketMQ可视化管理服务 4、升级分…

ubuntu安装libtorch

Ubuntu20.04安装libtorch 〇、前期准备1、查看NVIDIA显卡算力和CUDA版本支持的算力2、查看CUDA与显卡驱动的版本对应 一、NVIDIA显卡驱动安装1、下载显卡驱动2、安装驱动A. 安装依赖B. 禁用nouveau驱动C. 显卡驱动安装 3、参考 二、CUDA安装1、下载安装CUDA2、测试CUDA是否安装…

大语言模型-教育方向数据集

大语言模型-教育方向数据集 编号论文数据集1Bitew S K, Hadifar A, Sterckx L, et al. Learning to Reuse Distractors to Support Multiple-Choice Question Generation in Education[J]. IEEE Transactions on Learning Technologies, 2022, 17: 375-390.Televic, NL, https…

双向链表的基本结构及功能实现

1.基本结构: 双向链表是一种链表数据结构,它由一系列节点组成,每个节点包含三个部分: (1).数据域:存储节点的数据 (2).前驱指针:指向前一个节点 (3).后驱指针:指向下一个节点 2.基本特性: 双向链接: 与单向链表…

连锁多门店收银系统源码

近年来,越来越多的零售行业从业者意识到,线下线上全渠道整合将成为国内消费市场的大趋势,其中,线下门店能够赋予品牌发展的价值依然不可小觑。 1. 线下连锁门店发展方向,多种经营模式 新零售时代,基于品牌…

excel导出图片---HSSFWorkbook--SXSSFWorkbook

1 概述 平时在工作中,excel导出图片经常会用到,但奈何HSSFWorkbook导出数据数量有限制问题,所以企业里大多都用SXSSFWorkbook格式,很少用HSSFWorkbook。所以今天以这两种格式分别记录下,图片的导出过程。 2 HSSFWork…

Reddit账号太多?一文教你轻松管理

想要在Reddit上扩大品牌影响力,但不知道如何管理多个账号?面对复杂的社区规则,你是否在担心账号安全?渴望提升参与度,却对内容策略一筹莫展?本文将为你揭秘如何高效管理你的Reddit账号,让你在这…

PR快速片段分割教程

方法一: 方法二yyds: ctrla全选,拽过来ME导出即可。

周文强:我感受到了海口经济学院创新创业的热情

日前,由中国志愿服务基金会、中国志愿服务基金会汇成百年专项基金以及共青团海口市委员会主办,共青团海口经济学院委员会承办的“2024 首届青领杯大学生创新创业大赛”海口站线下培训在海口经济学院开展。汇成百年专项基金发起人周文强作为本次大赛的创业…

ReadWriteLock读写锁

读写锁基本概念 ReadWriteLock是Java并发包中的一个接口,它定义了两种锁:读锁(Read Lock)和写锁(Write Lock),真正的实现类是ReentrantReadWriteLock。读锁允许多个线程同时读取共享资源&#…

基于单片机的家用安防报警系统设计

本设计基于STM32F103单片机作为主控,通过DS18B20温度传感器和MQ烟雾传感器对家庭环境的温度和烟雾浓度进行检测实现火灾预警的设计要求,当检测数据异常时激发报警提示。系统采用红外传感器对家庭环境中是否有盗贼进入实现检测,当出现异常情况…

机器学习的应用领域

机器学习在许多领域有广泛的应用,下面列出了一些主要的应用领域及其典型应用: 1. 图像识别 人脸识别:用于解锁手机、自动标记照片、监控安全系统。物体识别:应用于自动驾驶汽车、机器人、医疗影像分析中,帮助机器理解…

面试经典 150 题:力扣88. 合并两个有序数组

每周一道算法题启动 题目 【题目链接】 【解法一】合并后排序 排序后的数组自动省略0的数字&#xff0c;又学到了 class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {//合并两个数组后排序for(int i0; i<…

计算机网络详解:发展史、TCP/IP协议、网络通信与应用开发全流程

文章目录 1. 计算机网络的发展史1.1 初期阶段&#xff1a;网络的萌芽&#xff08;1960年代&#xff09;1.2 第二阶段&#xff1a;TCP/IP协议的引入&#xff08;1970-1980年代&#xff09;1.3 第三阶段&#xff1a;互联网的普及与商业化&#xff08;1990年代&#xff09;1.4 现代…

线性跟踪微分器TD详细测试(Simulink 算法框图+CODESYS ST+博途SCL完整源代码)

1、ADRC线性跟踪微分器 ADRC线性跟踪微分器(ST+SCL语言)_adrc算法在博途编程中scl语言-CSDN博客文章浏览阅读784次。本文介绍了ADRC线性跟踪微分器的算法和源代码,包括在SMART PLC和H5U平台上的实现。文章提供了ST和SCL语言的详细代码,并讨论了跟踪微分器在自动控制中的作用…

基于python+django+vue的电影数据分析及可视化系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…