You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何学习用裸机汇编实现STM32F103C8T6的PC13引脚LED闪烁?

裸机汇编实现STM32F103C8T6 PC13 LED闪烁:从手册查阅到代码实现

先帮你把几个核心困惑捋清楚,再一步步教你怎么从官方文档挖信息,最后给你可运行的汇编代码——完全不用怕那些所谓的“魔法地址”,本质都是有章可循的硬件寄存器操作。

为什么必须配置外设时钟?

Arduino框架把所有底层脏活都替你做了,包括默认开启常用外设的时钟,但STM32的硬件设计逻辑是所有外设默认关闭时钟,目的是最大限度省电。你要操作GPIOC,必须先给它“通电”(打开时钟),否则所有对GPIOC寄存器的操作都是无效的。这不是多余步骤,是嵌入式硬件的基本设计规则。

所谓“魔法地址/数字”到底是什么?

这些就是STM32内存映射里的硬件寄存器地址和配置值,一点都不“魔法”——只是你还没学会从官方手册里找它们而已。比如:

  • GPIOC的所有寄存器都映射到固定内存区间(从0x40011000开始)
  • 控制GPIOC时钟的寄存器是RCC_APB2ENR,地址0x40021018,其中第4位对应GPIOC的时钟使能,写(1 << 4)就能打开它

怎么从官方手册里找需要的信息?

你提到的RM0008(STM32F1参考手册)和PM0056(Cortex-M3编程手册)是核心,不用全看,按需求查对应章节:

1. 确定外设时钟配置:查RCC章节

打开RM0008,翻到第6章 复位和时钟控制(RCC)

  • 找到「APB2外设时钟使能寄存器(RCC_APB2ENR)」,看位定义:第4位IOPCEN就是GPIOC的时钟使能位,置1开启时钟。
  • 记下寄存器地址:0x40021018(手册会给每个寄存器的偏移地址,加上RCC基地址0x40021000就能算出)

2. 配置GPIO引脚:查GPIO章节

翻到RM0008的第9章 通用和复用功能I/O(GPIO和AFIO)

  • PC13属于GPIOC的高8位引脚(引脚8-15对应CRH寄存器,0-7对应CRL),所以要配置GPIOC_CRH寄存器(地址0x40011004,GPIOC基地址0x40011000加偏移0x04
  • 每个引脚占4位,PC13对应第20-23位(计算方式:(13-8)*4 = 20)。要配置成通用推挽输出,4位配置值是0x02(二进制0010:CNF位设为00表示推挽输出,MODE位设为10表示2MHz输出速度)
  • 控制引脚电平的是GPIOC_ODR寄存器(地址0x4001100C),第13位对应PC13:置1是高电平(LED灭,因为STM32F1的PC13 LED是低电平点亮),置0是低电平(LED亮)

3. 汇编编程基础:查Cortex-M3编程手册

打开PM0056,看第8章 汇编语言编程,了解ARM Cortex-M3的汇编指令(比如LDR/STR访问内存,MOV/ORR操作寄存器,B跳转实现循环等),以及复位向量表的要求(必须先定义堆栈指针,再定义复位入口)

裸机汇编实现LED闪烁的代码示例

下面是基于ARM汇编的代码,直接可以烧录到STM32F103C8T6运行:

; 定义寄存器地址
RCC_APB2ENR  EQU 0x40021018
GPIOC_CRH    EQU 0x40011004
GPIOC_ODR    EQU 0x4001100C

; 复位向量表
            AREA    RESET, DATA, READONLY
            EXPORT  __Vectors
__Vectors
            DCD     0x20001000  ; 堆栈指针(STM32F103C8T6有20KB RAM,栈顶设为0x20001000)
            DCD     Reset_Handler  ; 复位入口
            ALIGN

; 复位处理函数
            AREA    CODE, READONLY
Reset_Handler
    ; 1. 开启GPIOC时钟
    LDR     R0, =RCC_APB2ENR
    LDR     R1, [R0]
    ORR     R1, R1, #(1<<4)  ; 置位IOPCEN位
    STR     R1, [R0]

    ; 2. 配置PC13为通用推挽输出(2MHz)
    LDR     R0, =GPIOC_CRH
    LDR     R1, [R0]
    BIC     R1, R1, #0xF000000  ; 清除PC13对应的4位(第20-23位)
    ORR     R1, R1, #0x2000000   ; 设置PC13为推挽输出,2MHz
    STR     R1, [R0]

    ; 3. 循环翻转LED电平
Loop
    ; 点亮LED:PC13置0
    LDR     R0, =GPIOC_ODR
    LDR     R1, [R0]
    BIC     R1, R1, #(1<<13)
    STR     R1, [R0]
    BL      Delay  ; 延时

    ; 熄灭LED:PC13置1
    LDR     R0, =GPIOC_ODR
    LDR     R1, [R0]
    ORR     R1, R1, #(1<<13)
    STR     R1, [R0]
    BL      Delay  ; 延时

    B       Loop  ; 循环

; 简单延时函数
Delay
    LDR     R2, =0x3FFFFF
Delay_Loop
    SUBS    R2, R2, #1
    BNE     Delay_Loop
    BX      LR

            END

总结学习路径

  1. 先从数据手册确认引脚对应关系(比如PC13属于哪个GPIO端口)
  2. 参考手册的RCC章节找外设时钟使能方法
  3. 参考手册的GPIO章节找引脚配置和电平控制的寄存器
  4. 编程手册学习汇编指令和Cortex-M3的编程模型
  5. 动手写代码,逐步验证每一步(比如先只配置时钟和GPIO,看LED是否能点亮,再加循环翻转)

内容的提问来源于stack exchange,提问作者nalzok

火山引擎 最新活动