ARM架构与编程——实战:按键控制LED
汇编实现按键控制LED
一、纯汇编点灯
1.1 程序流程图
1.2 delay函数流程图
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按键原理图

-
我们使用KEY1来控制红色LED:按下KEY1则灯亮,松开后灯灭
-
KEY1用的是PA0引脚

2.2 按键操作流程
1. 使能GPIOA模块
RCC_APB2ENR地址:0x40021000 + 0x18
设置Bit2为1,开始GPIO时钟

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

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

三、按键点灯
整合汇编点灯及按键输入功能即可
// 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;
}