RM电控RTOS

news2025/1/17 1:05:35

OS即(operating system)操作系统,比如我们常用的windows系统,mac系统,android系统,ios系统,linux系统等,都属于操作系统。操作系统的本质是一个特殊的软件,它直接管理硬件,同时为各个应用程序划分资源(内存,堆栈,时间片等),并提供控制(调度,同步)。不管是计算机还是单片机,在任意时刻都只能运行一段代码,顶多是运行速度上会有差距,为什么我们能够在电脑上打开多个软件同时流畅的使用,就需要归功于操作系统对于软件的控制,操作系统会将各个应用程序抽象成进程,给每个进程独立的分配资源,同时对他们进行调度,使得每一个进程都仿佛是在独占整个计算机。

以下图为例,该图较为清晰的反映了硬件,操作系统和应用程序之间的层次关系。可以发现操作系统operating system位于硬件computer hardware之上,应用程序application programs又位于操作系统operating system之上,各个应用程序如compiler(编译器),assembler(组译器),text editor(文本编辑器),database system(数据库系统)等都被抽象成了用户(user)。

由于单片机的资源比较少,一般在单片机上运行的操作系统具有功能精简,实时性强的特点,也被称为RTOS(real time operating system)实时操作系统。单片机上的RTOS非常多,国外常见的RTOS包括FreeRTOS,uCOSⅡ等,国内这几年做的RT-Thread操作系统也发展的很好,阿里和腾讯蹭物联网热点弄了些AliOS啥的乱七八糟的东西,但是好像没啥动静,个人感觉国内真正有竞争力的还是RT-Thread。

没有运行OS的计算机统称为裸机,一般我们利用中断和循环构建前后台系统完成的工程都是裸机工程,中断是前台,针对各种突发的中断源进行及时响应,循环是后台,稳定执行一些常驻的重复性工作。在裸机工程中,编写者对于代码的执行情况是一清二楚的,只要编写者清楚中断到来的时刻,就能知道每一时刻中单片机在执行哪段代码,另外裸机工程由用户手动分配堆栈,所以总体上裸机工程是完全可控的,这也使得裸机的调试难度比较低,但是当工程复杂,耗时、耗资源的任务多时,裸机工程必须在中断中编写复杂的逻辑或者执行耗时的任务,这就会导致裸机工程的执行效率非常低下,响应丧失实时性。

而OS则不一样,由于任务调度和堆栈分配都是由OS来完成的,编写者并不知道任意时刻OS内部的执行情况,因此如果OS的执行出了问题,调试难度是比较大的,很多时候需要借助特殊的调试工具帮助查找问题,比如FreeRTOS就有专用的调试工具FreeRTOSViewer。

另一方面是时间利用率高,之前说过,裸机工程最大的问题就是在工程复杂时,不得不往中断中增加一些执行起来很耗时的代码,继而导致实时性大大下降,比如工程中有一个定时器中断和一个串口中断,两个中断到来的间隔时间位1ms,定时器中断的优先级高于串口中断,只要定时器中断中的代码需要大于1ms的时间来执行,就会导致串口中断无法得到响应。可以想象当中断数量更多,各个中断之间的间隔时间更短,而需要执行的任务耗时更长的情况下,裸机工程跑起来会是个什么惨状。而使用OS时,耗时的代码全部放到任务中,交给OS来调度;中断中只需要执行耗时短的重要代码,这样中断就能够得到及时的响应,即使有多个复杂,耗时的任务也能够实时的进行处理,下图就是一个典型的RTOS执行的时序,可以看到中断消耗的时间很短,耗时的代码都被放到任务中去了。

此外OS还可以提供一些裸机不具备的功能,比如信号量,消息队列,任务通知等,用来管理复杂情况下的资源分配或者进程同步。以信号量为例,信号量的功能是实现各个任务对临界资源的互斥访问,比如一辆步兵车采用双板方案,云台和底盘各有一块开发板,两板采用串口进行通讯。下板需要将底盘yaw轴电机角度信息和功率信息发送给上板,yaw轴电机角度的发送和功率信息的发送各自在一个定时器中断和一个串口中断中进行,这时上下板通讯所使用的串口就是一个临界资源,必须采用信号量进行保护,即当一个任务正在访问通讯串口时,会占有信号量,另一个任务到来之后必须处于阻塞状态,等待上一个任务访问完毕,释放信号量后才能访问通讯串口。

