STM32学习:为什么需要学习汇编?
单片机与嵌入式','单片机与嵌入式 2024-02-23

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

为什么学习汇编?

性能

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

分析问题

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

帮助理解硬件

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

LDR指令

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

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

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

LDR R0[R1] ;将存储器地址为R1的字数据读入寄存器R0LDR R0[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0LDR R0[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0LDR R0[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1LDR R0[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1LDR R0[R1,R2]!    ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1LDR R0[R1,LSL #3] ;将存储器地址为R1*8的字数据读入寄存器R0LDR R0[R1,R2,LSL #2] ;将存储器地址为R1+R2*4的字数据读入寄存器R0LDR R0[R1,R2,LSL #2]!;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存入R1LDR R0[R1],R2LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1LDR R0LabelLabel为程序标号,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用起来比较麻烦,因为有些数不那么容易看出来是否合法。

如何在KEIL下阅读汇编

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

看光标,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)

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

先说最常用的两句汇编:

LDR r0,[r1]    r0 = *r1 STR r0,[r1]    *r1 = r0 MOV r0,r1    r1->r0拷贝

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

r0 = * 0x0800 017c

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

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

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的操作。再分析下一句 :

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

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

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

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

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

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

相关推荐

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 【立即预约】Keysight直播:搞懂介电常数那些事儿


  • 相关技术文库
  • 单片机
  • 嵌入式
  • MCU
  • STM
  • 深谈嵌入式系统,嵌入式系统是如何组成的?

    嵌入式系统在生活中有诸多应用,大家对于嵌入式系统或多或少有所耳闻。在前两篇文章中,小编对嵌入式系统进行过详细介绍。为继续增进大家对嵌入式系统的认识,本文将对嵌入式系统的组成加以说明。如果你对嵌入式系...

    06-27
  • 嵌入式系统秘籍共享,最全嵌入式系统解析

    嵌入式系统的应用十分广泛,因此越来越多的人学习嵌入式系统。由此,在学习嵌入式系统之前,我们应当对嵌入式系统具备一些认识。所以在本文余下部分,小编将对嵌入式系统进行全面解析。如果你对嵌入式系统具有兴趣...

    06-27
  • 51单片机超声波测距程序详解

    51单片机超声波测距程序详解 超声波四通道测距:超声波测距实现分为三大块: 其一是12864带字库的液晶驱动程序: 代码如下: /////////////////12864驱动程序/////////////////////////// //1写数据 void WriteDat...

    06-25
  • 51系列单片机的引脚图

    51系列单片机的引脚图 端子介绍 l P0.0~P0.7 P0口8位双向口线(在引脚的39~32号端子)。 l P1.0~P1.7 P1口8位双向口线(在引脚的1~8号端子)。 l P2.0~P2.7 P2口8位双向口线(在引脚的21~28号端子)。 l P3.0~P3.7 P2口8...

    06-25
  • 51单片机串口通信需要加超时中断吗?

    接收数据时,超过一定时间就算出错. 这个超时的时间是单片机自己算出的吗?超时的时间是由编程序的人定的,他定多长就多长从一段程序开始 实现电脑向 单片机发送一些数据,单片机返回Iget +数据 #include #define u...

    06-25
  • 51单片机电机pid控制系统程序

    51单片机电机pid控制系统程序 本程序来源网上,小编进行了简单修改,还未验证。 /************************* 应用背景:直流电机的额定功率12V,额定转速3000rpm,光码盘12孔, 晶振为12MHz,定时/计数器T0检测转...

    06-25
  • 51单片机指令集设计实例

    当你编写完一个程序后,通过软件调试,你可以看到程序的指令集,从指令集你就能知道单片机内部是如何工作的,比如数据存取的寄存器与地址,下面是电工之家找的一篇指令集,讲的蛮好的。 一、数据传送类指令(7种助...

    06-25
  • 51单片机定时器工作原理及用法

    TMOD : 控制定时器的工作方式。8个bit,高四位 bit 控制 T1,、低四位 bit 控制 T0。因为定时器有4种工作方式;TMOD = 0x00(工作方式0),TMOD = 0x01(工作方式0),TMOD = 0x02(工作方式2),TMOD = 0x03(工作方式3)。...

    06-25
  • 51单片机指令系统寻址方式

    指令给出参与运算的数据方式称为寻址方式。换句话说,寻址方式就是寻找确定参与操作的数的真正地址。 在MCS-51系列单片机的指令系统中寻址方式共有7种,立即寻址方式,mcs-51单片机的一种寻址方式,操作数就写在指...

    06-25
  • 51单片机学习单片机之路总结

    学习单片机有一学期了,现在也由51转到STM32了。一直想对51的学习做一个总结。也希望对别人有一些启发。也给后学者提供一些建议。当然本文是我对自己学习过程的总结,若有不对的地方,还请高手指出。 我想,再看本...

    06-25
  • 入手STM32单片机的知识点总结

    从STM32新建工程、编译下载程序出发,让新手由浅入深,尽享STM32标准库开发的乐趣

    06-23
  • 单片机定时器之改良版:时间轮定时器

    前段时间把自己以前用的单片机定时器整理出来,我称之为简单定时器,这种简单定时器比较适合定时器使用量少的程序中,如果定时器数量要求多,精度要求高,效率就会有问题,为此,俺就实现了一个时间轮定时器,简单测...

    06-23
下载排行榜
更多
评测报告
更多
EE直播间
更多
广告