基于Keil 5编写汇编程序
本文目的是通过keil 5 编写汇编程序来熟悉汇编语言的相关知识。这里分为两个部分:第一个部分在Keil上练习汇编的编写和调试,同时了解一下Hex文件的格式;第二个部分是使用汇编进行stm32F103的点灯实验,用实战的方式来加深理解。
目录
- (一)汇编语言
- 1.简介
- 2.指令
- 3.优缺点
- (二)使用Keil 5编写汇编程序
- 1.新建汇编工程
- 2.新建汇编文件
- 3.调试汇编程序
- 4.hex文件简介
- (三)汇编点灯实验
- 1.实验程序
- 2.程序分析
- 3.实验结果
- (四)总结
(一)汇编语言
1.简介
- 汇编语言(Assembly Language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。
2.指令
- 传送指令
包括通用数据传送指令MOV、条件传送指令CMOVcc、堆栈操作指令PUSH/PUSHA/PUSHAD/POP/POPA/POPAD、交换指令XCHG/XLAT/BSWAP、地址或段描述符选择子传送指令LEA/LDS/LES/LFS/LGS/LSS等。 - 逻辑运算
用于执行算术和逻辑运算,包括加法指令ADD/ADC、减法指令SUB/SBB、加一指令INC、减一指令DEC、比较操作指令CMP、乘法指令MUL/IMUL、除法指令DIV/IDIV、符号扩展指令CBW/CWDE/CDQE、十进制调整指令DAA/DAS/AAA/AAS、逻辑运算指令NOT/AND/OR/XOR/TEST等。 - 移位指令
用于将寄存器或内存操作数移动指定的次数,包括逻辑左移指令SHL、逻辑右移指令SHR、算术左移指令SAL、算术右移指令SAR、循环左移指令ROL、循环右移指令ROR等。 - 位操作
包括位测试指令BT、位测试并置位指令BTS、位测试并复位指令BTR、位测试并取反指令BTC、位向前扫描指令BSF、位向后扫描指令BSR等。 - 控制转移
包括无条件转移指令JMP、条件转移指令JCC/JCXZ、循环指令LOOP/LOOPE/LOOPNE、过程调用指令CALL、子过程返回指令RET、中断指令INTn、INT3、INTO、IRET等。 - 串操作
用于对数据串进行操作,包括串传送指令MOVS、串比较指令CMPS、串扫描指令SCANS、串加载指令LODS、串保存指令STOS,这些指令可以有选择地使用REP/REPE/REPZ/REPNE和REPNZ的前缀以连续操作。 - 输入输出
用于同外围设备交换数据,包括端口输入指令IN/INS、端口输出指令OUT/OUTS。
3.优缺点
- 优点
- 可以轻松的读取存储器状态以及硬件I/O接口情况
- 编写的代码因为少了很多编译的环节,可以能够准确的被执行
- 作为一种低级语言,可扩展性很高
- 缺点
- 程序非常单调,特殊指令字符很少,造成了代码的冗长以及编写的困难
- 仍然需要自己去调用存储器存储数据,很容易出现BUG,而且调试起来也不容易;就算完成了一个程序,后期维护时候也需要耗费大量的时间,因为机器的特殊性造成了代码兼容性差的缺陷。
(二)使用Keil 5编写汇编程序
1.新建汇编工程
- 选择
Project
->New uVision Project...
- 给新建的工程命名并保存到到相应的位置,我这里命名为
test
- 由于后面会涉及到STM32的点灯实验,因此这里需要选择使用的硬件支持,这里我使用的是
STM32F103ZET6
所以选择STM32F103ZE
即可
- 勾选
CORE
和Startup
两个选项,点击OK
- 这时左边的
Project
选项中出现了我们刚才新建好的工程
2.新建汇编文件
- 在
Source Group 1
选项下右键选择Add New Item to Group Source Group 1...
- 选择
Asm File(.s)
,输入新建的汇编文件的名字(我这里命名为TEST
)
- 编写汇编程序
AREA MYDATA, DATAAREA MYCODE, CODEENTRYEXPORT __main__mainMOV R0, #10MOV R1, #11MOV R2, #12MOV R3, #13;LDR R0, =func01BL func01;LDR R1, =func02BL func02BL func03LDR LR, =func01LDR PC, =func03B .func01MOV R5, #05BX LRfunc02MOV R6, #06BX LRfunc03MOV R7, #07MOV R8, #08 BX LREND
3.调试汇编程序
- 编译
没有错误,没有警告。 - 配置Debug选项
- 右键工程,选择
Options for Target 'Target1'...
(或者直接点击图中的魔术棒的图标)
- 在
Debug
选项卡下选择使用仿真调试工具(我这里使用的ST-Link
进行程序调试因此选择ST-Link Dehugger
)
- 右键工程,选择
- 点击图中的调试按钮
Start/Stop Debug Session
开始调试
- 进入调试界面如下:
- 动态调试变量
- 在
MOV R0, #10
这里设置断点,运行程序(F5)
可以看到程序运行到这里时停了下来,此时MOV R0, #10
还未执行,我们可以看到R0、R1、R2、R3的值都为0还没有改变。
- 取消原来设置的断点并在
BL function1
这里设置断点,运行程序(F5)
我们可以看到此时R0、R1、R2、R3的值都相应的变为赋给它的值(R0变为0x0000000A
,R1变为0x0000000B
,R2变为0x0000000C
,R3变为0x0000000D
)
- 取消原来设置的断点并在fun03的
BX LR
这里设置断点,运行程序(F5)
通过上面的图片我们可以看到R5、R6、R7、R8的值从全零变为相应的值(R5变为0x00000005
,R6变为0x00000006
,R7变为0x00000007
,R8变为```0x00000008 ``)
- 在
4.hex文件简介
- 生成hex文件
工程选项中选择Output
,然后勾选Create HEX File
,再重新编译一下工程即可生成Hex文件
- Hex文件分析
- 打开生成的Hex文件如下:
Hex文件都是由记录(RECORD)组成的。在HEX文件里面,每一行代表一个记录,每个记录由冒号开始。
- Hex文件分析
- 打开生成的Hex文件如下:
第一个字节 0x02表示本行数据的长度;
第二、三个字节 0x00 0x00表示本行数据的起始地址;
第四个字节 0x00表示数据类型,数据类型有:0x00、0x01、0x02、0x03、0x04、0x05。
后面是数据字节
最后一个字节 0xD0为校验和。
数据类型如下:
00: Data Rrecord 用来记录数据,HEX文件的大部分记录都是数据记录
01: End of File Record 用来标识文件结束,放在文件的最后,标识HEX文件的结尾
02: Extended Segment Address Record 用来标识扩展段地址的记录
03: Start Segment Address Record 开始段地址记录
04: Extended Linear Address Record 用来标识扩展线性地址的记录
05: Start Linear Address Record 开始线性地址记录
(三)汇编点灯实验
1.实验程序
LED0 EQU 0x42218194 ;LED0的地址 (PB5)
RCC_APB2ENR EQU 0x40021018
;GPIOA_CRH EQU 0x40010804
GPIOB_CRL EQU 0x40010C00Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_spAREA RESET, DATA, READONLY__Vectors DCD __initial_sp ; Top of StackDCD Reset_Handler ; Reset HandlerAREA |.text|, CODE, READONLYTHUMBREQUIRE8PRESERVE8ENTRY
Reset_Handler BL LED_Init
MainLoop BL LED_ONBL DelayBL LED_OFFBL DelayB MainLoopLED_InitPUSH {R0,R1, LR}LDR R0,=RCC_APB2ENRORR R0,R0,#0x08 ;使能GPIOB管脚时钟LDR R1,=RCC_APB2ENRSTR R0,[R1]LDR R0,=GPIOB_CRLBIC R0,R0,#0XFF0FFFFF ;配置为模拟输入模式LDR R1,=GPIOB_CRLSTR R0,[R1]LDR R0,=GPIOB_CRLORR R0,R0,#0X00300000 ;配置为通用推挽输出模式LDR R1,=GPIOB_CRLSTR R0,[R1]MOV R0,#1 LDR R1,=LED0STR R0,[R1]POP {R0,R1,PC}LED_ONPUSH {R0,R1, LR} MOV R0,#0 LDR R1,=LED0STR R0,[R1]POP {R0,R1,PC}LED_OFFPUSH {R0,R1, LR} MOV R0,#1 LDR R1,=LED0STR R0,[R1]POP {R0,R1,PC} DelayPUSH {R0,R1, LR}MOVS R0,#0MOVS R1,#0MOVS R2,#0DelayLoop0 ADDS R0,R0,#1CMP R0,#330BCC DelayLoop0MOVS R0,#0ADDS R1,R1,#1CMP R1,#330BCC DelayLoop0MOVS R0,#0MOVS R1,#0ADDS R2,R2,#1CMP R2,#15BCC DelayLoop0POP {R0,R1,PC} END
2.程序分析
- 预定义
LED0 EQU 0x42218194
RCC_APB2ENR EQU 0x40021018
GPIOB_CRL EQU 0x40010C00
这里主要是进行LED管脚位段(bit-band)地址、RCC_APB2ENR外设时钟使能寄存器和GPIOB_CRL端口配置低寄存器地址的设置。其中RCC_APB2ENR外设时钟使能寄存器地址基本上是固定的,不需要改动;而LED管脚和端口配置寄存器的地址需要根据实际情况查阅相关手册进行相应的修改。
这里根据下面红色方框中的公式进行LED管脚位带地址的计算(参照库函数工程版本中sys.h头文件的宏定义)
Cortex™-M3存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入一个字具有对位段区的目标位执行读-改-写操作的相同效果。在STM32F10xxx里,外设寄存器和SRAM都被映射到一个位段区里,这允许执行单一的位段的写和读操作。
关于位段的详细信息请参考《Cortex™-M3技术参考手册》
GPIOB_CRL端口配置低寄存器地址则是在GPIOB的基地址上参照手册上的偏移地址计算得出。
启动初始化
- 分配栈空间
Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp
AREA命令:AREA 命令指示汇编器汇编一个新的代码段或数据段。段是独立的、指定的、不可见的代码或数据块,它们由链接器处理。格式如下:
AREA 段名,段属性1,段属性2,段属性3。。。
AREA STACK, NOINIT, READWRITE, ALIGN=3
NOINIT: = NO Init,不初始化。
READWRITE : 可读,可写。
ALIGN =3 : 2^3 对齐,即8字节对齐。SPACE命令:SPACE 命令保留一个用零填充的存储器块。
所以这段代码意思是:分配一个STACK段,该段不初始化,可读写,按8字节对齐。分配一个大小为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
;这段的意思是,汇编器支持THUMB指令,代码段按8字节对齐
ENTRY
ENTRY命令:声明整个程序的入口点,有且仅有一个。
- 程序正式开始
相关指令:- BL:带链接的跳转指令。当使用该指令跳转时,当前地址(PC)会自动送入LR寄存器。
- B:无条件跳转。
- PUSH/POP:将值存入堆栈/从堆栈取出
- LDR和STR:寄存器的装载和存储指令。
- ORR 按位或操作。
- BIC 先把立即数取反,再按位与。
- CMP:CMP是比较两个数,相等或大于则将标志位C置位,否则将C清零。
- BCC是个组合指令,实际为B+CC,意思是如果C=0则跳转。
3.实验结果
实验说明
我这里采用STM32F103ZET6
开发板进行LED的点灯实验,并且完全采用纯汇编的方式实现间隔一定时间点亮LED灯,因此我这里将之前添加的启动文件给去掉,避免后续编译时产生类似于error: L6235E: More than one section matches selector - cannot all be FIRST/LAST.
的错误,这因为我们这里使用的纯汇编语言编写stm32点灯实验,所以在编写的.s文件中添加了堆栈指针的初始化,而之前仿真调试时没有添加堆栈指针的初始化;如果没有去掉之前添加启动文件,则会因为有两个启动文件导致编译失败。
(四)总结
这次在Keil 5上使用汇编语言进行调试和stm32的点灯实验,让我有了一番不一样的体验;感觉虽然相比于C语言来说,汇编确实要更加难以理解和编程实现并且难以移植到其他硬件上去,但是它的执行心率确实要快了不少;与库函数、寄存器编写的点灯实验相比,汇编语言编写的LED点灯其Hex文件只有477字节,而寄存器和库函数编写的点灯其Hex文件大小分别为3.81KB和5.32KB。由此可见,汇编语言执行的高效和简洁。而且在学习的过程中,也让我更加了解程序是如何被机器识别和执行的,感觉收获很大。
参考文章:
1.汇编语言 (面向机器的程序设计语言)–百度百科
2.ARM汇编基础之基于MDK创建纯汇编语言的STM32工程
3.hex文件说明
4.简单的STM32 汇编程序—闪烁LED
基于Keil 5编写汇编程序相关推荐
- 基于Keil、STM32,用C++编写流水灯程序
关注+星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | 嵌入式专栏 通常来说,在单片机上编程,要么汇编,要么C语言,而用C++进行开发的很少,那么究竟能不能用C++开发 ...
- 基于51单片机的汇编程序:拨码开关控制八位LED实现流水灯
基于51单片机的汇编程序:拨码开关控制八位LED实现流水灯 2022-03-08,51单片机学习笔记 功能 打开K1循环左移,打开K2循环右移,打开K3两侧到中心来回点亮,打开K4单双数位置交替点亮. ...
- 基于keil环境下mm32f327单片机rtthread的移植
基于keil环境下mm32f327单片机rtthread的移植 文章目录 基于keil环境下mm32f327单片机rtthread的移植 前言 一.所需资源 二.创建工程目录 三.复制所需文件到相应文 ...
- 基于 Keil MDK 移植 RT-Thread Nano RTOS到华大半导体HC32F030J8TA
<<<<<正文>>>>> 作者:李彬彬 时间:2021/12/20 微信公众号:airX嵌入式 公司项目合作联系方式:公众号留言/微信159 ...
- keil debug如何在watch直接修改变量值_printf系列教程03_SWO打印输出配置,基于Keil『Debug(printf)Viewer』...
本文原创作者『strongerHuang』 首发于微信公众号『嵌入式专栏』,同时也更新在我的个人网站:EmbeddedDevelop 标签:printf. SWD. SWO. SWV. ITM. JL ...
- Masm for Windows集成开发环境编写汇编程序
由于最近在学习汇编,用的软件是一款叫"Masm for Windows集成开发环境",但是发现该软件的资料比较少,对于我们这样刚刚学习汇编的同学,我查找了很多资料,下面主要是介绍该 ...
- java包裹邮费计算_GitHub - honghailiang/FreightSystem: 基于Java Swing编写的简易运费计算工具...
FreightSystem 基于java Swing编写的运费计算系统 初始化数据 从excel中读取数据,转化为对象(只保存基础数据:序列号.始发站.目的站.省份.100kg以下(元/kg).100 ...
- 基于Java Swing编写的简易运费计算工具
两年前给媳妇儿做的一个基于Java Swing编写的简易运费计算工具,现开源,关键是思路(https://github.com/honghailiang/FreightSystem).主要有两个部分实 ...
- java imgui,发布使用 IMGui 基于 msys2 平台编写的软件
发布使用 IMGui 基于 msys2 平台编写的软件 最近空闲时间为项目编写一个协议测试工具.由于习惯使用 gcc/g++ 所以在 Windows 10 操作系统上选择 msys2 开发.编程语言是 ...
- 【githubshare】基于 C 语言编写的一款 2D 太空射击游戏,已在 Windows 10 和 Ubuntu Linux 16.04 系统上跑通测试
基于 C 语言编写的一款 2D 太空射击游戏:space-shooter.c,已在 Windows 10 和 Ubuntu Linux 16.04 系统上跑通测试. GitHub:github.com ...
最新文章
- python拼音怎么写-Python 中拼音库 PyPinyin 的用法
- 对象后加一个值 php_PHP 对象使用
- Lamport Logical Clock 学习
- IE8下强制浏览器用哪个IE版本渲染页面
- VS.NET 2005 BETA 2 NOT DELAYED?
- java中after什么意思_Java中的即时isAfter()方法
- KM、流程、风险管理的关系分析
- bzoj3555 企鹅QQ
- 51单片机学习 光敏电阻传感器实验
- linux大华客户端,rdesktop 下载-rdesktop(Linux下远程桌面客户端) 1.8.2 官方版 - 河东下载站...
- swiper5 点击图换下一张_软网推荐:骗倒社交好友 制作另类隐藏图
- Kafka 之 HW 与 LEO
- 翻译:SQL Server 2005中的覆盖索引
- Linux下查找归档的内容
- Day-1 货仓选址(绝对值不等式)
- hdu6595 Everything Is Generated In Equal Probability 数学期望
- 微信公众平台初级使用教程
- java小程序计算器_java 小程序 计算器
- uni-app安卓appNFC读卡
- 腾讯点播试看视频功能分享
热门文章
- YYText实现图文混排静态图和动态图同时显示
- 计算机表格怎么往下排序,如何在Excel中随机排序表格中的顺序
- USB设备仿真框架设计指南——6.DSF核心模拟器
- 用户体验测试(UX测试)
- 深度解读汽车域控制器
- 织梦dedecms包装设计生产公司网站模板(中英文版)
- Android学习(二):Android Studio创建并运行Android项目(Hello World ~.~)
- MT7628KN/MT7628AN处理器区别解析,参数对比
- 2018计算机一级证件照,2018下半年软考报名照片要几寸的呢?是要白底照片吗?...
- 2021年大学生可以参加的科创竞赛-最全信息汇总