为什么学习STM32时还要学习汇编

发布者:MagicalSerenade最新更新时间:2024-02-28 来源: elecfans关键字:STM32  汇编  机器语言 手机看文章 扫描二维码
随时随地手机看文章

不同的平台的汇编代码是不一样的,最早的汇编在50年代就发明了,比很多人的父母的年龄都大,老掉牙,不用学习怎么写汇编。一个公司有一个人知道怎么写汇编就够了。但要学习读汇编,为什么学习汇编?


1、性能

直接翻译为机器语言,性能最高。优秀的C语言效率只能达到汇编的80%左右。其他高级语言跟汇编一比差得更远。语言越高级性能越差。很多bootloader和BIOS用汇编写,汇编操作的是电脑,手机刚刚上电时,硬件和初始化的那些命令,它们的性能的要求比较高,效率高开机速度更快。


分析问题

个人认为,编程人与机器对话,我们写C,写JAVA,但是电脑并不认识这些语言,电脑只认识0和1;所以需要一个人来翻译这些语言,这个翻译官就是编译器,但是编译器不能百分之百准确的表达程序员的意思,也就是所谓的翻译有反义。例如,编译器为了性能好一点,可能会优化变量和语句,这个过程可能好心办坏事,把有用的操作优化了。因此只有看懂一些汇编语句,才能分析程序真正执行的流程。在问题难以定位的情况下,汇编可能是分析问题的最后一根稻草。


帮助理解硬件

有些学校的单片机课程是以汇编进行教学的,主要原因就是汇编更贴近硬件。不过我不赞成这种做法,C语言能快速做出一点东西,有利于学生在放弃之前,增加成就感,好坚持下去。但是汇编确实更贴近硬件。


LDR指令

为了便于理解下文,先介绍下LDR指令,其格式如下:

LDR{条件} 目的寄存器 <存储器地址>

作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。LDR指令的寻址方式比较灵活,实例如下:

LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1。
LDR R0,[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。
LDR R0,[R1,R2]! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。
LDR R0,[R1,LSL #3] ;将存储器地址为R1*8的字数据读入寄存器R0。
LDR R0,[R1,R2,LSL #2] ;将存储器地址为R1+R2*4的字数据读入寄存器R0。
LDR R0,[R1,,R2,LSL #2]!;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
LDR R0,[R1],R2,LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
LDR R0,Label ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。

要注意的是:

LDR Rd,[Rn],#0x04 ;这里Rd不允许是R15。

另外LDRB 的指令格式与LDR相似,只不过它是将存储器地址中的8位(1个字节)读到目的寄存器中。LDRH的指令格式也与LDR相似,它是将内存中的16位(半字)读到目的寄存器中。

LDR R0,=0xff

这里的LDR不是arm指令,而是伪指令。这个时候与MOVE很相似,只不过MOV指令后的立即数是有限制的。这个立即数必须是0X00-OXFF范围内的数经过偶数次右移得到的数,所以MOV用起来比较麻烦,因为有些数不那么容易看出来是否合法。

2、如何在KEIL下阅读汇编

按d进入debug模式,在view下选择disassembly window 。

100059172-113890-1.png

看光标,c文件下指向了main函数的第一行。

汇编窗口也指向了对应的语句。但是,在执行C语言的第一行之前,仍然有许多操作要做,比如变量放在哪?在哪里调用了main函数等,这些操作都被集成开发环境IDE给封装起来了。我们必须知道,在执行main函数之前,有许多事情要做,只不过,初学的时候不必理会。以下是C语言源码,功能是点亮LED。

//main.c #include int main(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; GPIOB->CRL &= ~(0xf<<(1*4)); GPIOB->CRL |= 0x2<<(1*4); GPIOB->ODR &= ~(1<<1); return 0; } //main.h #define RCC_APB2ENR (*(unsigned int *)0x40021018) #define GPIOB_CRL (*(unsigned int *)0x40010c00) #define GPIOB_ODR (*(unsigned int *)0x40010c0c)

汇编窗口往上翻,确实很多语句,先看这几行代码的汇编:

100059172-113891-2.jpg

先说最常用的两句汇编:

LDR r0,[r1] r0 = *r1

STR r0,[r1] *r1 = r0

MOV r0,r1 r1->r0拷贝

100059172-113892-3.png

从内存0x0800 017c的32位数据拷贝到r0:

r0 = * 0x0800 017c

我们看到的 1000 4002其实 就是0x4002 1000。这里边有个知识点叫做大小端模式,以下简单讲解,不能理解就记住。

100059172-113893-4.jpg

这个数据是在地址是这么存放的:

7C 7D 7E 7F
00 10 02 40

实际数据是0x4002 1000

* 0x0800 017c=0x4002 1000

然后r0的值+0x18也就是24 因为这个是第6号(第6号就是第7个的意思)元素

得到r0 = *0x4002 1018,r0的值由一个地址,变成了地址所存放的数据。

然后是或0x08操作,结果再复制给r0,*0x4002 1018 |=0x08

给r1分配地址,这个地址也是0x4002 1000, r1 = *0x4002 1000

把r0存放的值,(不是r0的地址,)存到r1+18的空间上

*(r1+0x18) = r0
*0x4002 1018 = (*0x4002 1018 |=0x08)
*0x4002 1018|=0x08

最终结果:地址4002 1018的数,执行了或0x08的操作。再分析下一句 :

100059172-113895-6.jpg

前两句给r0分配空间,r0 = *0x4001 0c00

然后用BIC清除数据位,把4-7位清零,结果再赋值给r0。

*0x4001 0c00 &= ~(0xf0)
r1 = *0x4001 0c00
*0x4001 0c00 &= ~(0xf0)

剩下的不再详细分析,直接给答案 :

100059172-113894-5.jpg

***0x4001 0c00 |= 0x20
0x4001 0c0c &= ~(0x02)*

最终,可以看到C语句被翻译成了意料之中的汇编语句,自己的意图被机器准确的理解了。


关键字:STM32  汇编  机器语言 引用地址:为什么学习STM32时还要学习汇编

上一篇:基于STM32的实时心率检测仪设计
下一篇:什么是中断 stm32中断服务函数

推荐阅读最新更新时间:2024-11-12 22:18

STM32 Usart 上电发送一个无效字符的问题
无论这么设置USart,上电后都会发送一个无效字符,这个是STATUS寄存器的上电初始值有问题造成的,Usart的发送数据寄存器有一个缓冲移位寄存器。并且发送有两个状态,一个是发送数据寄存器为空,一个是移位寄存器发送完成。上电后Usart的状态寄存器的发送完成位为0,造成了上电以后会始终会有一个值被发送,这个值就是发送移位寄存器中的值,而这个值有时候是0X00有时候是0XFE 。 要解决这个问题,在初始化的时候先初始化Usart,然后再配置Usart的GPIO位,就可以避免Usart上电发送一个无效字符的问题。 还有一种可能性,在上电后至端口初始化,STM32的I/O端口处于高阻状态,有些RS232转换芯片在输入端为高阻时
[单片机]
STM32串口接收粉尘传感器数据
本文章主要记录STM32实现对粉尘传感器的数据采集及简单处理。 材料: 1、正点原子Mini开发板STM32f103RC 2、ZH03A激光粉尘传感器 3、USB TO TTL线(就是烧写51单片机的下载线)连接电脑和开发板上的串口2 4、电脑串口调试助手,用来查看数据 主要设计思路: 1、串口初始化,包括GPIO,外设时钟,NVIC等配置; 2、串口中断处理函数编写,即通过接收中断获取数据并且保存到数组,同时注意判断相关数据位; 3、发送数据,使用到了printf函数,需要重定向; 4、主程序初始化。 主要函数编写: 1、串口初始化,PA.2- USART2_TX,PA.3- USART2_RX,PA.9- USART1
[单片机]
<font color='red'>STM32</font>串口接收粉尘传感器数据
STM32裸机编程的基础知识(5)
闪烁 LED 现在我们已经搭建好了完整的构建、烧写的基础设施,是时候让固件做点儿有用的事情了。什么是有用的事情?当然是闪烁 LED 了!Nucleo-F429ZI 开发板有 3 颗 LED,在开发板数据手册的 6.5 节,我们可以看到板载 LED 连接的引脚: PB0: green LED PB7: blue LED PB14: red LED 再次修改 main.c 文件,添加上引脚定义,然后把蓝色 LED 引脚设为输出模式,开始无限循环。首先,把我们之前讨论过的 GPIO 定义和模式设置拷贝过来,注意,现在又新加了一个 BIT(position) 工具宏: #include inttypes.h #include
[单片机]
STM32生态系统 密码学原理的应用-TLS
密码学原理的典型应用:TLS TLS:即传输层安全 基于密码学原理的通信协议 实现服务器和设备之间的认证通信和数据加密 TLS握手协议 通信双方的相互确认 协商会话密钥 TLS握手 v1.2 (RFC 5246) CA证书:包含的是CA的公钥,用来核实该CA颁发给别人的证书的真实性 服务器/IoT设备的证书:包含了自己的公钥 通过公钥加密的消息,只能私钥拥有者可以解密 可以签证由对应私钥签名的消息的完整可靠性 服务器/IoT设备的私钥:用来为自己发送的消息签名 至此,通过“挑战-应答”机制,IoT设备端已经确认是和真正的目标服务器在通信 服务器的证书是有效的(CA保证,通过CA公钥验证成功) 对
[单片机]
<font color='red'>STM32</font>生态系统 密码学原理的应用-TLS
STM32开发笔记39: Keil打开时提示”Warning #440“警告的解决方法
单片机型号:STM32F070F6P6 首先指明的是此问题是升级keil以后造成的,keil版本升级到V5.26.2.0后,打开原先的程序提示”Warning #440“警告,如下图所示。 此问题的解决方法,在Keil的官方网站中,有详细的描述,网址如下:http://www.keil.com/support/docs/4028.htm。 具体解决的方法,就是打开”Options for Target“对话框,找到”Device“选项页,选择其它芯片类型,然后再选回来,点击”OK“按钮,就解决了。
[单片机]
<font color='red'>STM32</font>开发笔记39: Keil打开时提示”Warning #440“警告的解决方法
ARM汇编指令调试方法
学习ARM汇编时,少不了对ARM汇编指令的调试。作为支持多语言的调试器,gdb自然是较好的选择。调试器工作时,一般通过修改代码段的内容构造trap软中断指令,实现程序的暂停和程序执行状态的监控。为了在x86平台上执行ARM指令,可以使用qemu模拟器执行ARM汇编指令。 一、准备ARM汇编程序 首先,我们构造一段简单的ARM汇编程序作为测试代码main.s。 .globl _start _start: mov R0,#0 swi 0x00901 以上汇编指令完成了0号系统调用exit的调用。mov指令将系统调用号传入寄存器R0,然后使用0x00901软中断陷入系统调用。 为了运行ARM汇编代码,需要使用交叉编译器ar
[单片机]
STM32之IIC通讯升级版--SHT30温湿度读取
针对上篇文章对于程序可移植性不强的问题进行优化,基本思路是首先搭建好IIC底层驱动程序,该程序可用于任何IIC通讯设备,然后针对不同的IIC设备单独编写应用程序,本篇文章仍以SHT30为例。 一、IIC底层驱动之myiic.h #ifndef __MYIIC_H #define __MYIIC_H #include sys.h //IO方向设置 #define SDA_IN() {GPIOC- CRH&=0XFFFF0FFF;GPIOC- CRH|=8 12;} #define SDA_OUT() {GPIOC- CRH&=0XFFFF0FFF;GPIOC- CRH|=3 12;} //IO操作函数
[单片机]
<font color='red'>STM32</font>之IIC通讯升级版--SHT30温湿度读取
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved