当前位置: 首页 > news >正文

韦东山老师 RTOS 入门课程(一)RTOS 介绍,熟悉裸机的汇编逻辑

韦东山老师 RTOS 入门课程

课程链接:韦东山直播公开课:RTOS实战项目之实现多任务系统 第1节:裸机程序框架和缺陷_哔哩哔哩_bilibili

RTOS 介绍

裸机:固定顺序执行。

中断:可以一直专心做循环里的事情,直到触发中断。也可以中断里设立 flag 在循环里检测执行,防止中断超时。

定时器:太多个任务的时候不适合说都用中断。可以用定时器,设定不同任务的执行频率,比如 A 1ms 执行一次,B 2ms 执行一次…… 但是相互之间会有影响,比如 A 卡住了会影响 B。

还有一种解决办法是状态机。每个函数设定几个状态,每次执行一部分状态后保留当前状态退出,下次进入的时候继续执行。

image-20230818232306800

状态机有四大概念:状态,事件,动作,变换。

状态就是不同的状态。

事件是执行某个操作的触发条件,比如门开状态我发起关门事件,门关事件我发起开门事件。

动作是由事件触发额具体行为。

变换是状态之间的切换。

状态机忒麻烦而且也没有那么优。

RTOS 比如可以设定每个程序按一定时间片执行,到时间自己切换,不用自己写状态机那么复杂。而且现在 RTOS 生态比较好(特别是 rt-thread),而且大多数开发都需要 RTOS 。其实用了 RTOS 反而更简单。

ARM 基础

程序是什么?

运行程序时,先把程序烧录到 flash 文件中,数据放入 RAM 中(可变),CPU 读指令取数据写数据。RAM 中的数据是拿到了 CPU 的寄存器中。

