1. 环境搭建与LED闪烁
任务目标
本案例完成两项工作:搭建STM32最小开发环境(编译器+烧录工具+工程框架),并实现板载LED以1Hz频率闪烁,以此验证GPIO输出配置与基本延时功能的正确性。
环境与依赖
- 硬件:STM32F103C8T6最小系统板(蓝色Pill板),板载LED接PC13(低电平点亮),ST-Link V2烧录器
- 软件:
arm-none-eabi-gcc(版本≥10)、st-flash或OpenOCD、make;或直接使用STM32CubeIDE(本案例以命令行方式演示,CubeIDE操作路径相同) - 标准外设库:STM32F1xx标准外设库(或直接操作寄存器,本案例采用寄存器方式以保持最小依赖)
完整实现
以下代码直接操作寄存器完成GPIO配置与延时,不依赖HAL库,仅需stm32f1xx.h头文件中的寄存器地址定义。新建main.c与Makefile两个文件即可编译。
// main.c — STM32F103C8T6 LED闪烁 (PC13, 1Hz)
#include "stm32f1xx.h"
// 简单延时:约1ms @ 8MHz内部时钟(无外部晶振)
static void delay_ms(uint32_t ms) {
for (uint32_t i = 0; i < ms * 800; i++) {
__NOP();
}
}
int main(void) {
// 1. 使能GPIOC时钟(APB2总线,RCC寄存器)
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
// 2. 配置PC13为推挽输出,最大速度2MHz
// CNF13=00(推挽), MODE13=10(2MHz输出)
GPIOC->CRH &= ~(0xF << 20); // 清除CNF13+MODE13位
GPIOC->CRH |= (0x2 << 20); // MODE13=10, CNF13=00
while (1) {
GPIOC->BRR = (1 << 13); // 置低 → LED亮
delay_ms(500);
GPIOC->BSRR = (1 << 13); // 置高 → LED灭
delay_ms(500);
}
}
# Makefile — 编译与烧录
PREFIX = arm-none-eabi-
CC = $(PREFIX)gcc
OBJCOPY = $(PREFIX)objcopy
CFLAGS = -mcpu=cortex-m3 -mthumb -Wall -O2 -nostdlib -Tstm32f103.ld
TARGET = led_blink
all: $(TARGET).bin
$(TARGET).elf: main.c
$(CC) $(CFLAGS) -o $@ $^
$(TARGET).bin: $(TARGET).elf
$(OBJCOPY) -O binary $< $@
flash: $(TARGET).bin
st-flash write $< 0x08000000
clean:
rm -f $(TARGET).elf $(TARGET).bin
链接脚本stm32f103.ld需定义FLASH起始0x08000000(容量64KB)与RAM起始0x20000000(容量20KB),标准Cortex-M3链接脚本即可,此处不展开。
运行与验证
- 安装依赖:
sudo apt install gcc-arm-none-eabi stlink-tools make(Ubuntu/Debian) - 将上述
main.c、Makefile、链接脚本置于同一目录,执行make生成led_blink.bin - 连接ST-Link至板子SWD接口,执行
make flash烧录 - 复位板子,观察板载LED
通过标准:LED以约1Hz频率(亮0.5s/灭0.5s)持续闪烁。若LED常亮或常灭,检查PC13接线方向(低电平点亮)及BRR/BSRR寄存器操作是否正确;若完全不亮,用示波器或万用表测量PC13引脚电平是否在0V/3.3V间切换,确认烧录地址是否为0x08000000。
上图展示了GPIO初始化的完整数据流:先使能外设时钟,再配置引脚模式,最后在主循环中通过BSRR/BRR寄存器交替控制电平输出,形成周期翻转。
常见问题
- 编译报错找不到
stm32f1xx.h:确认已安装libstm32f1-dev包,或在Makefile的CFLAGS中添加-I/usr/include/stm32f1指定头文件路径 - 烧录后无反应:检查BOOT0跳线是否接地(正常运行时需为0);确认ST-Link与板子的SWDIO/SWCLK/GND三线连接正确
- LED常亮不闪烁:延时函数在-O2优化下可能被过度优化,将
delay_ms中的循环变量声明为volatile,或改用SysTick定时器实现精确延时