ARM汇编下GPIO引脚设为输出的公式应用及计算疑问
在ARM汇编中设置GPIO引脚为输出的方法及公式解析
嘿,我来帮你一步步理清这两个问题!
一、ARM汇编中设置GPIO为输出的具体步骤
以你给出的树莓派GPIO基地址0x3F200000(对应BCM2835芯片)和目标引脚17为例,我们先拆解GPIO控制的逻辑,再写汇编代码:
1. 先搞懂GPIO控制寄存器的结构
BCM2835的GPIO有一组功能选择寄存器(GPFSELx),每个寄存器负责控制10个GPIO引脚,每个引脚用3位来配置模式(000=输入,001=输出等):
- GPFSEL0:控制GPIO 0~9(地址偏移0)
- GPFSEL1:控制GPIO 10~19(地址偏移4)
- GPFSEL2:控制GPIO 20~29(地址偏移8)
- ...以此类推,每个寄存器占4字节(32位)
2. 用公式计算目标寄存器和位偏移
你给出的两个公式是分工协作的:
- 寄存器地址公式:
gpio_addr + (4*(GPIO_NR/10))→ 找到对应引脚的GPFSEL寄存器 - 位偏移公式:
((GPIO_NR)%10)*3→ 找到寄存器内对应引脚的起始位
对GPIO17来说:
- 寄存器地址:
0x3F200000 + (4*(17/10)) = 0x3F200000 + 4*1 = 0x3F200004(也就是GPFSEL1) - 位偏移:
(17%10)*3 =7*3=21→ 对应GPFSEL1的第21~23位,设置为001就是输出模式
3. ARM汇编代码实现
下面是具体的汇编代码(以ARM32为例):
@ 定义GPIO基地址 GPIO_BASE EQU 0x3F200000 @ 目标GPIO编号 GPIO_NR EQU 17 .text .global _start _start: @ 步骤1:加载GPIO基地址到r0 LDR r0, =GPIO_BASE @ 步骤2:计算GPFSEL寄存器的偏移量 MOV r1, #GPIO_NR @ 整数除法计算17/10=1(ARM32下通用的10除法实现) MOV r2, #0xCCCCCD MUL r2, r1, r2 LSR r2, r2, #35 @ 右移35位得到整数商1 LSL r2, r2, #2 @ 乘以4,得到偏移量4 ADD r0, r0, r2 @ 现在r0是GPFSEL1的地址:0x3F200004 @ 步骤3:计算位偏移 AND r3, r1, #0x7 @ 取17的余数7(17%10=7) MOV r4, #3 MUL r3, r3, r4 @ 7*3=21,得到位偏移 @ 步骤4:设置输出模式(将第21~23位设为001) MOV r4, #1 LSL r4, r4, r3 @ 把1左移21位,得到0x2000000 LDR r5, [r0] @ 读取当前GPFSEL1的值 ORR r5, r5, r4 @ 或操作,设置对应位为1 STR r5, [r0] @ 写回寄存器 @ 死循环保持程序运行 loop: B loop
二、为什么17除以10再乘以4不会丢失余数7?
你疑惑的点其实是把两个公式的作用搞混了:
GPIO_NR/10是整数除法,得到的是引脚所在的GPFSEL寄存器的索引(比如17属于第1组10~19,索引是1),乘以4是因为每个寄存器占4字节,用来计算寄存器的地址偏移。- 余数7并没有丢失,它被用在另一个公式
((GPIO_NR)%10)*3里,用来计算该寄存器内对应引脚的起始位偏移。
简单说,两个公式是分工的:一个负责找“哪个寄存器”,另一个负责找“寄存器里的哪几位”,余数7是后者的输入,完全没有浪费~
内容的提问来源于stack exchange,提问作者lunarkakka
相关产品推荐
相关产品推荐

