一、GPIO端口
STM32芯片根据芯片不通具有多组GPIO端口,分别为:A、B、C、D、E、F、G,每一组有16个GPIO端口(编号为0~15); 使用“GPIOx(x:组别名称).端口编号”或者使用“Px(x:组别名称).端口编号”格式来表示具体使用的GPIO端口,每个GPIO端口都具有多功能模式,GPIO端口默认功能为输入功能; |
例:使用GPIO A组编号15的端口,则使用PA.15(PA15)或GPIOA.15来表示; |
二、GPIO功能
GPIO端口电平状态不确定,完全由外部输入决定,一般用于处理信号; | |
上拉输入 | 在没有外接输入的情况下,能够让GPIO端口有一个确定的高电平信号,用于对输入电平信号进行检测(用于检测外部低电平); |
下拉输入 | 在没有外接输入的情况下,能够让GPIO端口有一个确定的低电平信号,用于对输入电平信号进行检测(用于检测外部高电平); |
模拟功能 | 芯片内部ADC或DAC模块专用功能(analog-digital); |
具有上拉或下拉功能的开漏输出 | 开漏输出也称为断开输出,可以正常输出低电平(0),没有输出高电平(1)的能力; 如果需要输出高电平(1),则需要配置成上拉功能的开漏输出(芯片内部上拉属于弱上拉,驱动能力很小,如果需要获得较强的驱动能力,需要在芯片外部外接上拉电阻); |
具有上拉或下拉功能的推挽输出 | 推挽输出可以输出高电平(1),也可以输出低电平(0); |
具有上拉或下拉功能的复用功能推挽 | 复用功能是指GPIO端口的第二功能(除了默认功能以外的功能),也就是对片内外设进行通信时功能管脚的专用功能,复用功能推挽是指当GPIO端口作为第二功能时配置为推挽输出模式; |
具有上拉或下拉功能的复用功能开漏 | 复用功能推挽是指当GPIO端口作为第二功能时配置为开漏输出模式; |
![]() |
三、GPIO复用
1、外设功能管脚复用概念
STM32芯片所有的片内外设模块的功能引脚(除了GPIO端口以外)都是使用GPIO端口的复用功能,并且每个GPIO端口都会对应有多个复用模块的功能。 |
![]() |
2、外设功能管脚复用
![]() |
注:每个GPIO端口可用复用功能在出厂时已经固定,选择端口复用功能必须满足管脚是否可以实现为前提。 |
四、GPIO操作
1、使用PIN驱动程序
2、GPIO输出
rt_pin_mode() 设置引脚模式 rt_pin_write() 设置引脚电平 |
#include <rtthread.h> #include <rtdevice.h> #include <drv_common.h> #define pinTest GET_PIN(F, 9) rt_pin_mode(pinTest, PIN_MODE_OUTPUT); rt_pin_write(pinTest, PIN_LOW); |
3、GPIO输入
rt_pin_mode() 设置引脚模式 rt_pin_read() 读取引脚电平 输入模式: #define PIN_MODE_INPUT 0x01 #define PIN_MODE_INPUT_PULLUP 0x02 #define PIN_MODE_INPUT_PULLDOWN 0x03 |
#include <rtthread.h> #include <rtdevice.h> #include <drv_common.h> #define pinTest GET_PIN(F, 9) rt_pin_mode(pinTest, PIN_MODE_INPUT_PULLUP); rt_base_t pinInstance = pinTest; uint8_t status = rt_pin_read(pinInstance); |
4、GPIO外部中断
外部中断(EXTI)是指直接能作用于GPIO端口,直接引用芯片外部的信号作为中断源。 |
外部中断框图: |
rt_pin_attach_irq() 绑定引脚中断回调函数 rt_pin_irq_enable() 使能引脚中断 rt_pin_detach_irq() 脱离引脚中断回调函数 触发边沿: #define PIN_IRQ_MODE_RISING 0x00 #define PIN_IRQ_MODE_FALLING 0x01 #define PIN_IRQ_MODE_RISING_FALLING 0x02 |
#include <rtthread.h> #include <rtdevice.h> #include <drv_common.h> void gpioCallback(void *args) { rt_kprintf("gpioCallback!\n"); } #define pinTest GET_PIN(E, 4) rt_pin_mode(pinTest, PIN_MODE_INPUT_PULLUP); rt_pin_attach_irq(pinTest, PIN_IRQ_MODE_FALLING, gpioCallback, RT_NULL); rt_pin_irq_enable(pinTest, PIN_IRQ_ENABLE); |
注意:先绑定回调函数再使能中断,引脚脱离了中断回调函数以后,中断并没有关闭,还可以调用绑定中断回调函数再次绑定其他回调函数。 |
电平检测示例(中断+定时器回调[延时消抖]): |
typedef enum { XXX_STATUS_RELEASE = 0, // 释放 XXX_STATUS_PRESS // 按下 } xxxStatus_e; typedef void (*m_xxxCallbackPtr)(uint8_t status); m_xxxCallbackPtr m_xxxCallback = NULL; static rt_base_t xxxPin; static rt_timer_t xxxTimer; static void xxxEdge(void *args) { rt_timer_start(xxxTimer); } static void xxxTimeout(void *parameter) { if (rt_pin_read(xxxPin) == PIN_HIGH) { if(m_xxxCallback != NULL) m_xxxCallback(XXX_STATUS_PRESS); } else { if(m_xxxCallback != NULL) m_xxxCallback(XXX_STATUS_RELEASE); } } bool xxxInit(rt_base_t pin, uint16_t delayms, void (*callback)(uint8_t status)) { xxxPin = pin; m_xxxCallback = callback; rt_pin_mode(pin, PIN_MODE_INPUT_PULLDOWN); rt_pin_attach_irq(pin, PIN_IRQ_MODE_RISING_FALLING, xxxEdge, RT_NULL); rt_pin_irq_enable(pin, PIN_IRQ_ENABLE); // 创建消抖定时器 xxxTimer = rt_timer_create("xxxTimer", xxxTimeout, RT_NULL, delayms, RT_TIMER_FLAG_ONE_SHOT); if (xxxTimer == RT_NULL) { rt_kprintf("xxxTimer creation failed!\n"); return false; } return true; } |