如果不进行保护的话,有可能会出现这种情况:串口中断中发送的功率信息只发送到一半 ,定时中断就绪了,串口中断被打断,剩下的一半发送的信息变成了yaw轴电机角度信息,两个信息一拼之后就变成了没有意义的乱码,发送给上板之后会引发各种奇奇怪怪的问题。

最后,现在的RTOS基本都是有自己的生态圈的,各种开发商会基于RTOS提供各种便利的组件,包括网络,蓝牙,GUI图形界面,文件管理系统等。选择使用OS开发的话就能够直接在工程中调用这些组件的接口,并且有丰富的文档支持,而如果是裸机的话就得自己造很多轮子,过于浪费时间精力。

所以在RM比赛中,到底有没有必要跑OS?我觉得其实是没有必要的,按照上文所说,除非出现工程过于复杂,耗时耗资源的任务过多的情况下,裸机才会有比较严重的问题,其他情况下裸机的可控性和调试方便程度都优于OS,而RM比赛中,一般一段中断里面的代码不过几百行,执行起来的耗时根本到不了毫秒级,用OS也并不能体现出任何优势,另外上面举例的信号量处理临界资源竞争的问题,其实两个中断撞到一起的概率非常非常的小,就算有也可以通过合理的设置中断优先级,或者代码逻辑来避免问题。

但是没有必要不等于不能够或者不应该上OS,如果编写者对OS的机制比较熟悉的话,使用OS就能够有非常好的编码体验,整个工程的抽象度得到了提升,代码的逻辑分层更加的清晰,不同兵种之间进行代码迁移也会比较容易。目前使用OS的参赛队还是很多的,我观摩过几个学校的代码,还是很有水平的。

任务调度机制

这里以FreeRTOS为例,介绍一下OS的任务调度机制。

我们先简单介绍一下进程的概念,对于进程,我们很难找到一个准确的定义,一般我们会将程序的一次执行当成一个进程,更准确的说,我们将一个程序在一个数据集合上的运行过程当成一个进程,这说明进程包含着动态的概念,一段程序执行时,我们一般划分成三个阶段,开始执行--->执行中--->执行完成。这也恰好对应了进程的工作状态:就绪态--->运行态--->挂起态。

进程除了以上三种状态,还有一个重要的状态被称位阻塞态(Blocke),对应的是一个程序执行到一般时被暂停的状态。

在FreeRTOS中,进程的四种基本工作状态是就绪态(Ready),运行态(Running),阻塞态(Blocked)和挂起态(Suspended),各个状态的相互转换关系如下图:

我们编写一段代码,来展示OS下的任务代码编写和裸机代码编写之间的区别:

void green_led_task(void const * argu)
{
	while(1)
	{
		HAL_GPIO_TogglePin(GREEN_LED_PORT,GREEN_LED_PIN);
		osDelay(100);
	}
}

这段程序的功能是控制一个绿色LED闪烁,如果我们在普通的裸机工程中将其作为一个函数调用,程序就会一直卡在这段闪烁的循环里,不会执行后续的代码,假如我们再写一个红色LED闪烁的代码,在裸机工程中调用,红色LED是不会闪烁的(这里我使用的是OS中的延时函数osDelay,裸机工程中对应的是HAL_Delay函数)。

void red_led_task(void const * argu)
{
	while(1)
	{
		HAL_GPIO_TogglePin(RED_LED_PORT,RED_LED_PIN);
		osDelay(100);
	}
}

但是我们通过如下的代码将上面两个函数注册为两个进程之后:

osThreadDef(GreenLEDTask, green_led_task, osPriorityNormal, 0, 128);
green_led_task_t = osThreadCreate(osThread(GreenLEDTask), NULL);

