C与汇编深入分析
汇编怎么调用C函数
直接调用
BL main
传参数
在arm中有个ATPCS规则(ARM-THUMB procedure call standard)(ARM-Thumb过程调用标准)。
约定r0-r15寄存器的用途:
- r0-r3:调用者和被调用者之间传递参数
- r4-r11:函数可能被使用,所以在函数的入口保存它们,在函数的出口恢复它们。

int delay(unsigned int d)
{while(d--);return 0;
}
ldr r0,=1000000
dl delay
cmp r0,#0
返回值保存在r0
A函数调用B函数
假设A函数里需要用到R4寄存器,B函数里也需要用到R4寄存器。
因此B函数就有会覆盖A函数R4寄存器的值。
于是需要在B函数执行前,保存R4-R11寄存器的值在A的栈中 。
B函数执行完后,返回A函数前,要从A的栈中恢复R4-R11寄存器。
C函数的反汇编码阅读
要解决几个问题:
- 为什么调用C函数前要设置栈?栈的作用是?
- C函数传参
- C函数执行过程

反汇编示例

地址0x08000010,Flash上烧写20010000。
启动流程
上电后:
- 设置栈:CPU会从0x08000000读取值,用来设置SP(我们的程序里再次设置了SP)。
- 跳转:CPU会从0x08000004得到地址值,根据它的BIT0切换到ARM状态或Thumb状态,然后跳转。
对于Cortex M3/M4,它只支持Thumb状态,所以0x08000004上的值bit0必定是1。
对0x08000004上的值=Reset_Handler+1。
从Reset_Handler上继续执行
纯汇编点灯


写程序
寄存器操作
对于寄存器的操作,主要涉及读、修改、写。
- 读可以使用LDR指令,代码为LDR R1,[R0]
- 写使用STR指令,代码为STR R1,[R0]
- 修改:清除位使用BIC或AND指令,设置位使用ORR指令
LDR R0, =(1<<20) | (1<<21)
BIC R1,R1,R0 ;清除R1的bit20,bit21
LDR R0, =(1<<20)
ORR R1,R1,R0 ;设置R1的bit20
- 函数里的条件判断
比如减1操作,代码为SUB R0,R0,#1
顺便使用减1后的结果影响程序状态寄存器,代码为SUBS R0,R0,#1 - 程序的调用与返回值
传参,代码为LDR R0,=VAL
调用,代码为BL delay,它顺便把下一条指令的地址保存在LR寄存器了。
返回,代码为MOV PC,LR
使用按键控制LED

先看原理图,我们使用KEY1来控制红色LED,按下KEY1在灯亮,松开后灯灭。
KEY1的引脚是PA0
使能GPIOA模块,RCC_APB2ENR:0x40021000+0x18
串口的硬件介绍
UART的全称是Universal Asynchronous Receiver and Transmitter,即通用异步收发器。
串口在嵌入式中用途非常的广泛,主要的用途有:
- 打印调试信息
- 外接各种模块:GPS、蓝牙
串口因为结构简单、稳定可靠,广受欢迎。
通过三根线即可,发送、接收、地线。

TXD线把PC机要发送的信息发送给ARM开发板。
最下面的地线统一参考地。
串口的参数
- 波特率:一般选波特率都会有9600、19200、115200等选项。其实意思就是每秒传输这么多个比特位数(bit)。
- 起始位:先发出一个逻辑0的信号,表示传输数据的开始。
- 数据位:可以是5~8位逻辑0或1.如ASCII码(7位)、扩展BCD码(8位)。小端传输。
- 校验位:数据位加上这一位后,使得1的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。
- 停止位:它是一个字符数据的结束标志。
怎么发送一字节数据,比如A?
'A’的ASCII值是0x41,二进制就是0x01000001,怎么把这8位数据发送给PC机呢?
- 双方约定好波特率(每一位占据的时间)
- 规定传输协议
原来是高电平,ARM拉低电平,保持1bit时间。
PC在低电平处开始计时。
ARM根据数据依次驱动TXD电平,同时PC依次读取RXD电平,获得数据。
PC机在数据位的中间读取引脚状态。

RS-232的电平比TTL/CMOS高,能传输更远的距离,在工业上用得比较多。
市面上大多数ARM芯片都不止一个串口,一般使用串口0来调试,其它串口来外接模块。

115200,8n1。
一秒钟可以传输115200个bit,传送一个字节需要:1个起始位+8个数据位+1个停止位=10bit。
所以一秒钟可以传输11520个字节。
UART编程
看原理图确定引脚
- 有很多串口,使用哪一个?看原理图确定。
- 配置引脚为UART功能
至少用到发送、接收引脚:txd、rxd
需要把这些引脚配置为UART功能,并使能UART模块 - 设置串口参数
- 根据状态寄存器读写数据
肯定有一个数据寄存器,程序把数据写入,即可通过串口向外发送数据。
肯定有一个数据寄存器,程序读取这个寄存器,就可以获得先前接收到的数据。
很多有状态寄存器:判断数据是否发送出去?是否发送成功?判断是否接收到了数据?

