You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:02:00