STM32
直播中

vinww特烦恼

8年用户 1112经验值
擅长:存储技术
私信 关注
[问答]

如何去实现基于汇编语言的LED灯闪烁呢

什么是汇编语言?汇编语言有何作用?
如何去实现基于汇编语言的LED灯闪烁呢?

回帖(2)

郭燕

2021-11-26 10:30:02
汇编实现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


  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
                                       
                                               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. 出现的问题及解决方法

  编译后警告:
  .Objectsproject.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…",如图示,则编译不再出现警告。
  
举报

jinyi7016

2021-11-29 09:40:50
汇编是哪种芯片的呢,是51的还是ARM的呢
举报

更多回帖

发帖
×
20
完善资料,
赚取积分