osThreadDef(RedLEDTask, red_led_task, osPriorityNormal, 0, 128);
red_led_task_t = osThreadCreate(osThread(RedLEDTask), NULL);

OS就会自动将上面两个代码进行调度,最后我们看到的结果是红绿LED一起以1s为周期闪烁。

OS的调度过程是这样的——当绿色LED闪烁进程green_led_task执行到osDelay处时,OS会将该进程由运行态变成阻塞态,直到500ms之后才会将其恢复为就绪态。当绿色LED闪烁进程处于运行态时,如果红色LED闪烁进程red_led_task在此时就绪了,就需要优先等待绿色LED闪烁进程从运行态变成阻塞态,才可以从就绪态变成运行态。

所以调度的实质就是OS按照某种调度算法的原则,安排各个进程的运行状态,使得它们以近乎“并行”的方式得到执行。关于调度的具体算法,这里不加以详细的介绍,主要是三个:先来先服务(FCFS)调度算法,优先级调度算法和时间片轮转调度算法。三种算法同时执行,合作完成任务调度功能。

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

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

相关文章

一文彻底搞懂Transformer - FFNN(前馈神经网络)

Transformer 神经网络: 神经网络(Neural Networks)是一种模仿生物神经网络的结构和功能的数学或计算模型。它由大量的人工神经元(也称为节点或处理单元)相互连接而成,这些神经元之间通过带有权重的连接进行…

罗德与施瓦茨(RS)FSW50,FSW85,FSW67信号和频谱分析仪

Rohde & Schwarz FSW50,FSW67,FSW85信号和频谱分析仪 高性能罗德与施瓦茨 (R&S) FSW50 信号和频谱分析仪专为方便、准确和快速而设计。其独特的触摸屏、直观的多视图结果显示和优化的用户指南使 R&S FSW50 分析仪的操作高效便捷。凭借其无与伦比的相位噪声、无与伦…

数学生物学-2-离散时间模型(Discrete Time Models)

上一篇介绍了一个指数增长模型。然而,我们也看到,在现实情况下,细菌培养的增长是在离散的时间(在这种情况下是小时)进行测量的,种群并没有无限增长,而是趋于以S形曲线趋于平稳,称为“…

[ACL 2024] Revisiting Knowledge Distillation for Autoregressive Language Models

Contents IntroductionMethodRethinking Knowledge Distillation for Autoregressive LMsImproving Knowledge Distillation with Adaptive Teaching Modes ExperimentsReferences Introduction 作者提出 Autoregressive KD with Adaptive Teaching Modes (ATKD),通…

Go语言开发通过本地数据xdb文件​查询获取IP地址的归属地区及运营商名称

说明: 用本地数据,离线识别ip属地,用于显示用户ip属地,不依赖第三方的api接口,本地数据包解析,解析速度快10微秒级别的查询效率。返回数据固定格式:国家|区域|省份|城市|ISP,例如&a…

c++11(三)

一、可变参数 1、可变参数模板 c语言中的 scanf 和 printf 可以支持我们传入任意个数的参数&#xff0c;原理就是用了参数包。 //可变参数包 template<class ...Args> void Print(Args... args) {} Args&#xff1a;模板参数包 args&#xff1a;函数形参参数包 声明…

检查linux系统中异常进程

1、查看非root运行的进程 [rootbastion-IDC ~]# ps -U root -u root -N 2、查看root运行的进程 [rootbastion-IDC ~]# ps -u root 注意&#xff1a;UID为0的进程&#xff0c;查看该进程所打开的端口和文件 [rootbastion-IDC ~]#ps -ef 查看进程 [rootbastion-IDC ~]# l…

Lesson 77 Terrible toothache

Lesson 77 Terrible toothache 词汇 appointment n. 预约 构成&#xff1a;point v. 指&#xff0c;指向 用法&#xff1a;point to 人 / 物    指着&#xff0c;指向……    point out 指出&#xff08;问题&#xff09; 相关&#xff1a;game point 局点    matc…

statsmodels学习笔记

