实验2:标准外设库GPIO控制流水灯实验
| 项目 | 内容 |
|---|---|
| 实验平台 | STM32F103C8T6最小系统核心板 |
| 开发环境 | Keil uVision5、STM32F10x标准外设库V3.5.0 |
| 实验日期 | 2026年9月29日 |
一、实验目的
- 掌握Keil MDK下基于STM32标准外设库的工程创建流程,学会手动添加库文件(.c/.h)与配置编译参数;
- 掌握标准外设库中GPIO初始化、电平输出相关库函数的使用方法,对比寄存器开发的差异;
- 学会使用Keil内置软件仿真逻辑分析仪,在无示波器条件下观测GPIO引脚时序波形;
- 分析软件循环延时的实际周期,理解软件延时的误差来源与调试方法。
二、实验硬件与功能要求
1. 硬件接线
所有LED均为低电平点亮,外接LED需串联200Ω~1kΩ限流电阻,接线对应关系:
| LED类型 | 连接GPIO引脚 | 引脚参数 |
|---|---|---|
| 核心板板载LED | PC13 | 推挽输出,最高2MHz速率 |
| 红色外接LED | PA4 | 推挽输出,最高10MHz速率 |
| 绿色外接LED | PB5 | 推挽输出,最高10MHz速率 |
| 蓝色外接LED | PC14 | 推挽输出,最高2MHz速率 |
2. 功能要求
四个LED按照板载PC13 → 红灯PA4 → 绿灯PB5 → 蓝灯PC14的顺序轮流点亮,任意时刻仅一个LED点亮,循环运行,通过软件循环实现延时。
三、标准外设库工程创建与库文件添加步骤
1. 工程目录规划
新建工程总文件夹LED_Water_SPL,在文件夹内创建以下子目录,分类存放工程文件:
User:存放用户main.c、中断处理文件、库配置文件CMSIS:存放Cortex-M3内核与芯片适配文件Startup:存放汇编启动文件FWlib/inc、FWlib/src:分别存放标准外设库头文件、源文件Output:存放编译输出的hex、obj文件Listing:存放编译列表文件
2. 复制标准库文件
从ST官方STM32F10x_StdPeriph_Lib_V3.5.0库中复制对应文件:
| 目标目录 | 复制文件 | 说明 |
|---|---|---|
| CMSIS | CoreSupport/core_cm3.c、core_cm3.h | Cortex-M3内核通用文件 |
| CMSIS | DeviceSupport/.../stm32f10x.h、system_stm32f10x.c/.h | 芯片寄存器定义、系统时钟配置 |
| Startup | startup/arm/startup_stm32f10x_md.s | STM32F103C8T6为64KB Flash,属于中等容量(md) |
| FWlib/inc | 标准外设库inc目录下所有头文件 | 外设函数声明 |
| FWlib/src | misc.c、stm32f10x_gpio.c、stm32f10x_rcc.c | 本实验仅需RCC、GPIO、NVIC相关源文件 |
| User | 模板目录下stm32f10x_conf.h、stm32f10x_it.c/.h | 库功能配置、中断处理模板 |
3. Keil新建工程
- 打开Keil uVision5,点击
Project → New μVision Project,保存到工程总目录,命名为LED_Water; - 在芯片选择窗口依次展开
STMicroelectronics → STM32F1 Series → STM32F103C8,点击OK; - 弹出运行时环境管理窗口直接点击Cancel,手动管理库文件。
4. 添加工程分组与源文件
- 点击工具栏工程管理图标,删除默认分组,新建
STARTUP、CMSIS、FWlib、USER四个分组; - STARTUP分组添加
startup_stm32f10x_md.s(文件类型选择All files); - CMSIS分组添加
core_cm3.c、system_stm32f10x.c; - FWlib分组添加
misc.c、stm32f10x_gpio.c、stm32f10x_rcc.c; - USER分组添加
stm32f10x_it.c与后续编写的main.c。
5. 编译参数配置
点击魔术棒图标打开工程配置:
- Target页:外部晶振频率填写8.0MHz;
- Output页:输出目录选择
Output文件夹,勾选Create HEX File生成烧录文件; - Listing页:列表输出目录选择
Listing文件夹; - C/C++页:
- 预处理宏定义填写:
STM32F10X_MD,USE_STDPERIPH_DRIVER; - 头文件包含路径添加:
CMSIS、FWlib/inc、User; - 优化等级默认设置为Level 0(-O0),避免空循环被优化;
- 预处理宏定义填写:
- Debug页:选中
Use Simulator使用软件仿真,硬件烧录时再切换ST-Link。
配置完成后编译工程,0错误0警告即工程搭建完成。启动文件进入main前会自动调用SystemInit(),默认将系统时钟配置为72MHz(8MHz HSE × 9倍PLL)。
四、实验原理与库函数说明
标准外设库将寄存器操作封装为函数与结构体,开发时不需要直接记忆寄存器地址,核心库函数:
RCC_APB2PeriphClockCmd():使能GPIO外设时钟,等价于直接配置RCC_APB2ENR寄存器;GPIO_InitTypeDef:GPIO配置结构体,包含引脚号、工作模式、翻转速率三个参数;GPIO_Init():根据结构体参数自动配置GPIOx_CRL/CRH寄存器,完成引脚初始化;GPIO_SetBits():将指定引脚置高电平(对应BSRR寄存器置位,本实验中熄灭LED);GPIO_ResetBits():将指定引脚置低电平(对应BSRR寄存器复位,本实验中点亮LED)。
软件延时通过双层空循环消耗CPU时钟周期实现,延时长度由系统时钟频率、编译优化等级、循环指令周期共同决定,没有精确固定值,需要通过仿真实际测量。
五、实验程序代码
/******************************************************************** * 文件名:main.c * 功能:STM32F103C8T6 标准外设库版四灯流水灯 * 板载 LED:PC13,低电平点亮 * 外接 LED:Red -> PA4,Green -> PB5,Blue -> PC14 * 顺序:PC13 -> PA4 -> PB5 -> PC14,循环点亮 ********************************************************************/#include"stm32f10x.h"/* 软件循环延时,单位约ms,加volatile防止空循环被编译器优化 */voidDelay_ms(unsignedintms){unsignedinti;volatileunsignedintj;for(i=0;i<ms;i++)for(j=0;j<8000;j++);}/* LED GPIO 初始化 */voidLED_Init(void){GPIO_InitTypeDef GPIO_InitStructure;/* 1. 使能 GPIOA、GPIOB、GPIOC 时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);/* 2. 配置 PA4:推挽输出,10MHz */GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);/* 3. 配置 PB5:推挽输出,10MHz */GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;GPIO_Init(GPIOB,&GPIO_InitStructure);/* 4. 配置 PC13、PC14:推挽输出,2MHz */GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;GPIO_Init(GPIOC,&GPIO_InitStructure);/* 5. 上电全灭:低电平点亮,输出高电平熄灭 */GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOB,GPIO_Pin_5);GPIO_SetBits(GPIOC,GPIO_Pin_13|GPIO_Pin_14);}/* 主函数 */intmain(void){LED_Init();while(1){/* PC13 板载 LED 点亮后熄灭 */GPIO_ResetBits(GPIOC,GPIO_Pin_13);Delay_ms(1000);GPIO_SetBits(GPIOC,GPIO_Pin_13);/* PA4 红灯点亮后熄灭 */GPIO_ResetBits(GPIOA,GPIO_Pin_4);Delay_ms(1000);GPIO_SetBits(GPIOA,GPIO_Pin_4);/* PB5 绿灯点亮后熄灭 */GPIO_ResetBits(GPIOB,GPIO_Pin_5);Delay_ms(1000);GPIO_SetBits(GPIOB,GPIO_Pin_5);/* PC14 蓝灯点亮后熄灭 */GPIO_ResetBits(GPIOC,GPIO_Pin_14);Delay_ms(1000);GPIO_SetBits(GPIOC,GPIO_Pin_14);}}六、软件仿真与时序分析
1. 逻辑分析仪操作步骤
- 编译工程后按
Ctrl+F5进入软件仿真; - 点击
View → Analysis Windows → Logic Analyzer打开逻辑分析仪; - 点击Setup,通过信号浏览器添加对应引脚的ODR信号,设置显示类型为Bit;
- 设置时间网格为0.5s,全速运行数秒后停止观测波形。
2. 实测波形
3. 波形与周期分析
时序正确性验证:
波形显示三个外接引脚按照红灯→绿灯→蓝灯的顺序依次拉低,板载LED在每轮初始阶段拉低;任意时刻最多一个引脚为低电平,无重叠、无毛刺,电平切换顺序与程序设计完全一致,流水灯逻辑正确。实际周期测量(网格刻度0.5s/格):
测量项 实测值 单个LED低电平(点亮)持续时间 约0.5s 相邻两个LED点亮的切换间隔 约0.5s 单个LED完整闪烁周期(本次亮到下一次亮) 约2s 高电平(熄灭)持续时间 约1.5s 误差原因分析:
代码中预期延时1秒,实测约0.5秒,原因是标准库将系统时钟从实验1的8MHz倍频到72MHz,同样循环次数的执行时间随频率升高缩短;同时C语言循环编译后存在固定指令开销,软件延时本身不具备精确性,属于正常现象,可通过增大内层循环参数将延时调整至1秒。
七、硬件实际运行演示
将编译生成的hex文件烧录到核心板后,流水灯实际运行效果如下:
实际硬件运行时LED点亮顺序、切换速度与仿真波形完全一致,板载LED与三个外接LED均正常工作,验证了程序与工程配置的正确性。
八、实验总结
- 掌握了STM32标准外设库工程从零搭建的完整流程,理解了头文件路径、预处理宏、启动文件的作用;
- 对比寄存器开发方式,标准外设库通过结构体与封装函数降低了开发门槛,代码可读性与可移植性更好,不需要记忆大量寄存器地址;
- 掌握了Keil软件仿真逻辑分析仪的使用方法,可以在无硬件示波器的条件下快速定位引脚时序问题、测量实际延时;
- 理解了软件循环延时的局限性:其精度受系统时钟、编译优化、中断影响很大,实际产品开发中需要使用SysTick或硬件定时器实现精确延时。
注意事项
- PC13/PC14/PC15为特殊引脚,作为GPIO时最高仅支持2MHz翻转速率,驱动能力有限;
- 外接LED必须串联限流电阻,避免烧坏GPIO引脚或LED;
- 若核心板焊接了32.768kHz低速晶振,PC14无法作为普通GPIO使用,需要更换到其他空闲引脚。