1. 环境搭建与LED控制
任务目标
本案例完成两项工作:一是搭建STM32的最小开发环境(编译器+烧录工具+工程框架),二是编写并烧录一个控制LED以1Hz频率闪烁的程序,以此熟悉STM32的GPIO输出操作。最终通过观察开发板上LED的实际闪烁状态来验证程序是否正确运行。
环境与依赖
- 硬件:STM32F103C8T6核心板(蓝丸)、ST-Link V2烧录器、LED(板载PC13或外接至PA0,需串联220Ω电阻)、面包板与杜邦线
- 软件:Windows/Linux/macOS均可;ARM GCC工具链(
arm-none-eabi-gcc)、OpenOCD或STM32CubeProgrammer、Make - 标准外设库:STM32F10x标准外设库(或直接使用寄存器操作,本案例采用寄存器方式以最小化依赖)
实现原理
STM32的GPIO操作核心是配置端口模式寄存器(CRL/CRH)和数据输出寄存器(ODR)。本案例使用寄存器直接操作,避免引入完整外设库,使代码最小化且逻辑清晰。LED接在PA0引脚,配置为推挽输出,通过延时函数实现电平翻转,形成闪烁效果。
关键完整代码
// main.c - STM32F103C8T6 LED闪烁 (PA0, 1Hz)
#include "stm32f10x.h"
void delay_ms(uint32_t ms) {
for (uint32_t i = 0; i < ms * 8000; i++) {
__NOP();
}
}
void GPIO_Init_LED(void) {
// 使能GPIOA时钟 (RCC_APB2ENR bit2)
RCC->APB2ENR |= (1 << 2);
// PA0配置为推挽输出,50MHz (CRL: MODE0=11, CNF0=00)
GPIOA->CRL &= ~(0xF << 0); // 清除PA0原有配置
GPIOA->CRL |= (0x3 << 0); // MODE0=11 (50MHz输出)
// CNF0保持00 = 推挽输出
// 初始状态:LED灭 (ODR bit0 = 0)
GPIOA->ODR &= ~(1 << 0);
}
int main(void) {
GPIO_Init_LED();
while (1) {
GPIOA->ODR ^= (1 << 0); // 翻转PA0电平
delay_ms(500); // 延时500ms,周期1s
}
}
编译与烧录
创建工程目录,包含上述main.c、启动文件startup_stm32f10x_md.s和链接脚本stm32f103c8t6.ld。编译命令如下:
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb main.c -o main.o
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb startup_stm32f10x_md.s -o startup.o
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -T stm32f103c8t6.ld main.o startup.o -o led.elf
arm-none-eabi-objcopy -O ihex led.elf led.hex
烧录(使用OpenOCD + ST-Link):
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "program led.hex verify reset exit"
验证方法
烧录成功后,观察PA0引脚连接的LED。通过条件:LED以约1Hz频率(每500ms翻转一次)持续闪烁。若LED不亮或常亮,检查接线(PA0是否与LED阳极相连、阴极是否接地)、编译是否报错、烧录是否成功。可用示波器或万用表测量PA0电压,正常应在0V和3.3V之间周期性切换。
常见问题
- 编译报错找不到头文件:确认
stm32f10x.h路径已加入-I参数,该头文件可从STM32标准外设库获取。 - LED不闪烁但程序已烧录:检查延时参数是否过大(系统时钟频率不同需调整
delay_ms循环次数),或确认PA0是否被其他外设复用。 - 烧录失败:确认ST-Link与板子的SWD接口连接正确(SWDIO、SWCLK、GND),且板子供电正常。