学习目标
- 了解mos管的使用
- 了解GPIO输出模式
- 了解GPIO输入模式
- 理解ARM系列GPIO相关理论
- 掌握GD32几种GPIO工作模式编码实现
学习内容
基础概念
GPIO,全称为“通用输入/输出”(General Purpose Input/Output),是计算机系统中用于与外部世界进行数字通信的一种接口标准。它允许硬件和软件通过电信号来交换数据,控制外部设备或接收外部事件。GPIO通常用于连接各种外设,如按钮、LED灯、传感器、马达、继电器等,以便与计算机系统进行交互。
GPIO具备一些特性:
- 通用性:GPIO是通用的,意味着它们可以在不同类型的硬件平台上使用,而不必修改底层电路。这种通用性使得开发人员能够设计和编写与硬件无关的代码,实现跨平台的应用。
- 输入和输出:每个GPIO引脚都可以被配置为输入或输出。当配置为输入时,引脚用于接收外部信号,例如按钮状态或传感器读数。当配置为输出时,引脚用于控制外部设备,例如点亮LED或控制马达运动。
- 数字信号:GPIO是数字信号接口,这意味着它们只能传输二进制值(0和1)。通过在引脚之间切换电压,可以传递这些数字值,从而实现数据传输和通信。
- 控制:操作系统或应用程序可以通过读取或写入GPIO引脚来控制外部设备。通过设置输出引脚的电平(高电平或低电平),可以打开或关闭连接的设备。
- 事件触发:GPIO引脚可以用于检测外部事件。例如,一个传感器可能连接到GPIO引脚上,当传感器检测到特定条件时,它会改变引脚的状态,从而触发系统中的相应操作。
- 引脚编号:每个GPIO引脚都有一个唯一的编号,通常用数字或字母和数字的组合来表示。在不同的硬件平台上,引脚编号可能会有所不同。
- 驱动程序和库:为了在操作系统中使用GPIO,通常需要适当的驱动程序或库。这些驱动程序或库可以帮助应用程序与硬件进行交互,读取和写入GPIO引脚的状态。
背景知识
MOS管
MOS管有NMOS和PMOS两种类型。MOS管包含了三个极:
- gate:栅极,缩写G
- drain:漏极,缩写D
- source:源极,缩写S
MOS管的作用就是开关,通过栅极控制漏极和源极的导通。
mos管主要关注两个点:
- 控制。负责mos管导通和不导通,高电平导通还是低电平导通。
- 流向。是从漏极流向源极,还是从源极流向漏极。
NMOS
特点:
- 给栅极输入高电平时,mos管导通;给栅极输入低电平时,mos管断开;
- 导通时,方向是由漏极到源极;
通常NMOS的使用示例:
注意:
- nmos需要下拉电阻;
- nmos的开关线路上的消耗物必须放到漏极侧;
PMOS
特点:
- 给栅极输入高电平时,mos管断开;给栅极输入低电平时,mos管导通;
- 导通时,方向是由源极到漏极;
注意:
- pmos需要上拉电阻;
- pmos的开关线路上的消耗物必须放到漏极侧;
GPIO输出模式
推挽输出
基本的示意图如上,作为编程人员,我们更多关注的是下图:
我们希望的是,通过寄存器控制外部引脚的高低电平。
- 寄存器的配置高电平,外部引脚输出高电平
- 寄存器的配置低电平,外部引脚输出低电平
上图为简略图,这里提供一个详细的图:
上图过于复杂,在分析结果道理后,为了方便观察,我们看下图:
加上外部电路,我们理解以下推挽中的推是什么:
推挽中的挽是什么:
总结,寄存器控制输出低电平时,外部引脚为低;寄存器控制输出高电平时,外部引脚为高。
开漏输出
基本的示意图如上,作为编程人员,我们更多关注的是下图:
我们希望的是,通过寄存器控制外部引脚的高低电平。
- 寄存器的配置高电平,外部引脚断开。
- 寄存器的配置低电平,外部引脚输出低电平。
上图为简略图,这里提供一个详细的图:
上图过于复杂,在分析结果道理后,为了方便观察,我们简化看下图:
加上外部电路,我们理解一下开漏输出中的开是什么:
这里存在一个问题,开漏输出时,如果给高电平,外接的灯是不会亮的,因此开漏状态下我们需要进行上拉,如下所示:
我们理解一下开漏输出中的漏是什么:
高阻态
高阻态表示,不输出任何高低电平。
无论寄存器输出高或者低,外部引脚始终断开。
内部详细电路为:
高阻态是断路状态,无论外部上拉下拉,都不会导通。
GPIO输出线与
推挽线与
推挽过程中,如果一方输出高,一方输出低,则会烧芯片。
因此,推挽是不可以线与的。不能线与,说明不可以和其他芯片同时采用推挽这种方式连接,否则会出现问题。
开漏线与
开漏过程中,无论双方输出高低电平,芯片都不会收到影响。I2C就是线与的一个实例。
GPIO输入模式
上图为GPIO输入的基本示意图,其中包含了上拉电路,下拉电路,模拟信号处理,数字逻辑信号接收。
TTL(Transistor-Transistor Logic)施密特触发器是一种数字电路元件,常用于去除输入信号的噪声和抖动,并提供稳定的输出信号。它的作用在于消除输入信号的不稳定性,确保在输入信号发生变化时,输出信号能够产生可靠的、干净的转换。 TTL施密特触发器的主要作用有以下几个方面:
- 消除噪声和抖动:在数字电路中,输入信号可能受到噪声的干扰或产生抖动(快速的信号变化)。这可能导致触发器在边沿变化时产生不稳定的输出。TTL施密特触发器使用了一个双阈值比较器,只有当输入信号超过一定的阈值范围时,才会引发输出状态变化。这样可以防止在噪声或抖动情况下触发误动作。
- 提供干净的信号转换:TTL施密特触发器能够确保输入信号的干净转换,即使输入信号存在一些不稳定性或较慢的上升/下降时间。它的阈值范围内,输入信号的微小变化都不会引起输出变化,从而产生更加可靠的输出信号。
- 信号整形:TTL施密特触发器可用于整形输入信号的波形。如果输入信号具有不规则的上升和下降时间,触发器可以将其整形为规整的方波信号,以便后续电路处理。
- 边沿检测器:由于TTL施密特触发器对输入信号的变化非常敏感,它常被用作边沿检测器。当输入信号的上升沿或下降沿发生变化时,触发器可以产生输出脉冲,用于触发其他数字电路中的特定操作。
总之,我们简单的理解就是,输入的电压值被转化为了逻辑的0和1.
浮空输入
浮空输入,就是将模拟信号,上拉,下拉全部断开。只接收外部电路的输入信号。
这里会存在一个问题,如果外部没有输入信号,那么这个逻辑信号是未知的,不确定的。
上拉输入
上拉输入,就是将模拟信号,下拉全部断开,同时将上拉开关打开。然后接收外部电路的输入信号。
当外部输入高电平时,如下图:
当外部接入地时,如下图:
上拉输入的一些总结:
当输入信号未连接时,上拉电阻将确保输入信号保持在高电平状态,从而避免浮空输入。当外部信号连接到输入引脚时,外部信号可以通过上拉电阻的电流被拉低到低电平。
下拉输入
下拉输入,就是将模拟信号,上拉全部断开,同时将下拉开关打开。然后接收外部电路的输入信号。
当外部输入高电平时,如下图:
当外部接入地时,如下图:
下拉输入的一些总结:
当输入信号未连接时,下拉电阻将确保输入信号保持在低电平状态,从而避免浮空输入。当外部信号连接到输入引脚时,外部信号可以通过下拉电阻的电流被拉高到高电平。
模拟输入
模拟输入的内部结构如上图。
在真实的物理世界中,我们外部输入的是电压值,这个属于模拟信号。其他的几种输入就是把模拟信号变为逻辑的0和1。通常输入的电压在1v以下我们认为是逻辑的0,1v以上是逻辑的1。(不同的芯片处理信号方式不同,这里简单的举例为1v上下)。
模拟输入的是物理世界中的真实电压,模拟信号的处理不同与逻辑电路的转换,逻辑转换只有两种值。模拟信号则是线性的值,电压多大,就转换一个数字值,也就是将物理世界中的模拟数据转换为数字值,这个值是线性,有范围的。
ARM系列GPIO
寄存器
GPIO的寄存器大体上分为一下几种:
- 配置寄存器:配置输入输出,上拉下拉
- 数据寄存器:读取输入输出的状态
- 复位寄存器:输出高低电平
- 复用寄存器:配置复用功能
保护二极管
在线与,或者电压过大的情况下,将电压进行钳制,防止芯片烧毁。(当然这个是有限度的,得参考芯片手册内部的二极管特性)。GPIO工作模式
| 模式 | 性质 | | —- | —- | | 浮空输入 | 数字输入 | | 上拉输入 | 数字输入 | | 下拉输入 | 数字输入 | | 模拟输入 | 模拟输入 | | 开漏输出 | 数字输出 | | 推挽输出 | 数字输出 | | 复用开漏输出 | 数字输出 | | 复用推挽输出 | 数字输出 |
GD32/STM32系列GPIO工作模式
浮空输入
// 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 配置GPIO模式
gpio_mode_set(GPIOx, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_x);
- RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
-
上拉输入
// 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 配置GPIO模式
gpio_mode_set(GPIOx, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_x);
RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
-
下拉输入
// 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 配置GPIO模式
gpio_mode_set(GPIOx, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_x);
RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
-
模拟输入
// 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 配置GPIO模式
gpio_mode_set(GPIOx, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_x);
RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
-
推挽输出
// 1. 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 2. 配置GPIO 输入输出模式
gpio_mode_set(GPIOx, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_x);
// 3. 配置GPIO 模式的操作方式
gpio_output_options_set(GPIOx, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_x);
RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
-
开漏输出
// 1. 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 2. 配置GPIO 输入输出模式
gpio_mode_set(GPIOx, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_x);
// 3. 配置GPIO 模式的操作方式
gpio_output_options_set(GPIOx, GPIO_OTYPE_OD, GPIO_OSPEED_MAX, GPIO_PIN_x);
RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIO_PIN_x:具体是哪个引脚。(0~15)
复用推挽输出
// 1. 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 2. 配置GPIO 输入输出模式
gpio_mode_set(GPIOx, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_x);
// 3. 配置GPIO 模式的操作方式
gpio_output_options_set(GPIOx, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_x);
// 4. 复用功能
gpio_af_set(GPIOx, GPIO_MODE_AF, GPIO_AF_x, GPIO_PIN_x);
- RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIO_PIN_x:具体是哪个引脚。(0~15)
-
复用开漏输出
// 1. 时钟初始化
rcu_periph_clock_enable(RCU_GPIOx);
// 2. 配置GPIO 输入输出模式
gpio_mode_set(GPIOx, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_x);
// 3. 配置GPIO 模式的操作方式
gpio_output_options_set(GPIOx, GPIO_OTYPE_OD, GPIO_OSPEED_MAX, GPIO_PIN_x);
// 4. 复用功能
gpio_af_set(GPIOx, GPIO_MODE_AF, GPIO_AF_x, GPIO_PIN_x);
RCU_GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIOx: 具体是哪个端口。(A,B,C,D,E,F,G,H,I)
- GPIO_PIN_x:具体是哪个引脚。(0~15)
- GPIO_AF_x:具体复用什么功能。(0-15)
通常开漏时,需要外部上拉,当然内部电路也可以控制上拉。
练习题
- 实现多种输出模式下的点灯,体会输出模式。
- 实现按键输入,测试输入模式。