第3章:GPIO基础——从模式到实战,点亮你的第一颗LED
各位同学,欢迎来到第三章。前面我们聊了STM32的整体架构和开发环境搭建,今天终于要动手了。这一章我们聚焦GPIO——说白了,就是芯片上那些可以编程控制的引脚。你想想看,一个单片机要跟外界打交道,靠的就是这些引脚。GPIO是基础中的基础,但也是坑最多的地方之一。
3.1 GPIO模式详解:别小看这几种配置
STM32的GPIO模式,比你想的要复杂。我刚开始用的时候,以为就是简单的输入输出。结果第一次做项目,就因为模式选错,折腾了一整天。嗯,这里我给大家梳理一下。
3.1.1 输出模式
- 推挽输出(Push-Pull):最常用的输出模式。可以输出高电平或低电平,驱动能力较强。我个人习惯,驱动LED、蜂鸣器这类外设,首选推挽。
- 开漏输出(Open-Drain):只能输出低电平,高电平要靠外部上拉电阻。I2C总线就是典型应用。我在项目中遇到过,如果忘了加上拉电阻,总线死活拉不高。
3.1.2 输入模式
- 浮空输入:引脚电平完全由外部决定,内部没有上下拉。这种模式容易受干扰,我一般不用。
- 上拉/下拉输入:内部有弱上拉或弱下拉电阻。读取按键时,我习惯用上拉输入,按键按下就是低电平,逻辑清晰。
3.1.3 复用功能与模拟模式
复用功能,就是把引脚交给片上外设(比如USART、SPI)去控制。模拟模式则用于ADC采集。这两种模式,说白了就是GPIO模块退居二线,让专业的人干专业的事。
核心要点:配置GPIO时,先想清楚你要干什么。输出?输入?还是交给外设?选错了,轻则功能异常,重则烧坏引脚。
3.2 核心API:HAL_GPIO_WritePin与HAL_GPIO_ReadPin
HAL库封装好了两个最常用的函数。我刚开始学的时候,觉得这俩函数太简单了,后来才发现,用得好不好,直接关系到代码的健壮性。
3.2.1 HAL_GPIO_WritePin
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
参数说明:
GPIOx:GPIO组,比如GPIOA、GPIOBGPIO_Pin:引脚编号,比如GPIO_PIN_0PinState:电平状态,GPIO_PIN_SET(高)或GPIO_PIN_RESET(低)
举个例子,点亮LED就是:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // PB0输出高电平
我的小技巧:不要直接用数字0或1来赋值,一定要用GPIO_PIN_SET和GPIO_PIN_RESET。这样代码可读性高,别人一看就懂。
3.2.2 HAL_GPIO_ReadPin
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
这个函数返回引脚当前的电平状态。读取按键时常用:
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
// 按键被按下(假设是上拉输入)
}
我曾经踩过的坑:读取引脚前,一定要确认GPIO模式配置正确。有一次我配置成了输出模式,然后去读引脚电平,结果读回来的值完全不对。折腾了半天才发现是模式搞错了。
3.3 点亮LED实战:从原理到代码
好了,理论知识讲完了,我们来动手。点亮LED,是嵌入式开发的"Hello World"。我当年第一次点亮LED时,那种成就感至今难忘。
3.3.1 硬件连接
假设我们使用STM32F103C8T6最小系统板,LED正极通过一个220Ω电阻连接到PB0,负极接地。为什么加电阻?限流,防止烧坏LED和引脚。
3.3.2 代码实现
第一步,配置GPIO。在STM32CubeMX中,将PB0设置为推挽输出模式,速度选Low(低速就够用)。然后生成代码。
第二步,在主循环中控制LED:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init(); // 初始化GPIO
while (1)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 点亮
HAL_Delay(500); // 延时500ms
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 熄灭
HAL_Delay(500); // 延时500ms
}
}
就这么简单。下载到板子上,你应该能看到LED以1秒的周期闪烁。
注意:HAL_Delay依赖于SysTick中断。如果你的代码中关闭了全局中断,延时就会失效。我在一个项目中就因为这个原因,LED死活不闪,排查了好久才发现是中断被关了。
3.4 知识体系总览
下面这张图,是我自己画的GPIO知识体系。你把它记在脑子里,以后用GPIO就不会乱了。
3.5 避坑指南与个人经验
最后,分享几个我这些年积累的经验:
- 配置完GPIO后,先测量引脚电平。用万用表测一下,确认输出对不对。我曾经因为焊接问题,引脚虚焊,程序怎么调都没用。
- 注意引脚耐压。STM32的GPIO耐压一般是3.3V,别直接接5V。我在一个项目中,客户要求接5V传感器,结果忘了加电平转换,烧了两个引脚。
- 调试时多用HAL_GPIO_TogglePin。这个函数可以翻转引脚电平,用来做调试指示非常方便。比如在某个关键代码段前后翻转一个引脚,用示波器一看就知道执行时间。
- 不要迷信默认配置。每次新建工程,我都会手动检查一遍GPIO配置。CubeMX生成的代码有时候会遗漏某些设置,尤其是复用功能。
我的习惯:每个GPIO引脚,我都会在代码注释里写明用途。比如 // PB0 - LED指示灯,低电平点亮。这样过几个月回头看代码,不用重新翻原理图。
好了,这一章就到这里。GPIO看似简单,但它是所有外设驱动的基础。你把它吃透了,后面学USART、I2C、SPI都会轻松很多。动手试试吧,把LED点亮的那一刻,你会爱上这种感觉的。