从零开始在MDK创建纯汇编语言的STM32工程,并实现用汇编程序完成 每间隔1秒钟闪烁一次LED的程序
序 言
简介
1.什么是汇编语言?
汇编语言又称为符号语言(下文介绍为什么会有这个名字),属于低级语言。它是从机器语言发展而来的。使用简短的英文缩写作为汇编指令,并通过汇编过程将这些汇编指令转换为机器指令。也就是说汇编指令和机器指令的差别在于指令的表示方法上。
2.为什么会出现汇编语言?
早期的机器语言由0和1构成,不方便阅读和修改,以及维护。一连串的二进制数字很难辨别和记忆。所以,程序员们为了方便,就使用一些英文单词作为汇编指令来代替那些纯粹由0和1组成的机器指令。所以汇编语言又称为符号语言。
应用
1.汇编语言 汇编语言是最接近于机器语言的bai编程语言。如果说机器语言是计算机操作的本质那么汇编语言就是最最接近本质的语言。汇编语言操作直接面向硬件。所以我们在使用汇编语言的时候,我们能够感知计算机的运行过程和原理,从而能够对计算机硬件和应用程序之间的联系和交互形成一个清晰的认识。这也是最能够锻炼编程者编程思维逻辑的,只有这样,学习者才能形成一个软、硬兼备的编程知识体系,这是任何高级语言都无法给予的,相对于繁复的高级语言,汇编语言指令集合更简约,指令操作更直接,从汇编开始学习更符合循序渐进的学习原理。所以,对于计算机技术初学者或者自学者,汇编语言重要性无可替代 2.汇编语言之于高级语言,不否认在应用层面高级语言占据了软件开发市场的绝大部分。也正是这种现象误导了学习者甚者是教育者,所以目前高校计算机专业的现状是,专业课程中C语言、C++、Java等高级语言一应俱全而毕业的学生却连简单的程序都不能编写。为什么?听不懂、学不会。这就是缺乏基础造成的。汇编语言才是计算机技术的基础,而不是常说的C语言。之所以说汇编重要,其一个重要的原因就是,汇编语言能够让你更好的理解高级语言,尤其是高级语言中的C语言。汇编语言对于内存的操作都是基于内存地址的,而C语言中最令人头疼的指针概念,说白了就是内存的地址。指针的学习和应用中最头疼的就是在指针这个抽象的概念和实际的内存单元之间建立思维映射,而这些恰恰是我们在汇编语言学习中频繁做的一件平常事。另外,对于C语言中的数据类型、形参实参、函数调用、全局变量、局部变量等概念及操作,我们都可以用汇编语言中的一些操作相关联把这些抽象的概念和过程通过汇编语言形成一个具体的映像,深度剖析这样我们才能真正的学会、学好C语言。 有了汇编和C的基础,那些所谓的面向对象的语言学习起来就更为顺畅了,奉劝那些好高骛远的学习者,踏踏实实的从汇编开始吧。古云:磨刀不误砍柴工啊! 3.汇编语言之于应用 很多学习者放弃对于汇编语言的学习,是因为高级语言的开发更容易找到工作。这个理由也是我见到过的最现实的。但是,这里面明显存在着认识误区。首先,我们的学习是一个系统过程,我们的知识结构不是一个单一课程所能够建立的。所以,学习汇编的目的并不是非要用汇编去挣饭钱。因为汇编语言对于一个编程人员所应该具备的基本素质的培养和形成得意义是非常重大的,这在前文中已经分析了,不再赘述;其次,汇编本身也是很重要的应用技术。由于学习者,尤其是在校的学生,平时接触的最多的是纯软件的东西。所以,觉得五花八门的软件才是计算机技术应用的舞台。那么这些人最终会成为那位博主提到的那些工作后才意识到汇编的作用的“师兄”。汇编的操作由于跟硬件紧密相关。所以,很多硬件设施的嵌入式编程使用的都是使用的汇编语言,因为汇编语言更直接、更有效率。我们现在的数码产品很多,而这些数码产品赖以生存的芯片、主板等。都包含了嵌入式程序,而这些程序中。汇编语言的使用是相当重要的。一.项目说明
本文博主将会为大家介绍汇编语言的基本应用,以及从零开始在MDK创建纯汇编语言的STM32工程,博主希望大家能在这里收获知识。
项目目标:在Keil下完成一个汇编程序的编写,学习动态调试变量;并注意观察最终生成 hex文件的各段的大小,以及Hex文件前8个字节内容,解释其含义。
二.项目实战
1) 从零开始在MDK创建纯汇编语言的STM32工程。
测试代码
AREA MYDATA, DATA
AREA MYCODE, CODE
ENTRY
EXPORT __main
__main
MOV R0, #10
MOV R1, #11
MOV R2, #12
MOV R3, #13
;LDR R0, =func01
BL func01
;LDR R1, =func02
BL func02
BL func03
LDR LR, =func01
LDR PC, =func03
B .
func01
MOV R5, #05
BX LR
func02
MOV R6, #06
BX LR
func03
MOV R7, #07
MOV R8, #08
BX LR
输出HEX文件
观察HEX各段的大小
Code:指程序中代码的字节数
RO-data:指程序中定义的常量字节数
RW-data :程序中已初始化的变量字节数
ZI-Data :程序中未初始化的变量字节数
可计算出flash和RAM的占用情况:
flash = Code + RO-data + RW-data
ram = RW-data + ZI-data
hex、bin、flash三者的大小关系
在烧录程序时往往将hex文件烧录到flash中,但hex文件的大小和flash的大小没什么必然的关系,hex文件大于单片机flash的大小也能烧录到单片机中。原因在于真正写入flash的不是hex文件,而是hex文件中的bin文件。有些软件直接生成的就是bin文件,而不是hex文件。
如图,其中第一行020000040800f8中,可以看做是0x02 0x00 0x00 0x04 0x08 0x00 0xf8,其前四个字节和最后一个字节有特殊含义。中间为数据
第一个0×02表示该行数据中有两个数据
第二个,第三个0x00 0x00表示本行数据的起始地址位
第四个字节有0x00 0x01 0x02 0x03 0x04 0x05,分别有以下含义
'00’Data Rrecord:用来记录数据,HEX文件的大部分记录都是数据记录
'01’文件结束记录:用来标识文件结束,放在文件的最后,标识HEX文件的结尾
'02’扩展段地址记录:用来标识扩展段地址的记录
'03’开始段地址记录:开始段地址记录
'04’扩展线性地址记录:用来标识扩展线性地址的记录
'05’开始线性地址记录:开始线性地址记录
最后一个字节0xf8为校验和。校验和= 0x100 - 累加和。在nodepad++中,如果该校验和不是绿色,则表示该校验和是错的。
注意,0×04标识扩展线性地址的记录,所以如上图中的020000040002f8中,拓展地址是0002。那么第二行数据的起始地址就是0002c000,即0x0002c000开始
2) 编写一个简单的汇编语言程序
博主在这里先向大家介绍一些汇编语言常用的语法
1、堆栈相关指令
push:把一个32位的操作数压入堆栈中。这个操作导致esp被减4。esp被形象地称为栈顶。我们认为顶部是地址小的区域,那么,压入堆栈的数据越多,这个堆栈也就越堆越高,esp也就越来越小。在32位平台上,esp每次减少4(字节)。
sub:减法。第一个参数是被减数所在的寄存器;第二个参数是减数。(对应的还有add指令。)
add:加法。
ret:返回。相当于跳转回调用函数的地方。(对应的call指令来调用函数,返回到call之后的下一条指令。)(本质相当于pop+jmp)
call:调用函数。(本质相当于push+jmp)
2、数据传送指令
mov:数据移动。第一个参数是目的,第二个参数是来源。在C语言中相当于赋值号。
xor:异或。这虽然是逻辑运算的指令,但是有趣的是,xor eax,eax这样的操作常常用来代替mov eax,0。好处是速度更快,占用字节数更少。(见到xor eax,eax,应该马上明白这是清零操作。)
lea:取得地址(第二个参数)后放入到前面的寄存器(第一个参数)中。(mov不支持后一个操作数写成寄存器减去数字,但是lea支持,所以可以用lea来代替它。)
当然这些都是部分而已,这里博主不能将所有的语法都列出来,所以博主为大家推荐了一位大牛的博客链接: 大牛博客.
接下来博主来写一个基础的汇编程序
编写一个汇编程序,实现计算1+2+3+……+10,并将计算结果保留在R4寄存器中。
area add,code,readonly
entry
start
mov r0,#0
mov r1,#1
loop
add r0,r0,r1
add r1,r1,#1
cmp r1,#11
bne loop
mov r4,r0
str r0,[r4]
end
3) 用汇编程序完成 每间隔1秒钟闪烁一次LED的程序。
首先我们先创建一个LED的工程,创建工程的步骤和上面的步骤是基本一样的
我们要注意的是到这一步我们不用选择直接跳过即可
然后新建一个led汇编语言程序
添加
编写程序
LED0 EQU 0x422101a0
RCC_APB2ENR EQU 0x40021018
GPIOA_CRH EQU 0x40010804
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
AREA |.text|, CODE, READONLY
THUMB
REQUIRE8
PRESERVE8
ENTRY
Reset_Handler
BL LED_Init
MainLoop BL LED_ON
BL Delay
BL LED_OFF
BL Delay
B MainLoop
LED_Init
PUSH {R0,R1, LR}
LDR R0,=RCC_APB2ENR
ORR R0,R0,#0x04
LDR R1,=RCC_APB2ENR
STR R0,[R1]
LDR R0,=GPIOA_CRH
BIC R0,R0,#0x0F
LDR R1,=GPIOA_CRH
STR R0,[R1]
LDR R0,=GPIOA_CRH
ORR R0,R0,#0x03
LDR R1,=GPIOA_CRH
STR R0,[R1]
MOV R0,#1
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
LED_ON
PUSH {R0,R1, LR}
MOV R0,#0
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF
PUSH {R0,R1, LR}
MOV R0,#1
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
Delay
PUSH {R0,R1, LR}
MOVS R0,#0
MOVS R1,#0
MOVS R2,#0
DelayLoop0
ADDS R0,R0,#1
CMP R0,#330
BCC DelayLoop0
MOVS R0,#0
ADDS R1,R1,#1
CMP R1,#330
BCC DelayLoop0
MOVS R0,#0
MOVS R1,#0
ADDS R2,R2,#1
CMP R2,#15
BCC DelayLoop0
POP {R0,R1,PC}
NOP
END
我们这个程序是通过控制I/O口PA8电位的变化从而使LED灯发生变化,由于博主使用的开发板LDE没有在PA8而是在PC1和PC2,所以博主外接了一个LED灯
效果如下
至此我们的实战完成,之后博主会陆续发布与汇编相关的内容,希望各位继续关注
三. 结语
这个实战对于我们了解汇编语言有着重要的意义,通过这次实战我们了解到了,从零开始在MDK创建纯汇编语言的STM32工程的方法,以及对于用汇编语言编程有了更加深刻的认识,这对于以后我们进一步学习使用stm32,有着比较好的帮助,所以博主在这里希望各位也要好好学习,争取掌握这个知识点。还有就是希望各位有问题可以联系博主,博主很乐意和各位一起学习。请您关注我个人的微信公众号,微信搜索h生活剪影很期待您的关注,我们一起进步。