在Keil下完成一个汇编程序的编写

摘要:在学习STM32的路上开始是学的C语言尚未进行对汇编进行学习,因此抽出时间来学习一下在keil下的汇编语言。

一、 汇编语言简介

汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地址符号(Symbol)或标号(Label)代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。普遍地说,特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。

许多汇编程序为程序开发、汇编控制、辅助调试提供了额外的支持机制。有的汇编语言编程工具经常会提供宏,它们也被称为宏汇编器

汇编语言不像其他大多数的程序设计语言一样被广泛用于程序设计。在今天的实际应用中,它通常被应用在底层,硬件操作和高要求的程序优化的场合。驱动程序、嵌入式操作系统和实时运行程序都需要汇编语言。

具体学习参考请该博客什么是汇编语言

有兴趣的同学可以阅读下这篇汇编语言笔记(全)

二、 初步分析

实验步骤参考ARM汇编基础之基于MDK创建纯汇编语言的STM32工程

  • 新建完成

在这里插入图片描述

  • 仿真器我的是ST-Link和小麦大叔的配置不同,但影响不大。

  • 由于博主没有对汇编语言进行注释,所以我进行了一定的注释

 AREA MYDATA, DATA  ;AREA 功能:指示汇编器 汇编一段新的代码或数据区。在汇编时,必须至少有一个ARME指示符。DATA 包含数据,但不包含指令

	
 AREA MYCODE, CODE;定义此标号是程序内的数据区
	ENTRY;执行汇编程序的入口点,至少一个源文件中只能有一个
	EXPORT __main//EXPORT ;明全局变量 _main 这个相当于函数入口

__main
	MOV R0, #10 传送指令——MOV DST,SRC 指令的基本功能:(DST)<-(SRC) 将原操作数(字节或字)传送到目的地址。即将10写入RO
	MOV R1, #11
	MOV R2, #12
	MOV R3, #13
	;LDR R0, =func01;将func01的数据读入到R0中

	BL	func01	;跳转指令但跳转之前,会在寄存器R14 中保存PC 的当前内容
	;LDR R1, =func02;将func02的数据读入到R1中
	BL	func02
	
	BL 	func03
	LDR LR, =func01
	LDR PC, =func03
	B .		;死循环
		
func01
	MOV R5, #05
	BX LR	;跳转到LR寄存器里的地址执行
	
func02
	MOV R6, #06
	BX LR  ;指令跳转到指令中所指定的目标地址
	
func03
	MOV R7, #07
	MOV R8, #08	
	BX LR	;跳转到LR寄存器里的地址执行

参考资料:ARM汇编语言伪指令
详解汇编语言各种指令的解释与用法

  • 分析

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

由实验结果分析,分别对寄存器进行了赋值练习且结果与之前分析一致。

  • 分析HEX文件

在这里插入图片描述

首行 0x02 0x00 0x00 0x04 0x08 0x00 0xF2
第一个字节 0x02表示本行数据长度;
第二、三字节 0x00 0x00表示本行数据的起始地址;
第四字节 0x04表示数据类型,数据类型有:0x000x010x020x030x040x05
‘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:开始线性地址记录
然后是数据,0x08 0x00
最后一个字节 0xf2为校验和。

三、 实验分析

3.1 实验要求

用汇编程序完成 每间隔1秒钟闪烁一次LED的程序

3.2 新建工程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

成功新建
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
添加LED.s文件

在这里插入图片描述

新建工程完成。

3.3 软件代码

LED0 EQU 0x422201b4
RCC_APB2ENR EQU 0x40021018
GPIOC_CRH EQU 0x40011004                           ;预定义


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指令,代码段按8字节对齐
                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}			;将R0,R1,LR入栈
                
                LDR R0,=RCC_APB2ENR
                ORR R0,R0,#0x04
                LDR R1,=RCC_APB2ENR
                STR R0,[R1]
                
                LDR R0,=GPIOC_CRH
                BIC R0,R0,#0XFF0FFFFF   ;配置为模拟输入模式
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
                
                LDR R0,=GPIOC_CRH
                ORR R0,R0,#0X00300000   ;配置为通用推挽输出模式,最大速度为50MHz
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
                
                MOV R0,#1			;将立即数1送入R0.
                LDR R1,=LED0		;将PC13 bit-bond的地址送入R1.
                STR R0,[R1]			;将R0的值,也就是1,送给R1中的值所指向的地址中
             
                POP {R0,R1,PC}      ;将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         ;加法,R0=R0+1
                CMP R0,#330           ;计算R0-330的值,R0<330,则C=0;否则C=1。
                BCC DelayLoop0        ;若是C=0,则跳到DelayLoop0,若是c=1,则不跳转
        
                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