这里我们重点关注6条 arm 指令即可。

  1. 读指令。LDR R0,[R1,#4],指明了 rd, rs, length。LDR 是固定取 4B,从 R1+4 地址取。
  2. 写指令。STR R0,[R1,#4]
  3. 加减。ADD R0,R1,R2 ADD R0,R0,#1 SUB R0,R1,R2
  4. 比较。CMP R0,R1 结果存在 PSR 中。
  5. 跳转 B BL ,BL 是跳转后还保存返回地址。

分析C的汇编码,理解程序

image-20230819133726104

用一个很简单的程序来举例,Keil 进入调试模式后可以看到对应代码的汇编码。

首先通过 PUSH 指令自动压栈 r3 lr 并修改 sp 指针,保存 r3 寄存器和函数返回地址

第二句令 r0 = a 的地址。

第三句根据地址取出 a 的值存入 r0.

第四句 r0 的值存入栈0的位置,因为刚才压栈后,栈中从高到低分别存了 lr r3,也就是说r0 实际上是把数据存入栈中 r3 的位置,r3 入栈是在栈中占了一个栈中的位。

然后出栈,lr 赋值给 pc 以供函数返回,r3 获取到栈中写入的值。

再看第二个程序:

int add_val(int *pa, int *pb)
{volatile int tmp;tmp = *pa;tmp += *pb;return tmp;
}int mymain()
{volatile int a = 1;volatile int b = 2;volatile int c;c = add_val(&a, &b);return 0;
}

汇编得到的代码(在 .dis 文件中):

    i.mymainmymain0x08000372:    b50e        ..      PUSH     {r1-r3,lr}0x08000374:    2001        .       MOVS     r0,#10x08000376:    9002        ..      STR      r0,[sp,#8]0x08000378:    2002        .       MOVS     r0,#20x0800037a:    9001        ..      STR      r0,[sp,#4]0x0800037c:    a901        ..      ADD      r1,sp,#40x0800037e:    a802        ..      ADD      r0,sp,#8 ;传参0x08000380:    f7ffffca    ....    BL       add_val ; 0x80003180x08000384:    9000        ..      STR      r0,[sp,#0]0x08000386:    2000        .       MOVS     r0,#00x08000388:    bd0e        ..      POP      {r1-r3,pc}0x0800038a:    0000        ..      MOVS     r0,r0i.add_valadd_val0x08000318:    b508        ..      PUSH     {r3,lr}0x0800031a:    4602        .F      MOV      r2,r00x0800031c:    6810        .h      LDR      r0,[r2,#0]0x0800031e:    9000        ..      STR      r0,[sp,#0]0x08000320:    6808        .h      LDR      r0,[r1,#0]0x08000322:    9b00        ..      LDR      r3,[sp,#0]0x08000324:    4418        .D      ADD      r0,r0,r30x08000326:    9000        ..      STR      r0,[sp,#0]0x08000328:    9800        ..      LDR      r0,[sp,#0]0x0800032a:    bd08        ..      POP      {r3,pc}

可见几个函数参数 r0 r1… 来传入,超过 r3 的一般压栈,这是一个约定俗成的标准,直接传入的参数不超过4个。

参数问题,我们再尝试第二个代码:传入4个参数的 add。

程序:

int add_val(int a, int b, int c, int d)
{return a+b+c+d;
}int mymain()
{volatile int a = 1;volatile int b = 2;volatile int c = 3;volatile int d = 4;volatile int sum;sum = add_val(a,b,c,d);return 0;
}
i.mymainmymain0x0800036a:    b500        ..      PUSH     {lr}0x0800036c:    b085        ..      SUB      sp,sp,#0x140x0800036e:    2001        .       MOVS     r0,#10x08000370:    9004        ..      STR      r0,[sp,#0x10]0x08000372:    2002        .       MOVS     r0,#20x08000374:    9003        ..      STR      r0,[sp,#0xc]0x08000376:    2003        .       MOVS     r0,#30x08000378:    9002        ..      STR      r0,[sp,#8]0x0800037a:    2004        .       MOVS     r0,#40x0800037c:    9001        ..      STR      r0,[sp,#4]0x0800037e:    e9dd3201    ...2    LDRD     r3,r2,[sp,#4]0x08000382:    e9dd1003    ....    LDRD     r1,r0,[sp,#0xc]0x08000386:    f7ffffc7    ....    BL       add_val ; 0x80003180x0800038a:    9000        ..      STR      r0,[sp,#0]0x0800038c:    2000        .       MOVS     r0,#00x0800038e:    b005        ..      ADD      sp,sp,#0x140x08000390:    bd00        ..      POP      {pc}0x08000392:    0000        ..      MOVS     r0,r0

存入 lr r3 r2 r1 r0 后,从低到高地址加载 r3 r2 r1 r0(大概是因为输入入栈顺序和函数参数顺序是反的),然后跳转。

i.add_valadd_val0x08000318:    b510        ..      PUSH     {r4,lr}0x0800031a:    4604        .F      MOV      r4,r00x0800031c:    1860        `.      ADDS     r0,r4,r10x0800031e:    4410        .D      ADD      r0,r0,r20x08000320:    4418        .D      ADD      r0,r0,r30x08000322:    bd10        ..      POP      {r4,pc}

这里涉及到了函数中的寄存器保护。最近在看 MIPS 的体系结构,那里面是分了不同的寄存器(t,s,a……)arm 也是有不同作用之分。

r0-r3 传参。r13 sp,r14 lr,r15 pc。

传参的三个函数随意使用,无需保护,返回的时候值不同了也没关系。r4-r11 也可以用,但是得保存和恢复。上例中 add 函数就使用了 r4.

比如,如果代码改为:

int add_val(int a, int b, int c, int d)
{// 故意使用R4register int sum asm("r4");sum = a+b+c+d;return sum;
}

汇编:

    i.add_valadd_val0x08000318:    b530        0.      PUSH     {r4,r5,lr}0x0800031a:    4604        .F      MOV      r4,r00x0800031c:    1865        e.      ADDS     r5,r4,r10x0800031e:    4415        .D      ADD      r5,r5,r20x08000320:    18e8        ..      ADDS     r0,r5,r30x08000322:    bd30        0.      POP      {r4,r5,pc}

r5 相当于中间计算结果,他和 r4 都要回复。

中断处理

保存现场-处理中断-还原现场,继续源程序执行。要保存哪些寄存器?

  • 首先参数寄存器要存,不然函数还没处理参数呢来个中断参数丢了。

  • r4-r11 要保存,不然函数还没压栈保存呢这些丢了找不回来了,没法还原了。

  • lr 要保存,一样道理,没压栈的时候 lr 被修改了就没法跳转回原位置了。

实际上,发生中断的一瞬间所有寄存器都要存!

我们调用的 c 中断处理函数只能保证 r4-r11 不被破坏,所以如果想保证所有寄存器都能被保存,调用 c 函数之前就要保存。硬件自动保存其他寄存器.

恢复的时候也是硬件自动恢复其他寄存器,c 函数保证恢复 r4-r11.

硬件要保存的寄存器有 r0-r3,r12,lr,当前中断返回位置。一个典型的误区是,lr 不就是当前中断返回位置吗? 并不是。比如 main 函数调用 A 函数,A 函数执行到一半发生了中断,这时 lr 里的值是 A 函数返回到 main 函数所需的位置地址,中断返回到 A 函数的地址需要再单独保存。

相关文章:

韦东山老师 RTOS 入门课程(一)RTOS 介绍,熟悉裸机的汇编逻辑

韦东山老师 RTOS 入门课程 课程链接:韦东山直播公开课:RTOS实战项目之实现多任务系统 第1节:裸机程序框架和缺陷_哔哩哔哩_bilibili RTOS 介绍 裸机:固定顺序执行。 中断:可以一直专心做循环里的事情,直…...

WebRTC | SDP详解

目录 一、SDP标准规范 1. SDP结构 2. SDP内容及type类型 二、WebRTC中的SDP结构 1. 媒体信息描述 (1)SDP中媒体信息格式 i. “artpmap”属性 ii. “afmtp”属性 (2)SSRC与CNAME (3)举个例子 &…...

Springboot 实践(9)springboot集成Oauth2.0授权包,5个接口文件配置详解

前文讲解实现了spring boot集成Oauth2.0,实现了授权服务器和资源服务器的搭建,并通过浏览器和postman测试,获取到了授权码,用携带授权码的URL能够争取范文到资源。 本文详细讲解spring boot集成Oauth2.0的几个重要文件接口&#…...

最新AI系统ChatGPT程序源码/支持GPT4/自定义训练知识库/GPT联网/支持ai绘画(Midjourney)+Dall-E2绘画/支持MJ以图生图

一、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT?小编这里写一个详细图文教程吧&#xff01…...

【高频面试题】 消息中间件

文章目录 1、RabbitMQ1.1 RabbitMQ-如何保证消息不丢失1.2 RabbitMQ消息的重复消费问题如何解决的1.3 RabbitMQ中死信交换机 ? (RabbitMQ延迟队列有了解过嘛)1.4 RabbitMQ如果有100万消息堆积在MQ , 如何解决(消息堆积怎么解决)1.5 RabbitMQ的高可用机制有了解过嘛 2、Kafka2.…...

物联网智慧安防实训综合实训基地建设方案

一、系统概述 物联网智慧安防实训综合实训基地是一个为学生提供综合实践、培养技能的场所,专注于物联网技术与智慧安防应用的培训和实训。通过物联网智慧安防实训综合实训基地的建设和运营,学生可以在真实的环境中进行实践训练,提高其物联网技…...

openGauss学习笔记-44 openGauss 高级数据管理-存储过程

文章目录 openGauss学习笔记-44 openGauss 高级数据管理-存储过程44.1 语法格式44.2 参数说明44.3 示例 openGauss学习笔记-44 openGauss 高级数据管理-存储过程 存储过程是能够完成特定功能的SQL语句集。用户可以进行反复调用,从而减少SQL语句的重复编写数量&…...

【Linux】进程信号篇Ⅲ:可重入函数、volatile关键字、SIGCHLD信号

信号Ⅲ 🔗 接上篇七、可重入函数八、volatile 关键字九、SIGCHLD 信号 🔗 接上篇 👉🔗进程信号篇Ⅰ:信号的产生(signal、kill、raise、abort、alarm)、信号的保存(core dump&#x…...

排序算法:冒泡排序

冒泡排序是入门级的算法,但也有一些有趣的玩法。通常来说,冒泡排序有三种写法: 一边比较一边向后两两交换,将最大值 / 最小值冒泡到最后一位;经过优化的写法:使用一个变量记录当前轮次的比较是否发生过交换…...

Spring事件监听源码解析

spring事件监听机制离不开容器IOC特性提供的支持,比如容器会自动创建事件发布器,自动识别用户注册的监听器并进行管理,在特定的事件发布后会找到对应的事件监听器并对其监听方法进行回调。Spring帮助用户屏蔽了关于事件监听机制背后的很多细节…...

Cpp学习——list的模拟实现

目录 一,实现list所需要包含的三个类 二,三个类的实现 1.list_node 2.list类 3.iterator_list类 三,功能实现 1.list类里的push_back() 2.iterator类里的运算符重载 3,list类里面的功能函数 1.insert(&#xff…...

工具推荐:Chat2DB一款开源免费的多数据库客户端工具

文章首发地址 Chat2DB是一款开源免费的多数据库客户端工具,适用于Windows和Mac操作系统,可在本地安装使用,也可以部署到服务器端并通过Web页面进行访问。 相较于传统的数据库客户端软件如Navicat、DBeaver,Chat2DB具备了与AIGC…...

C语言刷题指南(二)

📙作者简介: 清水加冰,目前大二在读,正在学习C/C、Python、操作系统、数据库等。 📘相关专栏:C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…...

[C++11]

文章目录 1. 自动类型推导1.1 auto1.1.1 推导规则1.1.2 auto的限制1.1.3 auto的应用1.1.4 范围for 1.2 decltype1.2.1 推导规则1.2.2 decltype的应用 1.3 返回类型后置 2.可调用对象包装器、绑定器2.1 可调用对象包装器2.1.1 基本用法2.1.2 作为回调函数使用 2.2 绑定器 3. usi…...

【MySQL系列】--初识数据库

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...

Unity导入google.protobuf失败,无法找到google命名空间

问题: 1.刚开始把protobuf的文件夹直接从其他项目里(unity2021)里复制到unity(2020)版本,当时报错protobuf.dll的依赖项system.memory版本不对。 2.没有使用原来的protobuf文件了。使用vs2019的NuGet管理包来下载Google.Protobuf ,仍然报错找…...

使用IDM下载视频出现“由于法律原因,IDM无法下载...

一、问题描述 由于法律原因,IDM无法下载..,如图: 二、原因分析 下载该IDM抓取的M3U8文件,查看其中的内容发现 : #EXT-X-KEY 字段已经写明了加密方式是AES-128,包含一个URI和IV值 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:8 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:…...

pointnet C++推理部署--tensorrt框架

classification 如上图所示,由于直接export出的onnx文件有两个输出节点,不方便处理,所以编写脚本删除不需要的输出节点193: import onnxonnx_model onnx.load("cls.onnx") graph onnx_model.graphinputs graph.inpu…...

34.Netty源码之Netty如何处理网络请求

highlight: arduino-light 通过前面两节源码课程的学习,我们知道 Netty 在服务端启动时会为创建 NioServerSocketChannel,当客户端新连接接入时又会创建 NioSocketChannel,不管是服务端还是客户端 Channel,在创建时都会初始化自己…...

vscode 安装勾选项解释

1、通过code 打开“操作添加到windows资源管理器文件上下文菜单 :把这个两个勾选上,可以对文件使用鼠标右键,选择VSCode 打开。 2、将code注册为受支持的文件类型的编辑器:不建议勾选,这样会默认使用VSCode打开支持的相…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

Robots.txt 文件

什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...

三体问题详解

从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...