目录

  • GPIO模式
  • 模拟
  • 浮空输入
  • 下拉输入
  • 上拉输入
  • 推挽
  • 开漏
  • 例程
  • 点亮LED
  • 按钮检测



GPIO全称为通用输入输出接口(General Purpose Input Output),是单片机中必不可少的外设,它控制这单片机的IO管脚,无论使用什么通信协议,如SPI、I2C都需要对GPIO进行初始化。

GPIO模式

GD32的GPIO模式一共有6种,下面结合原理图详细解释。

GPIO0 esp_单片机

模拟

下面是模拟模式的框图。

GPIO0 esp_GPIO0 esp_02


在模拟模式,单片机需要接收或发送模拟信号,因此电路中不需要任何去噪的电路,因此可以简单理解为就一条直线连接到单片机对应管脚。

这时,弱上拉和下拉电阻禁用;输出缓冲器禁用;施密特触发输入禁用;端口输入状态寄存器相应位为“0”

浮空输入

下面是GD32输入结构的框图,浮空输入、下拉输入、上拉输入都是同样的框图。

GPIO0 esp_GPIO0 esp_03


当单片机管脚处于浮空输入,输入电路中的上拉和下拉电阻被禁用,施密特触发器使能,可以理解为管脚上为高或低电平,单片机就接收到高或低电平。

下拉输入

当单片机处于下拉输入,输入电路中的下拉电阻使能,施密特触发器使能。当管脚接上了线时,它的作用是和浮空输入一样的;但当管脚悬空时,管脚电平会被下拉至低电平,此时单片机只能接收到低电平。

上拉输入

当单片机处于上拉输入,输入电路中的上拉电阻使能,施密特触发器使能。现象和下拉输入是相反的,就是当管脚悬空时,管脚电平会被上拉至高电平,此时单片机只能接收到高电平。

推挽

下面是GD32输出结构的框图,推挽和开漏都是同样的框图。

GPIO0 esp_GPIO0 esp_04


当GPIO配置为输出模式时,统一禁用上拉和下拉电阻,使能施密特触发器,使能输出缓冲区

当处于推挽模式时,输出控制寄存器设置为“0”时,相应引脚输出低电平;输出控制寄存器设置为“1”,相应引脚输出高电平

开漏

当处于开漏模式时,输出控制寄存器设置为“0”时,相应引脚输出低电平;输出控制寄存器设置为“1”,相应管脚处于高阻状态

大家可能注意到,单片机的几乎每个模式都离不开施密特触发器这个东西,所以在这里简单解释一下,施密特触发器的作用。
施密特触发器在GPIO中的作用主要是波形变换和整波,因为有电磁干扰或电路中有噪声的时候,那么经过GPIO管脚的电压就可能会不稳定,即上下起伏的;经过施密特触发器后,起伏的信号会被规整为矩形波,便于单片机识别高低电平信号。

例程

点亮LED

具体的现象为开发板上对应的LED闪烁。

#include "gd32f10x.h"
#include "main.h"

void delay(__IO uint32_t ms)  // 随便写一个软件延时函数,不准确的,在例程中能用就行
{
    for(uint32_t i = 0; i < ms; ++i)
    {
        for(uint32_t j = 0; j < 10000; ++j)
        {
        }
    }
}

int main(void)
{	
    rcu_periph_clock_enable(RCU_GPIOC);  // 初始化GPIO口的时钟
    // 初始化GPIO引脚,使能PC13引脚,速度为50MHz,模式为推挽输出
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
    
    while(1)
    {
        gpio_bit_write(GPIOC, GPIO_PIN_13, SET);  // PC13引脚高电平
        delay(1000);
        gpio_bit_write(GPIOC, GPIO_PIN_13, RESET);  // PC13引脚低电平
        delay(1000);
    }
}

说明:
对GPIO管脚写“1”不一定就是亮灯,有可能是灭灯,写“0”反之;这个是根据单片机的设计时的原理图决定的。
GD32为GPIO管脚提供了3种时钟速率——50MHz、10MHz、2MHz,一般来说没有特殊要求一般选择最高速率;有一些情况下,如使用SPI与ESP32进行通信时,速率就不能选最高,因为ESP32在SPI模式下的GPIO管脚承受不住50MHz的速度,这个我们后面遇到再详细说。

按钮检测

现象为,当我们按下开关时,LED灯亮;当我们松开开关时,LED灯灭。

#include "gd32f10x.h"
#include "main.h"

int main(void)
{	
    rcu_periph_clock_enable(RCU_GPIOC);  // 初始化GPIO口的时钟
    // 初始化GPIO引脚,使能PC13引脚,速度为50MHz,模式为推挽输出
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
    
    rcu_periph_clock_enable(RCU_GPIOA);  // 初始化GPIO口的时钟
    // 初始化GPIO引脚,使能PA0引脚,速度为50MHz,模式为浮空输入
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
    
    while(1)
    {
        if(gpio_input_bit_get(GPIOA, GPIO_PIN_0) == SET)  // 获取对应管脚的电平值
        {
            gpio_bit_write(GPIOC, GPIO_PIN_13, SET);  // 亮灯
        }
        else
        {
            gpio_bit_write(GPIOC, GPIO_PIN_13, RESET);  // 灭灯
        }
    }
}

说明:
在设计按钮检测代码时需查看开发板的原理图里面按钮模块的设计,一般按钮在按下时会产生抖动,所以在设计开发板时会用RC电路进行包裹,实现硬件消抖;但如果在开发板设计之初没有考虑这个问题,那么就需要在代码中添加消抖代码,实现软件消抖。