ARM架构与编程——实战:按键控制LED

汇编实现按键控制LED

一、纯汇编点灯

1.1 程序流程图

Created with Raphaël 2.3.0 start 使能GPIO模块 设置引脚为GPIO功能 设置引脚为输出 设置引脚输出高电平 delay 设置引脚输出低电平 delay

1.2 delay函数流程图

Created with Raphaël 2.3.0 start R0减1 等于0? 返回LR所示地址 yes no

1.3 程序实现

寄存器操作
对于寄存器的操作,主要涉及读、修改、写。

  • 读可以使用LDR指令,代码为LDR R1, [R0]

  • 写使用STR指令,代码为STR R1, [R0]

  • 修改稍微复杂,清除位使用BIC或AND指令,设置位使用ORR指令

LDR R0, =(1<<20) | (1<<21)
BIC R1, R1, R0              ; 清除R1的bit20, bit21
LDR R0, =(1<<20)
ORR R1, R1, R0              ; 设置R1的bit20
  • 函数里的条件判断
    比如减1操作,代码为SUB R0, R0, #1
    但是顺便使用减1后的结果影响程序状态寄存器,代码为SUBS R0, R0, #1

  • 程序的调用与返回

    • 传参,代码为LDR R0, =VAL
    • 调用,代码为BL delay,它顺便把下一条指令的地址保存在LR寄存器了
    • 返回,代码为MOV PC, LR

二、汇编实现按键操作

2.1 按键原理图

  • 100ASK STM32F103按键原理图
    ARM架构与编程——实战:按键控制LED_第1张图片

  • 我们使用KEY1来控制红色LED:按下KEY1则灯亮,松开后灯灭

  • KEY1用的是PA0引脚
    在这里插入图片描述

2.2 按键操作流程

1. 使能GPIOA模块

RCC_APB2ENR地址:0x40021000 + 0x18
设置Bit2为1,开始GPIO时钟

ARM架构与编程——实战:按键控制LED_第2张图片
2. 设置引脚为GPIO输入

GPIOA_CRL地址:0x40010800 + 0x00
设置Bit3,Bit2 为 01 ;浮空输入
设置Bit1,Bit0 为 00 ;选择输入模式

ARM架构与编程——实战:按键控制LED_第3张图片
3. 读取引脚值

GPIOA_IDR 地址:0x40010800 + 0x08
PA0用到的IO口为端口0,我们只需要判断端口的输入值即可(即Bit0)

ARM架构与编程——实战:按键控制LED_第4张图片

三、按键点灯

整合汇编点灯及按键输入功能即可

// start.s 启动文件
                PRESERVE8
                THUMB


; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT	__Vectors

__Vectors      	DCD		0
				DCD     Reset_Handler              ; Reset Handler

                AREA    |.text|, CODE, READONLY
                
; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  mymain
					
                LDR     sp, =(0x20000000+0x10000)
                BL		mymain
                ENDP
				END

// main.c 通过指针操作寄存器地址实现按键点灯

void delay(int d)
{
    while(d--);
}

int mymain(void)
{
    unsigned int *pReg;
    unsigned int *pRegA;
    unsigned int *pRegB;
    
    /* 使能GPIOB ,GPIOA*/
    pReg = (unsigned int *)(0x40021000 + 0x18);
    *pReg |= (1 << 3) | (1 << 2);
    
    /* 设置GPIOB0为输出引脚 */
    pRegB = (unsigned int *)(0x40010C00 + 0x00);
    *pRegB |= (1 << 0);
    
    /* 设置GPIOA0为输入 */
    pRegA = (unsigned int *)(0x40010800 + 0x00);
    *pRegA &= ~(3);     /* mode0 = 0b00 */
    *pRegA &= ~(3 << 2);    /* cnf0 = 0b00 */ 
    *pRegA |= (1 << 2);
    
    /* GPIOB ouput data register */
    pRegB = (unsigned int *)(0x40010C00 + 0x0C);
    
    /* GPIO input data register */
    pRegA = (unsigned int *)(0x40010800 + 0x08);
    
    while (1)
    {
        if ((*pRegA & (1 << 0)) == 0)
        {
            /* GPIOB输出0 */
            *pRegB &= ~(1 << 0);
            
        }
        else
        {
            /* GPIOB输出1 */
            *pRegB |= (1 << 0);
        } 
    }
    
    return 0;
}

你可能感兴趣的:(ARM架构与编程学习,arm开发,汇编)