
LED闪烁实验是嵌入式开发的"Hello World",通过这个实验可以掌握STM32的GPIO配置、时钟控制和基本的编程逻辑。本实验将详细介绍两种常见的LED驱动方式及其应用场景。

推挽输出采用两个MOS管(P-MOS和N-MOS)组成推挽结构,能够主动输出高电平(3.3V)和低电平(0V),具有较强的驱动能力。
// 推挽输出配置
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 引脚号
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度
GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIO//001 采用推挽模式输出
//使用 GPIOx 前需要先开启时钟 --- 给他提供脉搏 时钟 -> 心跳
#include "stm32f10x.h"
#include "delay.h"
int main(void)
{
// 开启 GPIOC 的时钟 --- 激活心跳
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
// GPIO 模块编程接口配置
//IO 引脚的初始化 --- 选择八种工作模式中的一种,还有输出速度
//GPIO_InitTypeDef Tepy = {GPIO_Pin_13, GPIO_Mode_Out_OD, GPIO_Speed_2MHz}; ARMCC 不支持这种写法;
GPIO_InitTypeDef Tepy = {0};
Tepy.GPIO_Pin = GPIO_Pin_13;
Tepy.GPIO_Mode = GPIO_Mode_Out_OD;
Tepy.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &Tepy); // 初始化GPIOC
while(1)
{
// 使用通用开漏模式输出 ---- 2MHz的输出速度
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // 向寄存器写 0
Delay(250);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET); // 向寄存器写 1
Delay(250);
}
}
开漏输出只有N-MOS管,只能主动输出低电平,高电平需要外部上拉电阻实现。支持"线与"连接,可用于电平转换和总线通信。
// 开漏输出配置
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; // 引脚号
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度
GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIO//002 采用开漏模式输出
#include "stm32f10x.h"
void LED_OpenDrain_Init(void)
{
// 开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA1为开漏输出(需要外部上拉电阻)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void LED_OpenDrain_Blink(void)
{
while(1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); // LED点亮(输出低电平)
Delay_ms(250);
GPIO_SetBits(GPIOA, GPIO_Pin_1); // LED熄灭(输出高阻,靠上拉)
Delay_ms(250);
}
}按键检测是嵌入式系统中最基本的人机交互功能,通过读取GPIO输入状态来感知用户操作。本实验将深入讲解STM32的按键检测原理、实现方法和优化技巧。

上拉输入模式在芯片内部连接了一个上拉电阻到VCC,当按键未按下时,引脚被拉至高电平;当按键按下时,引脚被拉至低电平。
// 上拉输入配置
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 引脚号
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式
GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIO#include "stm32f10x.h"
// 按键初始化
void KEY_Init(void)
{
// 开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA0为上拉输入(按键引脚)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void LED_Init(void)
{
// 开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA1为开漏输出(需要外部上拉电阻)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 主函数:按键控制LED
int main(void)
{
// 初始化LED和按键
LED_Init();
KEY_Init();
while(1)
{
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == Bit_RESET)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
}
else
{
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
}
}
}
STM32 GPIO Pin → 220Ω电阻 → LED阳极 → LED阴极 → GND
3.3V → 220Ω电阻 → LED阳极 → LED阴极 → STM32 GPIO Pin实验中采用此接法的LED为板载LED,所以就不附上接线图了
STM32 GPIO Pin → 按键引脚1 → 按键引脚2 → GND
(配合内部上拉电阻)
// 使用三极管增强驱动(NPN晶体管)
// STM32 GPIO → 1kΩ电阻 → NPN基极
// NPN集电极 → LED → 限流电阻 → VCC
// NPN发射极 → GND问题现象 | 可能原因 | 解决方法 |
|---|---|---|
LED不亮 | 接线错误 | 检查LED极性,确认共阴/共阳接法 |
LED常亮 | GPIO配置错误 | 检查GPIO模式设置,确认推挽输出 |
LED亮度异常 | 限流电阻不合适 | 根据LED规格调整电阻值 |
闪烁频率不对 | 延时函数不准确 | 使用SysTick实现精确延时 |
按键无响应 | 上拉电阻未启用 | 检查GPIO输入模式配置 |
按键抖动 | 未进行消抖处理 | 添加软件消抖或硬件RC滤波 |
系统不工作 | 时钟未配置 | 检查系统时钟初始化 |
// 在延时期间进入低功耗模式
void Enter_LowPower_During_Delay(void)
{
// 配置进入睡眠模式
__WFI(); // 等待中断
}// 使用中断代替延时查询
void SysTick_Handler(void)
{
static uint32_t counter = 0;
if(++counter >= 500) // 500ms
{
counter = 0;
GPIO_WriteBit(GPIOA, GPIO_Pin_0,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0)));
}
}