statsmodels学习笔记 统计模型、假设检验和数据探索。statsmodels是一个python模块&#xff0c;提供了用于估计许多不同统计模型的类和函数&#xff0c;以及用于统计测试和统计数据探索。每个估计器都有一个广泛的结果统计列表。根据现有的统计软件包对结果进行测试&#xff0c…

【C++】深入解析C/C++内存管理:new与delete的使用及原理

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类 本章将分享C为何放弃malloc/free系列&#xff0c;选择新系列new/delete去管理内存。深度探索new/delete的使用及其原理,m…

VBA注释 (<*> + <*>)

在VBA&#xff08;Visual Basic for Applications&#xff09;中&#xff0c;注释是一种用于向代码中添加说明或解释文本的方法&#xff0c;这些文本不会被执行。注释对于理解代码的目的、逻辑或特定部分的代码功能非常有帮助&#xff0c;尤其是在处理复杂或长的代码时。 一、…

当《黑神话:悟空》遇上openKylin,国产力量的极致碰撞!

万众瞩目的国产3A游戏巨作《黑神话&#xff1a;悟空》终于上线啦&#xff01;&#xff01;&#xff01; 在正式发售后不到24小时&#xff0c;Steam在线玩家峰值突破222万&#xff0c;在Steam所有游戏在线玩家历史峰值中排名第二。第一拨玩家纷纷晒出好评&#xff0c;称这款现象…

Python安装Crypto库报错:ModuleNotFoundError: No module named ‘Crypto‘

目录 from Crypto.Cipher import AES 1.解决方法 1、卸载Crypto和pycrypto库 2、安装pycryptodome库 二、另一种解决方法&#xff08;看的别人遇到的情况&#xff0c;我没有遇到这种情况&#xff09; from Crypto.Cipher import AES 在网上搜的教程使用第三方库实现AES算法…

消息中心业务系统集成方案:提升企业信息流动性与协作效率

在信息化时代&#xff0c;企业的业务系统之间需要实现高效的信息流动与协作&#xff0c;以支持动态的业务需求和快速的决策过程。消息中心作为企业信息管理的重要组成部分&#xff0c;通过整合各类消息和通知&#xff0c;能够提升信息传递的效率和准确性。本文将详细探讨消息中…

Nginx 配置指南

一、Nginx 简介 1.1 概述 Nginx 是一款高性能、轻量级的开源 Web 服务器和反向代理服务器&#xff0c;以其可靠性、丰富的功能和简单的配置而闻名。由 Igor Sysoev 开发&#xff0c;最初用于解决 C10K 问题&#xff0c;与传统的 Web 服务器相比&#xff0c;Nginx 采用异步事件…

使用stream()流合并两个列表

List<Author>结构如下&#xff1a; List<Reader>结构如下&#xff1a; 需求&#xff1a;将Author列表和Reader列表根据相同id合并到一个列表中 private static void mergeList() {List<Author> authors Author.getAuthors();List<Reader> readers …

阅读、分析和维护高质量开源软件有感——小计一笔

目录 一、问题分析 软件开发问题分析 动机 学什么 目的 二、要求 阅读 理解 运用 分析 评估 认知 三、案例选择 MiNotes”开源软件 方式 实践支撑软件工具 操作流程 应该学到的知识 学习过程 四、任务与输出 1.阅读开源软件 2.标注开源软件 3.分析开源…

iLogtail 开源两周年:感恩遇见,畅想未来

早在上世纪 60 年代&#xff0c;早期的计算机&#xff08;例如 ENIAC 和 IBM 的大型机&#xff09;在操作过程中会输出一些基本的状态信息和错误报告&#xff0c;这些记录通常通过打印机输出到纸带或纸卡上&#xff0c;用于跟踪操作流程和调试&#xff0c;最早期的日志系统借此…

前端必备:高效处理树形数据与数组的实用函数

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:Vue-树形数据处理|数组:实用函数封装 大家好&#xff0c;依旧青山&#xff0c;在开发项目过程中&a…

3、springboot时代背景

一、微服务 二、分布式 三、云原生 原生应用如何上云。 Cloud Native 上云的困难 服务自愈弹性伸缩服务隔离自动化部署灰度发布流量治理...... 上云的解决