为什么学习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 。
看光标,c文件下指向了main函数的第一行。
汇编窗口也指向了对应的语句。但是,在执行c语言的第一行之前,仍然有许多操作要做,比如变量放在哪?在哪里调用了main函数等,这些操作都被集成开发环境ide给封装起来了。我们必须知道,在执行main函数之前,有许多事情要做,只不过,初学的时候不必理会。以下是c语言源码,功能是点亮led。
//main.c #include int main(void) { rcc->apb2enr |= rcc_apb2enr_iopben; gpiob->crl &= ~(0xf从内存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语句被翻译成了意料之中的汇编语句,自己的意图被机器准确的理解了。
来源 | stm32嵌入式开发
整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除


无线路由器如何选择,双频合一还是单频独立
新华三长期服务医疗信息化建设,助力医疗信息化不断深入发展
vivo X20上手评测 梦幻天成
一种基于DDS的高速定时同步方法
浅析运算放大器的增益带宽积
为什么学习STM32时还要学习汇编
LoRa在电动车智能充电系统的应用
“视”无止境!CES 2017戴尔显示器尽显绝佳视界
TicWatch Pro智能手表4G版发布 李志飞意图尝试AI新零售
魅族16Xs高清图赏
5盘Raid5被重建为4盘raid5的数据恢复案例
iOS11beta4怎么样?苹果iOS11 beta4已经发布,你的iPhone想升级先看看这六大改变
苹果iPad广州接受预订
当 CPU 空闲时它都在做什么?
可控硅-向强电冲击的先锋
城际铁路与市域铁路过轨运行适应性分析
交流接触器的压敏电阻作用和选用
基于RFID技术的电子件烟箱系统解决方案
包揽七项葵花奖 参编多项标准 萤石领跑智能家居+物联网云平台行业
以Flash控制器为核心的FPGA在线更新功能实现设计流程介绍