需要使能GPIOA/USART1模块
需要设置GPIOA的寄存器,选择引脚功能:所以要使能GPIOA模块。
GPIOA模块、USART1模块的使能都是在同一个寄存器里实现。


USART寄存器,用结构体来表示比较方便:
typedef unsigned int uint32_t;
typedef struct
{volatile uint32_t SR; /*!< USART Status register, Address offset: 0x00 */volatile uint32_t DR; /*!< USART Data register, Address offset: 0x04 */volatile uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */volatile uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */volatile uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */volatile uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */volatile uint32_t GTPR; /*!< USART Guard time and prescaler register, Address
}USART_TypeDef;
USART_TypeDef *usart1 = (USART_TypeDef *)0x40013800;
在C语言中,编译器通常会对代码进行各种优化,以提高程序的执行效率。这些优化包括重新排序指令、删除看似无用的变量读取等。
然而,在与硬件通信的情景下,有些变量的值可能会被硬件或者其他事件异步地修改,而这种修改通常是在程序控制流之外发生的。
假设有一个代表硬件寄存器的变量,如果没有使用’volatile’关键字,编译器可能会进行一些优化,认为这个变量的值在程序的某个地方被设置后就不再改变。这就可能导致一些问题,因为实际上这个变量的值可能会在程序的其它地方被异步地修改。
通过在变量声明中加入’volatile’关键字,告诉编译器不要对这个变量进行过多的优化,以确保每次访问这个变量时都从内存中读取最新的值,而不是使用之前缓存的值。
这对于与硬件直接交互的变量,比如你提供的USART通信寄存器,非常重要,因为这些寄存器的值可能会在程序的正常流程之外被外部事件改变。
#ifndef __UART_H
#define __UART_Hvoid uart_init();
char getchar();
char putchar(char c);#endif
这段代码是一种常见的C/C++预处理器约定,用于防止头文件(header file)被多次包含,避免引起重定义错误。
- #ifndef:这是预处理指令,表示if not defined,即如果之前没有定义过指定的标识符,那么执行接下来的代码。
- __UART_H:这是一个宏标识符,通常是头文件名的大写形式,加上双下划线前缀以确保标识符的唯一性。在这里,它用于作为一个宏,防止头文件被多次包含。
- #define __UART_H:如果之前没有定义过__UART_H,那么用这个#define指令定义它。这样,当头文件再次被引用时,#ifndef检查将会失败,因为__UART_H已经被定义了。
- #endif:表示条件编译的结束。如果之前#ifndef条件成立,那么在这里结束条件编译块。
这种写法的目的是确保一个头文件只会被编译一次,即使它在多个地方被引用。这可以防止由于头文件被重复引用而导致的重定义错误。这是一种预防措施,用于提高代码的可维护性和可移植性。
相关文章:
C与汇编深入分析
汇编怎么调用C函数 直接调用 BL main传参数 在arm中有个ATPCS规则(ARM-THUMB procedure call standard)(ARM-Thumb过程调用标准)。 约定r0-r15寄存器的用途: r0-r3:调用者和被调用者之间传递参数r4-r11…...
MySQL中外键的使用及外键约束策略
一、外键约束的概念 外键约束(FOREIGN KEY,缩写FK是数据库设计的一个概念,它确保在两个表之间的关系保持数据的一致性和完整性。 外键是指表中的某个字段的依赖于另一张表中某个字段的值,而被依赖的字段必须具有主键约束或者唯一约束&#…...
Home Assistant使用ios主题更换背景
Home Assistant使用ios主题、更换背景 lovelace-ios-dark-mode-theme 默认前置情况,1、已安转HACS插件2、搜索安装 IOS Dark Mode Theme1)第一、二步应该很容易实现,configuration.yaml文件很容易被找到2)而本人在进行第三步操作时…...
深入了解鼠标光标的设置过程
有一位读者问了这样一个问题: “为什么鼠标光标的设定绑定在窗口类,而不是窗口上?” 这个问题隐含地假设了光标与窗口类相关联。虽然每个窗口类都有一个关联的光标,但决定使用哪个光标的是窗口。 光标设置过程在 WM_SETCURSOR 消…...
数据结构-散列表
列表(Hash Table),又称哈希表,是一种数据结构,特点是:数据元素的关键字与其存储地址直接相关 例:有一堆数据元素,关键字分别为{19,14,23ÿ…...
一款IT团队都在用的私有化知识库,技术开放,还开源了!
IT和软件开发团队需要处理大量的技术文档和知识,通过建立内部知识库,可以将技术文档、代码示例、最佳实践等知识整理和归档起来,方便团队成员查找和参考。 IT和软件开发团队为什么要建立内部知识库? 提高知识管理效率:…...
解决 docker compose 官方 MySQL 镜像在容器中不能输入中文的问题
该问题可以通过添加环境变量解决,途径如下: 一、如果容器没条件或不允许重启,可通过命令行方式临时解决。 docker compose exec SERVICE-NAME env LANGC.UTF-8 mysql -u username -p 二、修改 docker-compose.yml 配置文件一劳永逸 envir…...
基于连续Hopfield神经网络优化——旅行商问题优化计算
大家好,我是带我去滑雪! 利用神经网络解决组合优化问题是神经网络应用的一个重要方面。所谓组合优化问题,就是在给定约束条件下,使目标函数极小(或极大)的变量组合问题。将Hopfield网络应用于求解组合优化问…...
SpringBoot整合Activiti7——定时器事件(九)
文章目录 定时器事件时间定义时间固定时间段时间周期 1.开始事件2.中间事件3.边界事件代码实现xml文件自定义服务任务监听器自定义用户任务监听器测试流程流程执行步骤 定时器事件 可以用在开始事件、中间事件、边界事件上,边界事件可以是中断和非中断边界事件 需要…...
轻量封装WebGPU渲染系统示例<29>- 深度模糊DepthBlur(源码)
实现方式: step1. 通过mrt机制,输出颜色和深度相关数据的两张rtt纹理。 step2. 基于上述颜色纹理,生成一张模糊之后的新rtt纹理。 setp3. 基于深度(也就是距离摄像机的远近)数据,合成颜色和模糊纹理数据,并最终输出。 当前示例…...
LeetCode226. Invert Binary Tree
文章目录 一、题目二、题解2.1 前序遍历版本2.2 中序遍历版本2.3 后序遍历版本 一、题目 Given the root of a binary tree, invert the tree, and return its root. Example 1: Input: root [4,2,7,1,3,6,9] Output: [4,7,2,9,6,3,1] Example 2: Input: root [2,1,3] Ou…...
Java设计模式-创建型模式-建造者模式
建造者模式 建造者模式案例与工厂模式的区别:Builder 注解 建造者模式 建造者模式是将一个复杂对象的构件与表示分离,使得同样的构件过程可以创建不同的表示。 建造者模式将内部构件的创建和组装分割开,一般使用链式编程,代码整洁…...
PyQt中QFrame窗口中的组件不显示的原因
文章目录 问题代码(例)原因和解决方法 问题代码(例) from PyQt5.QtWidgets import * from PyQt5.QtGui import QFont, QIcon, QCursor, QPixmap import sysclass FrameToplevel(QFrame):def __init__(self, parentNone):super().…...
git 命令行回退版本
git 命令行回退版本 git 命令行回退版本命令: 1.切换到需要回退的分支 git checkout branch-v2.0.02.更新远程分支 git fetch3.找到需要回退版本的版本号git revert a6914da55ff40a09e67ac2426b86f1212e6580eb4.清除工作区缓存git clean -df5.强制提交git push -f...
IntelliJ IDEA 安装 GitHub Copilot插件 (最新)
注意: GitHub Copilot 插件对IDEA最低版本要求是2021.2,建议直接用2023.3,一次到位反正后续要升级的。 各个版本的依赖关系,请参照: ##在线安装: 打开 IntelliJ IDEA扩展商店,输入 "Git…...
viewpage选择器
GitHub - hackware1993/MagicIndicator: A powerful, customizable and extensible ViewPager indicator framework. As the best alternative of ViewPagerIndicator, TabLayout and PagerSlidingTabStrip —— 强大、可定制、易扩展的 ViewPager 指示器框架。是ViewPagerIndi…...
vue中如何将json数组指定的key赋值给el-form-item并均匀的分成2列
在Vue中,你可以使用v-for指令来遍历JSON数组,并将指定的key赋值给el-form-item。下面是一个示例: <template><el-form><el-row><el-col :span"6" v-for"item in jsonArray" :key"item.key&qu…...
笔记本分屏怎么操作?3个方法提高工作效率!
“有朋友知道笔记本怎么才能实现分屏吗?我在工作时,经常需要来回切换屏幕,效率真的太低了,有什么方法可以实现两个屏幕同时使用吗?” 在现代生活中,多任务处理已成为常态,而笔记本分屏技术为用户…...
Android 使用poi生成Excel ,word并保存在指定路径内
一添加依赖(一定要用新版依赖防止一些bug) minSdk 26 //注意最小支持SDK26 dependencies {implementation org.apache.poi:poi:5.2.4implementation org.apache.poi:poi-ooxml:5.2.4implementation javax.xml.stream:stax-api:1.0-2 }二,创…...
嵌入式杂记 -- MCU的大小端模式
MCU的大小端模式 大端模式小端模式大小端模式测试联合体概念MCU大小端模式测试大端模式测试小端模式测试 大小端模式转换 在进行MCU开发的时候,我们需要注意MCU的数据存储模式,在嵌入式中有两种不同的存储模式,分别是 大端模式和小端模式。 …...
Prompt工程进阶:6个技巧提升大模型输出精准度
Prompt工程进阶:6个技巧提升大模型输出精准度 随着大语言模型在代码生成、内容创作、数据分析等场景的渗透率持续提升,开发者和从业者逐渐发现,通用Prompt往往只能得到模糊、冗余甚至偏离需求的输出。如何通过精细化的Prompt设计,…...
JSP 语法详解
JSP 语法详解 引言 JSP(JavaServer Pages)是一种动态网页技术,它允许开发者在网页中嵌入Java代码,以实现与数据库的交互和动态内容生成。JSP语法简洁明了,易于学习和使用。本文将详细介绍JSP的语法结构,帮助读者更好地理解和应用JSP技术。 JSP基本语法 1. JSP页面结构…...
STM32F4用CubeMX HAL库驱动STP-23激光模块,实测921600波特率串口中断接收避坑指南
STM32F4高波特率串口通信实战:激光测距模块稳定接收全解析 在机器人导航和智能小车开发中,激光测距模块的实时数据采集往往成为系统精度的关键瓶颈。当波特率提升至921600这一工业级速率时,传统的中断处理方式常会出现数据丢失、帧错位等问题…...
Tencent Hunyuan3D-1.0虚幻引擎集成:从生成模型到游戏资产的完整工作流
Tencent Hunyuan3D-1.0虚幻引擎集成:从生成模型到游戏资产的完整工作流 【免费下载链接】Hunyuan3D-1 腾讯开源的Hunyuan3D-1项目,创新提出两阶段3D生成方法,实现快速、高质量的文本到3D和图像到3D转换,融合Hunyuan-DiT模型&#…...
JetBrains IDE重置工具终极指南:30天试用无限续杯的完整教程
JetBrains IDE重置工具终极指南:30天试用无限续杯的完整教程 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 你是否经历过这样的场景:深夜加班赶项目,JetBrains IDE突然弹出&qu…...
如何利用Postiz实现高效社交媒体管理:AI驱动的智能调度解决方案
如何利用Postiz实现高效社交媒体管理:AI驱动的智能调度解决方案 【免费下载链接】clickvote 📨 The ultimate social media scheduling tool, with a bunch of AI 🤖 项目地址: https://gitcode.com/GitHub_Trending/cl/clickvote Pos…...
3步实现音频自由:QMCFLAC2MP3高效解密与跨平台应用指南
3步实现音频自由:QMCFLAC2MP3高效解密与跨平台应用指南 【免费下载链接】qmcflac2mp3 直接将qmcflac文件转换成mp3文件,突破QQ音乐的格式限制 项目地址: https://gitcode.com/gh_mirrors/qm/qmcflac2mp3 一、音乐收藏者的困境:当专有格…...
mT5分类增强版中文-base效果惊艳:同一输入生成‘正式/口语/幽默’三风格文本示例
mT5分类增强版中文-base效果惊艳:同一输入生成‘正式/口语/幽默’三风格文本示例 1. 模型介绍:零样本学习的文本增强利器 mT5分类增强版中文-base是一个基于mT5架构的文本增强模型,专门针对中文场景进行了深度优化。这个模型最大的特点是采…...
BallonsTranslator:深度学习驱动的漫画翻译自动化工具
BallonsTranslator:深度学习驱动的漫画翻译自动化工具 【免费下载链接】BallonsTranslator 深度学习辅助漫画翻译工具, 支持一键机翻和简单的图像/文本编辑 | Yet another computer-aided comic/manga translation tool powered by deeplearning 项目地址: https:…...
别再乱点默认应用了!麒麟Kylin Desktop V10 SP1默认程序设置,一篇讲清逻辑与重置
麒麟Kylin桌面系统V10 SP1:默认应用管理的深度解析与实战指南 你是否曾在安装WPS或浏览器时,面对系统弹出的默认应用选择窗口随手一点,结果发现.docx文件全被浏览器打开?这种"手滑"操作在麒麟Kylin Desktop V10 SP1系统…...
