1. 环境搭建与LED控制

环境搭建与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),且板子供电正常。