一、GPIO是什么?
你可以把GPIO理解成单片机的“手指”:想控制外面的设备(比如点亮LED、让蜂鸣器响)就通过它输出信号,想知道外面的状态(比如有没有按按键、传感器有没有触发)就通过它读取信号,是嵌入式开发最基础也最常用的功能。
我们使用的STM32F103C8T6芯片共有4组16个GPIO引脚(PA0~PA15、PB0~PB15等),每个引脚的电平只有两种状态:
高电平(1):3.3V
低电平(0):0V
二、GPIO的8种工作模式
1. 输入模式(4种):用来读取外部信号
浮空输入:引脚没有默认电平,完全由外部信号决定,适合外部已经有稳定电平的场景(比如串口接收引脚)。
上拉输入:引脚默认是高电平,外部给低电平时会被拉低,最适合接按键(按键一端接引脚,一端接地,没按的时候是高电平,按下去是低电平)。
下拉输入:引脚默认是低电平,外部给高电平时会被拉高,适合外部默认输出高电平的场景。
模拟输入:专门用来读取连续变化的电压(比如0~3.3V之间的任意值),只能用于ADC模数转换,比如接光敏电阻、温度传感器。
2. 输出模式(4种):用来控制外部设备
推挽输出:可以主动输出稳定的高电平和低电平,驱动能力强,点LED、控制蜂鸣器就用这个。
开漏输出:只能主动输出低电平,输出高电平需要外接上拉电阻,适合I2C通信、电平转换等场景。
复用推挽输出:引脚的控制权交给芯片内部的外设(比如串口、SPI),由外设自动控制输出,适合高速通信接口。
复用开漏输出:和复用推挽类似,只是输出结构是开漏的,适合I2C的外设引脚。
三.实例
点亮LED
#include "stm32f10x.h" // 包含STM32标准库头文件
// LED初始化函数
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 第一步:开启GPIOA的时钟(所有GPIO都挂在APB2总线上,必须先开时钟才能用!)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 第二步:配置引脚参数
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 选择PA0引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 配置为推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度设置为50MHz
// 第三步:调用初始化函数,把配置写入寄存器
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
int main(void)
{
LED_Init(); // 先初始化LED引脚
while(1)
{
// PA0输出高电平,LED亮
GPIO_SetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500); // 延时500ms
// PA0输出低电平,LED灭
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
}
}
按键控制LED
把按键的一端接PB1引脚,另一端接GND,PB1配置为上拉输入:没按按键的时候,引脚被内部上拉电阻拉成高电平;按下按键的时候,引脚被拉到地,变成低电平。
// 按键初始化函数
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// PB1配置为上拉输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
// 按键读取函数(带消抖)
uint8_t Key_Read(void)
{
// 第一次检测到引脚为低电平(可能是按键按下,也可能是干扰)
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20); // 等待20ms,跳过按键抖动的干扰
// 再次确认还是低电平,说明确实是按键按下了
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
// 等待按键松开,防止按一次触发多次
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
return 1; // 返回1表示按键按下
}
}
return 0; // 没按下返回0
}
int main(void)
{
LED_Init();
KEY_Init();
while(1)
{
if(Key_Read() == 1) // 如果检测到按键按下
{
// 翻转LED的状态:原来是亮就灭,原来是灭就亮
if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) == 1)
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
else
GPIO_SetBits(GPIOA, GPIO_Pin_0);
}
}
}

1297

被折叠的 条评论
为什么被折叠?



