准备

Windows + protues

Ubuntu虚拟机:用于编译

绘制原理图选择stm32f103c8元件

stm32f10X参考手册

stm32f103c8t6.h:由st公司提供的寄存器定义头文件,主要是查看寄存器地址

时钟

define PERIPH_BASE ((uint32_t)0x40000000)

define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)

define RCC_BASE (AHBPERIPH_BASE + 0x1000)

RCC_APB2ENR 偏移0x18:0x40021018 bit2=1(0b100=4)

GPIOA01属性

define PERIPH_BASE ((uint32_t)0x40000000)

define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)

GPIOA_BASE 0x40010800

端口配置低寄存器(GPIOx_CRL) (x=A..E)
偏移地址:0x00

GPIOA_CRL 0x40010800

CNF0[3:2] 00:推挽输出模式

MODE0[1:0] 11:输出模式,最大速度50MHz

0b0011 = 0x3 [3:0] = 0b0011

GPIOA01输出

端口输出数据寄存器(GPIOx_ODR) (x=A..E)
地址偏移:0Ch(0x0c)

GPIOA_ODR 0x4001080C

bit0 = 1

向量表

主要是堆栈指针+Reset_Handler部分

.word

.word

    .syntax unified
    .cpu cortex-m3
    .thumb

    .section .text
    .global Reset_Handler
    .global _start

    /* 向量表:放在 0x08000000 开头 */
    .word   0x20005000          @ 初始栈顶:SRAM 末地址(20KB -> 0x20005000)
    .word   Reset_Handler       @ 复位向量,指向 Reset_Handler(Thumb 地址)

    .thumb_func
Reset_Handler:
_start:
    /* 1. 使能 GPIOA 时钟:RCC_APB2ENR[2] = 1 */
    ldr r0, =0x40021018         @ RCC_APB2ENR
    ldr r1, [r0]
    orr r1, r1, #0x4            @ IOPAEN = 1
    str r1, [r0]

    /* 2. 配置 PA0 为 50MHz 推挽输出:GPIOA_CRL[3:0] = 0b0011 */
    ldr r0, =0x40010800         @ GPIOA_CRL
    ldr r1, [r0]
    bic r1, r1, #0x0F           @ 清除 PA0 的 4 位
    orr r1, r1, #0x03           @ MODE0=11 (50MHz), CNF0=00 (GP 推挽)
    str r1, [r0]

    /* 3. 置位 PA0 输出高电平:GPIOA_ODR[0] = 1 */
    ldr r0, =0x4001080C         @ GPIOA_ODR
    ldr r1, [r0]
    orr r1, r1, #0x1            @ PA0 = 1
    str r1, [r0]

loop:
    b   loop                    @ 死循环,保持灯亮

编译链接

使用Ubuntu16中apt包中的gcc-arm-none-eabi交叉编译工具链(支持mcu cortex-m3内核)

# 1) 编译成目标文件
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb led.s -o led.o

# 2) 链接到 STM32 Flash 起始地址 0x08000000
arm-none-eabi-ld -Ttext=0x08000000 led.o -o led.elf

# 3) 导出为 hex,给 Proteus 用
arm-none-eabi-objcopy -O ihex led.elf led.hex

最终成功点亮小灯!
led_light