嵌入式系统stm32原理及应用-1.汇编实现LED灯闪

汇编实现LED灯闪

1. 本文目的

基于汇编语言实现最简单的LED灯闪烁。

汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。汇编的作用有很多,这里我们更偏终于对高级语言的理解,高级语言C语言、C++语言有很多概念,如果我们懂汇编,看懂每一行代码编译器生成的汇编代码,我们就能知道这行代码计算机在做什么,从本质上理解高级语言。同时,启动代码使用的也是汇编语言,汇编是高手的必经之路。

2. 硬件平台

  • 开发板CPU: STM32F103RBT6

  • 开发板板载:

    • W25Q32 : SPI1(PA4 PA5 PA6) CS(PA2)

    • 24C02 (PA4 PA5 PA6)CS(PA3)

    • SD卡: SPI1

    • LED0: PA8 LED1: PD2 LED2: PC12

    • KEY_WKUP:PA0 KEY0:PA13 KEY:PA15

    • DS18B20: PA0

    • HS0038: PA1

      扫描二维码关注公众号,回复: 11317194 查看本文章

3. 软件开发环境

MDK uVision V5.24.2.0

4. 实现步骤

  • 新建文件夹 test ,在此处新建 mdk 工程

  • 新建工程 工程位置在这里插入图片描述

  • 选择CPU在这里插入图片描述

  • 添加cortex的接口标准在这里插入图片描述

  • 复制代码添加后编译下载运行在这里插入图片描述

;led.s
LED0 EQU 0x422101a0 
RCC_APB2ENR EQU 0x40021018
GPIOA_CRH EQU 0x40010804

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3 ;AREA命令:堆栈段 不初始化 可读写 8字节对齐
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   ;汇编器支持THUMB指令
                REQUIRE8 ;该文件标识为REQ8属性
                PRESERVE8;汇编文件是8字节对齐
                     
                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}  
				
                END
					

5. 代码分析

1)首先分配一个STACK段,该段不初始化,可读写,按8字节对齐。分配一个大小为Stack_Size的存储空间,并使栈顶的地址为__initial_sp。

2)DCD指令:用于分配一片连续的字存储单元(32bit),并将表达式的值初始化给该字存储单元,类似于C中定义数组并初始化。

3) 开始代码段

AREA |.text|, CODE, READONLY  

THUMB
REQUIRE8
PRESERVE8

这段的意思是,汇编器支持THUMB指令,代码段按8字节对齐。

ENTRY命令:声明整个程式的入口点,入口点有且仅有一个。不管哪种语言,编译器都得有个入口点。

LR 是连接寄存器(Link Register, LR),在ARM体系结构中LR的是用来保存子程序返地址

6. 汇编的基本语法

  • BL:带链接的跳转指令。

  • B:无条件跳转。

  • PUSH和POP:压栈和出栈。

  • LDR是把地址装载到寄存器中(比如R0)。

  • STR是把值存储到寄存器所指的地址中。

  • ORR:按位或操作。

  • BIC: 先把立即数取反,再按位与。

ORR R0,R0,#0x04 ;即将R0中的数或上0x04,再将结果送往R0中。实际意思就是将R0的第二位置1,其他位不变。
  • CMP:是比较两个数,相等或大于则将标志位C置位,否则将C清零。

  • BCC: 是组合指令,实际为B+CC,意思是如果C=0则跳转。

CMP R2,#15; 计算R2-15的值,若是R2<15,则C=0;若是R2>=15,则C=1。
BCC DelayLoop0;若是C=0,则跳到DelayLoop0,若是c=1,则不跳转。

例如 将PA8置1。

MOV R0,#1 ;将立即数1送入R0.

LDR R1,=LED0;将PA8 bit-bond的地址送入R1.

STR R0,[R1];将R0的值,也就是1,送给R1中的值所指向的地址中,也就是PA8的地址。

以上代码段相关指令的介绍结束 。

7. 出现的问题及解决方法

编译后警告:

.\Objects\project.sct(8): warning: L6314W: No section matches pattern *(InRoot$$Sections).

以下转载自 keil mini2440 分散加载文件scatter中(InRoot$$Sections)的理解

分析:
(InRoot Sections)实现对映像的加载,这一段代码就是∗(InRoot" role=“presentation”>Sections)实现对映像的加载,而这一段代码就是∗(InRoot Sections)是__main()的一部分。如果只用汇编代码,没有 C 代码,则这一段加载应该去除。

从启动代码说起

启动代码

1。异常/中断跳转的地址表。

2。堆栈初始化

3。分散加载镜像文件

IMAGE(映像文件)

1个RO,

1个RW,

1个ZI组成。

并且RO的load region和execution region相同,这个里面放置

*(InRoot$$Sections)

主要作用COPY RW区到RAM,然后再RW区后面创建ZI区。

库函数__main函数中有这个段。

,则这一段加载应该去除。

从启动代码说起

启动代码

1。异常/中断跳转的地址表。

2。堆栈初始化

3。分散加载镜像文件

IMAGE(映像文件)

1个RO,

1个RW,

1个ZI组成。

并且RO的load region和execution region相同,这个里面放置

*(InRoot$$Sections)

主要作用COPY RW区到RAM,然后再RW区后面创建ZI区。

库函数__main函数中有这个段。

注释掉"…InRoot…",如图示,则编译不再出现警告。在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/sundm75/article/details/106690231