一、LED闪烁实验

实验简介
LED闪烁实验是嵌入式开发的"Hello World",通过这个实验可以掌握STM32的GPIO配置、时钟控制和基本的编程逻辑。本实验将详细介绍两种常见的LED驱动方式及其应用场景。
驱动方式
1. 共阴极接法
电路原理:
-
LED阴极连接到GND,阳极通过限流电阻连接到STM32的GPIO引脚
-
当GPIO输出高电平时,LED点亮;输出低电平时,LED熄灭
特点:
-
逻辑直观:高电平点亮,低电平熄灭
-
驱动能力依赖STM32的IO口输出电流(通常8-20mA)
-
电路简单,成本低
适用场景:
-
单个LED控制
-
对驱动电流要求不高的应用
-
初学者学习实验
2. 共阳极接法
电路原理:
-
LED阳极连接到VCC(3.3V),阴极通过限流电阻连接到STM32的GPIO引脚
-
当GPIO输出低电平时,LED点亮;输出高电平时,LED熄灭
特点:
-
逻辑反向:低电平点亮,高电平熄灭
-
当IO口驱动能力不足时可选用此接法
-
可利用三极管增强驱动能力
适用场景:
-
需要驱动多个LED或高亮度LED
-
IO口驱动能力不足的情况
-
需要电平转换的场合
GPIO输出模式详解
通用推挽输出模式

工作原理:
推挽输出采用两个MOS管(P-MOS和N-MOS)组成推挽结构,能够主动输出高电平(3.3V)和低电平(0V),具有较强的驱动能力。
适用场景:
-
✅ LED控制
-
✅ 驱动小功率器件
-
✅ 数字信号输出
-
✅ 需要较强驱动能力的场合
电路分析:
-
输出高电平:P-MOS导通,N-MOS截止,输出3.3V
-
输出低电平:P-MOS截止,N-MOS导通,输出0V
-
输出电流:通常可达20mA(具体参考芯片数据手册)
编程接口:
C
// 推挽输出配置
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
代码案例:
C
//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管,只能主动输出低电平,高电平需要外部上拉电阻实现。支持"线与"连接,可用于电平转换和总线通信。
适用场景:
-
✅ I2C、SMBus等总线通信
-
✅ 电平转换(3.3V↔5V)
-
✅ 多设备"线与"连接
-
✅ 需要防止电流倒灌的场合
电路分析:
-
输出低电平:N-MOS导通,输出0V
-
输出高电平:N-MOS截止,依靠外部上拉电阻输出高电平
-
输出电流:灌电流能力强,拉电流依赖外部上拉
编程接口:
C
// 开漏输出配置
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
代码案例:
C
//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,当按键未按下时,引脚被拉至高电平;当按键按下时,引脚被拉至低电平。
适用场景:
-
✅ 按键检测
-
✅ 开关状态读取
-
✅ 数字信号输入检测
-
✅ 需要默认高电平的输入场合
电路分析:
-
按键未按下:内部上拉电阻使引脚保持高电平
-
按键按下:引脚通过按键连接到GND,变为低电平
-
消除抖动:需要通过软件或硬件消除机械按键的抖动
编程接口:
C
// 上拉输入配置
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
代码案例:
C
#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);
}
}
}
三、硬件接线指南
基础接线方案

共阴极接法:
C
STM32 GPIO Pin → 220Ω电阻 → LED阳极 → LED阴极 → GND

共阳极接法:
C
3.3V → 220Ω电阻 → LED阳极 → LED阴极 → STM32 GPIO Pin
实验中采用此接法的LED为板载LED,所以就不附上接线图了
按键接线:
C
STM32 GPIO Pin → 按键引脚1 → 按键引脚2 → GND
(配合内部上拉电阻)

元件参数选择:
-
限流电阻:通常220Ω-1kΩ(根据LED额定电流计算)
-
LED类型:普通发光二极管(压降1.8-2.2V,电流5-20mA)
-
按键类型:轻触开关、微动开关
-
连接方式:面包板或PCB焊接
增强驱动方案
当需要驱动大功率LED或多个LED时:
C
// 使用三极管增强驱动(NPN晶体管)
// STM32 GPIO → 1kΩ电阻 → NPN基极
// NPN集电极 → LED → 限流电阻 → VCC
// NPN发射极 → GND
四、调试技巧与常见问题
调试步骤
1. 硬件检查:
-
确认电源电压正常(3.3V)
-
检查LED极性是否正确
-
测量限流电阻值
2. 软件调试:
-
确认GPIO时钟已开启
-
检查GPIO配置模式
-
验证延时函数准确性
-
检查中断配置
3. 信号测量:
-
使用万用表测量GPIO输出电压
-
用示波器观察波形
-
使用逻辑分析仪捕获信号
常见问题及解决方案
问题现象 | 可能原因 | 解决方法 |
---|---|---|
LED不亮 | 接线错误 | 检查LED极性,确认共阴/共阳接法 |
LED常亮 | GPIO配置错误 | 检查GPIO模式设置,确认推挽输出 |
LED亮度异常 | 限流电阻不合适 | 根据LED规格调整电阻值 |
闪烁频率不对 | 延时函数不准确 | 使用SysTick实现精确延时 |
按键无响应 | 上拉电阻未启用 | 检查GPIO输入模式配置 |
按键抖动 | 未进行消抖处理 | 添加软件消抖或硬件RC滤波 |
系统不工作 | 时钟未配置 | 检查系统时钟初始化 |
性能优化建议
1. 降低功耗:
C
// 在延时期间进入低功耗模式
void Enter_LowPower_During_Delay(void)
{
// 配置进入睡眠模式
__WFI(); // 等待中断
}
2. 提高响应速度:
C
// 使用中断代替延时查询
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)));
}
}