3.4 编译烧录

在这里插入图片描述

通过该博客成功解决More than one section matches selector - cannot all be FIRST/LAST的解决方法(包含只有一个启动文件的解决方法)

3.5 实验结果

汇编语言点灯实验结果

四、 总结

通过此次实验,我基本了解了汇编语言的一些指令以及作用。通过上手实践编写汇编语言的点灯程序,掌握了一些基本的汇编程序编译知识。中途遇到了很多问题,特别感谢我的老师和同学的帮助。

五、参考资料

1.ARM汇编语言伪指令

2.详解汇编语言各种指令的解释与用法

3.基于MDK下的STM32F103纯汇编语言练习

  • 4
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的汇编语言程序,用于在Keil环境下编写STM32F407串口程序: ``` ; STM32F407串口程序 ; 串口配置:波特率9600,无校验位,8位数据位,1位停止位 ; 定义寄存器 USART1_BASE equ 0x40011000 USART_SR equ 0x00 USART_DR equ 0x04 USART_BRR equ 0x08 USART_CR1 equ 0x0C ; 定义常量 AHB1ENR equ 0x40023830 USART1EN equ 0x00000010 RCC_CFGR equ 0x40023808 PLL_M equ 8 PLL_N equ 336 PLL_P equ 2 PLL_Q equ 7 SYSCLK equ 168000000 ; 初始化USART1 init_usart1: ; 使能USART1时钟 ldr r0, =AHB1ENR ldr r1, [r0] orr r1, #USART1EN str r1, [r0] ; 设置USART1波特率 ldr r0, =USART1_BASE mov r1, #0 mov r2, #0 mov r3, #0 ldr r4, =SYSCLK add r4, r4, #PLL_N mov r5, #0 mov r6, #0 mov r7, #0 mov r8, #0 mov r9, #0 mov r10, #0 mov r11, #0 mov r12, #0 mov r13, #0 mov r14, #0 mov r15, #0 bl set_usart_baud_rate ; 配置USART1 ldr r0, =USART1_BASE ldr r1, [r0, #USART_CR1] orr r1, #0x2000 orr r1, #0x0008 orr r1, #0x0004 str r1, [r0, #USART_CR1] bx lr ; 发送一个字符 send_char: ldr r0, =USART1_BASE ldr r1, [r0, #USART_SR] tst r1, #0x0080 bne send_char strb r2, [r0, #USART_DR] bx lr ; 发送一个字符串 send_string: push {r4, r5, lr} ldr r4, =0 ldr r5, =0 loop: ldrb r5, [r0, r4] cmp r5, #0 beq end_loop bl send_char add r4, #1 b loop end_loop: pop {r4, r5, pc} ; 设置USART波特率 set_usart_baud_rate: push {r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, lr} mov r4, #PLL_M mov r5, #PLL_N mov r6, #PLL_P mov r7, #PLL_Q mul r5, r5, r8 udiv r5, r5, r4 udiv r9, r8, r4 sub r10, r8, r9 mul r7, r7, r10 udiv r7, r7, r9 lsl r7, r7, #4 orr r6, r6, r7 str r6, [r0, #USART_BRR] pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, pc] ; 主程序 main: ; 初始化USART1 bl init_usart1 ; 发送一个字符串 ldr r0, =message bl send_string ; 无限循环 loop: b loop ; 数据段 message: dc.b "Hello, World!", 0 ``` 该程序使用汇编语言编写,实现了STM32F407的串口功能。首先,`init_usart1`函数用于初始化USART1,包括使能USART1时钟,设置波特率和配置USART1。然后,`send_char`函数用于发送一个字符,`send_string`函数用于发送一个字符串。最后,`main`函数初始化USART1并发送一个字符串,然后进入一个无限循环。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值