GPIO的输入与输出

一、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);
        }
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值