一、什么是GPIO
GPIO 是控制或者采集外部器件的信息的外设,即负责输入输出。它按组分配,每组 16 个 IO 口,组数视芯片而定。STM32F103ZET6 芯片是 144 脚的芯片,具有 GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF 和 GPIOG 七组 GPIO 口,共有 112 个 IO 口可供我们编程使用。
STM32F103 的绝大部分 IO 口,都兼容 5V。我们可以参考 STM32F103xE 的数据手册,见表 5 大容量 STM32F103xx 引脚定义,凡是有 FT 标志的,都是兼容 5V 电平的 IO 口,可以直接接 5V 的外设(注意:如果引脚设置的是模拟输入模式,则不能接 5V!)。
二、GPIO基本结构
【1】、保护二极管
保护二极管共有两个,用于保护引脚外部过高或过低的电压输入。当引脚输入电压高于 VDD 时,上面的二极管导通,当引脚输入电压低于 VSS 时,下面的二极管导通,从而使输入芯片内部的电压处于比较稳定的值。虽然有二极管的保护,但这样的保护却很有限,大电压大电流的接入很容易烧坏芯片。所以在实际的设计中我们要考虑设计引脚的保护电路。
【2】、上拉、下拉电阻
它们阻值大概在 30~50K 欧之间,可以通过上、下两个对应的开关控制,这两个开关由寄存器控制。当引脚外部的器件没有干扰引脚的电压时,即没有外部的上、下拉电压,引脚的电平由引脚内部上、下拉决定,开启内部上拉电阻工作,引脚电平为高,开启内部下拉电阻工作,则引脚电平为低。同样,如果内部上、下拉电阻都不开启,这种情况就是我们所说的浮空模式。浮空模式下,引脚的电平是不可确定的。引脚的电平可以由外部的上、下拉电平决定。需要注意的是,STM32 的内部上拉是一种“弱上拉”,这样的上拉电流很弱,如果有要求大电流还是得外部上拉。
【3】、施密特触发器
TTL肖特基触发器其实可以理解为用肖特基管构成的施密特触发器。对于标准施密特触发器,当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;当输入在正负向阈值电压之间,输出不改变,也就是说输出由高电准位翻转为低电准位,或是由低电准位翻转为高电准位对应的阈值电压是不同的。只有当输入电压发生足够的变化时,输出才会变化,因此将这种元件命名为触发器。这种双阈值动作被称为迟滞现象,表明施密特触发器有记忆性。从本质上来说,施密特触发器是一种双稳态多谐振荡器。
施密特触发器可作为波形整形电路,能将模拟信号波形整形为数字电路能够处理的方波波形,而且由于施密特触发器具有滞回特性,所以可用于抗干扰,以及在闭回路正回授/负回授配置中用于实现多谐振荡器。
【4】、P-MOS 管和 N-MOS 管
这个结构控制 GPIO 的开漏输出和推挽输出两种模式。开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。推挽输出:这两只对称的 MOS 管每次只有一只导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载拉电流。推拉式输出既能提高电路的负载能力,又能提高开关速度。
三、GPIO的工作模式
GPIO 有八种工作模式,分别是:(1)输入浮空;(2)输入上拉;(3)输入下拉;(4)模拟输入;(5)开漏输出;(6)推挽式输出;(7)推挽式复用功能;(8)开漏复用功能;
3.1、输入浮空
上拉/下拉电阻为断开状态,施密特触发器打开,输出被禁止。输入浮空模式下,IO 口的电平完全是由外部电路决定。如果 IO 引脚没有连接其他的设备,那么检测其输入电平是不确定的。该模式可以用于按键检测等场景。
空闲时,IO 状态不确定,由外部的环境决定;
3.2、输入上拉
上拉电阻导通,施密特触发器打开,输出被禁止。 在需要外部上拉电阻的时候,可以使用内部上拉电阻,这样可以节省一个外部电阻,但是内部上拉电阻的阻值较大,所以只是“弱上拉”,不适合做电流型驱动。
空闲时,IO 呈现高电平;
3.3、输入下拉
下拉电阻导通,施密特触发器打开,输出被禁止。 在需要外部下拉电阻的时候,可以使用内部下拉电阻,这样可以节省一个外部电阻,但是内部下拉电阻的阻值较大,所以不适合做电流型驱动。
空闲时,IO 呈现低电平;
3.4、模拟输入
上下拉电阻断开,施密特触发器关闭,双 MOS 管也关闭。其他外设可以通过模拟通道输入输出。 该模式下需要用到芯片内部的模拟电路单元单元,用于 ADC、DAC、MCO 这类操作模拟信号的外设。
专门用于模拟信号输入或输出,如:ADC 和 DAC;
3.5、开漏输出
STM32 的开漏输出模式是数字电路输出的一种,从结果上看它 只能输出低电平 VSS 或者高阻态,常用于 IIC 通讯(IIC_SDA)或其它需要进行电平转换的场景。
根据《STM32F10xxx参考手册_V10(中文版).pdf》第 108页 关于“GPIO输出配置”的描述,我们可以知道开漏模式下,IO 是这样工作的:
- P-MOS 被“输出控制”控制在截止状态,因此 IO 的状态取决于 N-MOS 的导通状况;
- 只有 N-MOS 还受控制于输出寄存器,“输出控制”对输入信号进行了逻辑非的操作;
- 施密特触发器是工作的,即可以输入,且上下拉电阻都断开了,可以看成浮空输入;
根据参考手册的描述:开漏输出模式下 P-MOS 一直在截止状态,即不导通,所以 P-MOS 管的栅极相当于一直接 VDD。
如果输出数据寄存器的值为 0,那么 IO 引脚的输出状态为低电平。输出数据寄存器的逻辑 0 经过“输出控制”的取反操作后,输出逻辑 1 到 N-MOS 管的栅极,这时 N-MOS 管就会导通,使得 IO 引脚连接到 VSS,即输出低电平。
如果输出数据寄存器的值为 1,经过“输出控制”的取反操作后,输出逻辑 0 到 N-MOS 管的栅极,这时 N-MOS 管就会截止。又因为 P-MOS 管是一直截止的,使得 IO 引脚呈现高阻态,即不输出低电平,也不输出高电平。因此要 IO 引脚输出高电平就必须接上拉电阻。 又由于 F1 系列的开漏输出模式下,内部的上下拉电阻不可用,所以只能通过接芯片外部上拉电阻的方式,实现开漏输出模式下输出高电平。如果芯片外部不接上拉电阻,那么开漏输出模式下,IO 无法输出高电平。
在开漏输出模式下,施密特触发器是工作的,所以 IO 口引脚的电平状态会被采集到输入数据寄存器中,如果对输入数据寄存器进行读访问可以得到 IO 口的状态。也就是说开漏输出模式下,我们可以读取 IO 引脚状态。
不能输出高电平,必须由外部(或内部)上拉才能输出高电平;
3.6、开漏复用功能
一个 IO 口 可以是 通用的 IO 口功能,还可以是 其他外设的特殊功能引脚,这就是 IO 口的复用功能。一个 IO 口可以是多个外设的功能引脚,我们需要选择作为其中一个外设的功能引脚。当选择复用功能时,引脚的状态是由对应的外设控制,而不是输出数据寄存器。除了复用功能外,其他的结构分析请参考开漏输出模式。
另外 在开漏式复用功能模式下,施密特触发器也是打开的,我们可以读取 IO 口的电平状态,同时外设可以读取 IO 口的信息。
不能输出高电平,必须由外部(或内部)上拉才能输出高电平,由其它外设控制输出;
3.7、推挽式输出
STM32 的推挽输出模式,从结果上看它会 输出低电平 VSS 或者高电平 VDD。推挽输出跟开漏输出不同的是,推挽输出模式 P-MOS 管和 N-MOS 管都用上。
如果输出数据寄存器的值为 0,经过“输出控制”取反操作后,输出逻辑 1 到 P-MOS 管的栅极,这时 P-MOS 管就会截止,同时也会输出逻辑 1 到 N-MOS 管的栅极,这时 N-MOS 管就会导通,使得 IO 引脚接到 VSS,即输出低电平。
如果输出数据寄存器的值为 1 ,经过“输出控制”取反操作后,输出逻辑 0 到 N-MOS 管的栅极,这时 N-MOS 管就会截止,同时也会输出逻辑 0 到 P-MOS 管的栅极,这时 P-MOS 管就会导通,使得 IO 引脚接到 VDD,即输出高电平。
推挽输出模式下,P-MOS 管和 N-MOS 管同一时间只能有一个管是导通的。 当 IO 引脚在做高低电平切换时,两个管子轮流导通,一个负责灌电流,一个负责拉电流,使其负载能力和开关速度都有较大的提高。
另外 在推挽输出模式下,施密特触发器也是打开的,我们可以读取 IO 口的电平状态。
由于推挽输出模式下输出高电平时,是直接连接 VDD,所以驱动能力较强,可以做电流型驱动,驱动电流最大可达 25mA,但是芯片的总电流有限,所以并不建议这样用,最好还是使用芯片外部的电源。
可输出高低电平,驱动能力强;
3.8、推挽式复用功能
一个 IO 口 可以是 通用的 IO 口功能,还可以是 其他外设的特殊功能引脚,这就是 IO 口的复用功能。一个 IO 口可以是多个外设的功能引脚,我们需要选择作为其中一个外设的功能引脚。当选择复用功能时,引脚的状态是由对应的外设控制,而不是输出数据寄存器。除了复用功能外,其他的结构分析请参考推挽式输出模式。
另外 在推挽式复用功能模式下,施密特触发器也是打开的,我们可以读取 IO 口的电平状态,同时外设可以读取 IO 口的信息。
可输出高低电平,驱动能力强,由其它外设控制输出;
四、复用功能
使用默认复用功能前必须对端口位配置寄存器编程。
- 对于 复用的输入功能,端口必须配置成 输入模式(浮空、上拉 或 下拉)且 输入引脚必须由外部驱动
- 也可以通过软件来模拟复用功能输入引脚,这种模拟可以通过对 GPIO 控制器编程来实现。此时,端口应当被设置为复用功能输出模式。显然,这时相应的引脚不再由外部驱动,而是通过GPIO控制器由软件来驱动。
- 对于 复用输出功能,端口必须配置成 复用功能输出模式(推挽 或 开漏)
- 对于 双向复用功能,端口位必须配置 复用功能输出模式(推挽 或 开漏)。这时,输入驱动器 被配置成 浮空输入模式。
如果把端口配置成复用输出功能,则引脚和输出寄存器断开,并和片上外设的输出信号连接。如果软件把一个 GPIO引脚 配置成 复用输出功能,但是外设没有被激活,它的输出将不确定。
当 I/O 端口被配置为复用功能时:
- 开漏或推挽式配置中,输出缓冲器被打开
- 内置外设的信号驱动输出缓冲器(复用功能输出)
- 施密特触发输入被激活
- 弱上拉 和 下拉电阻 被禁止
- 在每个 APB2 时钟周期,出现在 I/O 引脚上的数据被采样到输入数据寄存器
- 开漏模式时,读输入数据寄存器时可得到 I/O 口状态
- 在推挽模式时,读输出数据寄存器时可得到最后一次写的值
五、GPIO寄存器介绍
每个 GPIO 端口有两个 32 位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR),一个 32 位置位/复位寄存器(GPIOx_BSRR),一个 16 位复位寄存器(GPIOx_BRR)和 一个 32 位锁定寄存器(GPIOx_LCKR)。
每个 I/O 端口位可以自由编程,然而 I/O 端口寄存器必须按 32 位字被访问(不允许半字或字节访问)。GPIOx_BSRR 和 GPIOx_BRR 寄存器允许对任何 GPIO 寄存器的读/更改的独立访问;这样,在读和更改访问之间产生 IRQ 时不会发生危险。
5.1、端口配置寄存器(GPIOx_CRL、GPIOx_CRH)(x=A..E)
这两个寄存器都是 GPIO 口配置寄存器,不过 CRL 控制端口的低八位,CRH 控制端口的高八位。寄存器的作用是控制 GPIO 口的工作模式和工作速度。每组 GPIO 下有 16 个 IO 口,一个寄存器共 32 位,每 4 个位控制 1 个 IO,所以才需要两个寄存器完成。
上面这 2 个配置寄存器就是用来配置 GPIO 的相关工作模式和工作速度,它们通过不同的配置组合方法,就决定我们所说的 8 种工作模式。
端口配置表:
配置模式 | CNF1 | CNF0 | MODE1 | MODE2 | PxODR寄存器 | |
---|---|---|---|---|---|---|
通用输出 | 推挽(Push-Pull) | 0 | 0 |
01 10 11 见下表输出模式位 |
0 或 1 | |
开漏(Open-Drain) | 1 | 0 或 1 | ||||
复用功能输出 | 推挽(Push-Pull) | 1 | 0 | 不使用 | ||
开漏(Open-Drain) | 1 | 不使用 | ||||
输入 | 模拟输入 | 0 | 0 | 00 | 不使用 | |
浮空输入 | 1 | 不使用 | ||||
下拉输入 | 1 | 0 | 0 | |||
上拉输入 | 1 | |||||
输出模式位:
MODE[1:0] | 意义 |
---|---|
00 | 保留 |
01 | 最大输出速度为 10MHz |
10 | 最大输出速度为 2MHz |
11 | 最大输出速度为 50MHz |
这两个寄存器都是 GPIO 口配置寄存器,不过 CRL 控制端口的低八位,CRH 控制端口的高八位。
每组 GPIO 下有 16 个 IO 口,一个寄存器共 32 位,每 4 个位控制 1 个 IO,所以才需要两个寄存器完成。
5.2、端口输入数据寄存器(GPIOx_IDR)(x=A..E)
该寄存器用于存储 GPIOx 的输入状态,它连接到施密特触发器上,IO 口外部的电平信号经过触发器后,模拟信号就被转化成 0 和 1 这样的数字信号,并存储到该寄存器中。
该寄存器低 16 位有效,分别对应每一组 GPIO 的 16 个引脚。当 CPU 访问该寄存器,如果对应的某位为 0(IDRy = 0),则说明该 IO口 输入的是 低电平,如果是 1(IDRy = 1),则表示输入的是高电平,y = 0~15。
5.3、端口输出数据寄存器(GPIOx_ODR)(x=A..E)
该寄存器用于控制 GPIOx 的输出高电平或者低电平。该寄存器低 16 位有效,分别对应每一组 GPIO 的 16 个引脚。当 CPU 写访问该寄存器,如果对应的某位写 0 (ODRy = 0),则表示设置该 IO 口输出的是低电平,如果写 1(ODRy = 1),则表示设置该 IO 口输出的是高电平,y = 0~15。
5.4、端口位设置/清除寄存器(GPIOx_BSRR)(x=A..E)
该寄存器也用于控制 GPIOx 的输出高电平或者低电平。
为什么有了 GPIOx_ODR 寄存器,还要这个 GPIOx_BSRR 寄存器呢?
GPIOx_BSRR 是只写权限,而 GPIOx_ODR 是可读可写权限。GPIOx_BSRR 寄存器 32 位有效,对于低 16 位(0-15),我们往相应的位写 1(BSy = 1),那么对应的 IO 口会输出高电平,往相应的位写 0(BSy = 0),对 IO 口没有任何影响,高 16 位(16-31)作用刚好相反,对相应的位写 1(BRy = 1)会输出低电平,写 0(BRy = 0)没有任何影响,y = 0~15。
也就是说,对于 GPIOx_BSRR 寄存器,你写 0 的话,对 IO 口电平是没有任何影响的。我们要设置某个 IO 口电平,只需要相关位设置为 1 即可。而 GPIOx_ODR 寄存器,我们要设置某个 IO 口电平,我们首先需要读出来 GPIOx_ODR 寄存器的值,然后对整个 GPIOx_ODR 寄存器重新赋值来达到设置某个或者某些 IO 口的目的,而 GPIOx_BSRR 寄存器直接设置即可,这在多任务实时操作系统中作用很大。
GPIOX_BSRR 寄存器还有一个好处,就是 GPIOx_BSRR 寄存器改变引脚状态的时候,不会被中断打断,而 GPIOx_ODR 寄存器有被中断打断的风险。
5.5、端口位清除寄存器(GPIOx_BRR) (x=A..E)
5.6、端口配置锁定寄存器(GPIOx_LCKR) (x=A..E)
六、GPIO配置步骤
HAL 库中关于 GPIO 的驱动程序在 stm32f1xx_hal_gpio.c 文件以及其对应的头文件 stm32f1xx_hal_gpio.h 中。
6.1、使能对应GPIO时钟
STM32 在使用任何外设之前,我们都要先使能其时钟。有关片上外设使能的头文件放在 stm32f1xx_hal_rcc.h 和 stm32f1xx_hal_rcc_ex.h 头文件中。
/** @defgroup RCC_APB2_Clock_Enable_Disable APB2 Clock Enable Disable
* @brief Enable or disable the High Speed APB (APB2) peripheral clock.
* @note After reset, the peripheral clock (used for registers read/write access)
* is disabled and the application software has to enable this clock before
* using it.
* @{
*/
#define __HAL_RCC_GPIOA_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);\
/* Delay after an RCC peripheral clock enabling */\
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);\
UNUSED(tmpreg); \
} while(0U)
#define __HAL_RCC_GPIOB_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);\
/* Delay after an RCC peripheral clock enabling */\
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);\
UNUSED(tmpreg); \
} while(0U)
#define __HAL_RCC_GPIOC_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);\
/* Delay after an RCC peripheral clock enabling */\
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);\
UNUSED(tmpreg); \
} while(0U)
#define __HAL_RCC_GPIOD_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPDEN);\
/* Delay after an RCC peripheral clock enabling */\
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPDEN);\
UNUSED(tmpreg); \
} while(0U)
/** @defgroup RCCEx_APB2_Clock_Enable_Disable APB2 Clock Enable Disable
* @brief Enable or disable the High Speed APB (APB2) peripheral clock.
* @note After reset, the peripheral clock (used for registers read/write access)
* is disabled and the application software has to enable this clock before
* using it.
* @{
*/
#if defined(STM32F100xE) || defined(STM32F101xB) || defined(STM32F101xE)\
|| defined(STM32F101xG) || defined(STM32F100xB) || defined(STM32F103xB)\
|| defined(STM32F103xE) || defined(STM32F103xG) || defined(STM32F105xC)\
|| defined(STM32F107xC)
#define __HAL_RCC_GPIOE_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPEEN);\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPEEN);\
UNUSED(tmpreg); \
} while(0U)
#endif /* STM32F101x6 || STM32F101xB || STM32F101xE || (...) || STM32F105xC || STM32F107xC */
#if defined(STM32F101xE) || defined(STM32F103xE) || defined(STM32F101xG)\
|| defined(STM32F103xG)
#define __HAL_RCC_GPIOF_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPFEN);\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPFEN);\
UNUSED(tmpreg); \
} while(0U)
#define __HAL_RCC_GPIOG_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPGEN);\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPGEN);\
UNUSED(tmpreg); \
} while(0U)
#endif /* STM32F101xE || STM32F103xE || STM32F101xG || STM32F103xG*/
6.2、设置工作模式
【1】、HAL_GPIO_Init() 函数
HAL_GPIO_Init() 函数是外设 GPIO 初始化函数,用来配置 GPIO 功能模式。外设 GPIO 的初始化函数声明如下:
/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
- 函数形参:
GPIOx 是 端口号,其中 x 可以是 A-G:
/** @addtogroup Peripheral_declaration
* @{
*/
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *)GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *)GPIOG_BASE)
GPIO_Init 是 GPIO_InitTypeDef 类型的结构体变量,其定义如下:
/**
* @brief GPIO Init structure definition
*/
typedef struct
{
uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIO_mode_define */
uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref GPIO_pull_define */
uint32_t Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIO_speed_define */
} GPIO_InitTypeDef;
成员 Pin 表示 引脚号,范围:GPIO_PIN_0 到 GPIO_PIN_15,另外还有 GPIO_PIN_Al l 可选。
/** @defgroup GPIO_pins_define GPIO pins define
* @{
*/
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
成员 Mode 是 GPIO 的 模式选择,有以下选择项:
/** @defgroup GPIO_mode_define GPIO mode define
* @brief GPIO Configuration Mode
* Elements values convention: 0xX0yz00YZ
* - X : GPIO mode or EXTI Mode
* - y : External IT or Event trigger detection
* - z : IO configuration on External IT or Event
* - Y : Output type (Push Pull or Open Drain)
* - Z : IO Direction mode (Input, Output, Alternate or Analog)
* @{
*/
#define GPIO_MODE_INPUT 0x00000000u /*!< Input Floating Mode */
#define GPIO_MODE_OUTPUT_PP 0x00000001u /*!< Output Push Pull Mode */
#define GPIO_MODE_OUTPUT_OD 0x00000011u /*!< Output Open Drain Mode */
#define GPIO_MODE_AF_PP 0x00000002u /*!< Alternate Function Push Pull Mode */
#define GPIO_MODE_AF_OD 0x00000012u /*!< Alternate Function Open Drain Mode */
#define GPIO_MODE_AF_INPUT GPIO_MODE_INPUT /*!< Alternate Function Input Mode */
#define GPIO_MODE_ANALOG 0x00000003u /*!< Analog Mode */
成员 Pull 用于 配置上下拉电阻,有以下选择项:
/** @defgroup GPIO_pull_define GPIO pull define
* @brief GPIO Pull-Up or Pull-Down Activation
* @{
*/
#define GPIO_NOPULL 0x00000000u /*!< No Pull-up or Pull-down activation */
#define GPIO_PULLUP 0x00000001u /*!< Pull-up activation */
#define GPIO_PULLDOWN 0x00000002u /*!< Pull-down activation */
成员 Speed 用于 配置 GPIO 的速度,有以下选择项:
/** @defgroup GPIO_speed_define GPIO speed define
* @brief GPIO Output Maximum frequency
* @{
*/
#define GPIO_SPEED_FREQ_LOW (GPIO_CRL_MODE0_1) /*!< Low speed */
#define GPIO_SPEED_FREQ_MEDIUM (GPIO_CRL_MODE0_0) /*!< Medium speed */
#define GPIO_SPEED_FREQ_HIGH (GPIO_CRL_MODE0) /*!< High speed */
- 函数返回值:
无;
6.3、设置输出状态
【1】、HAL_GPIO_WritePin() 函数
HAL_GPIO_WritePin() 函数是 GPIO 口的写引脚函数,用于设置引脚输出高电平或者低电平,通过 GPIOx_BSRR 寄存器复位或者置位操作。其声明如下:
/**
* @brief Sets or clears the selected data port bit.
*
* @note This function uses GPIOx_BSRR register to allow atomic read/modify
* accesses. In this way, there is no risk of an IRQ occurring between
* the read and the modify access.
*
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to be written.
* This parameter can be one of GPIO_PIN_x where x can be (0..15).
* @param PinState: specifies the value to be written to the selected bit.
* This parameter can be one of the GPIO_PinState enum values:
* @arg GPIO_PIN_RESET: to clear the port pin
* @arg GPIO_PIN_SET: to set the port pin
* @retval None
*/
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
- 函数参数:
GPIOx 是 端口号,其中 x 可以是 A-G:
/** @addtogroup Peripheral_declaration
* @{
*/
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *)GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *)GPIOG_BASE)
GPIO_Pin 是引脚号,可以选择范围:GPIO_PIN_0 到 GPIO_PIN_15:
/** @defgroup GPIO_pins_define GPIO pins define
* @{
*/
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
PinState 是要设置输出的状态,是枚举型有两个选择:GPIO_PIN_SET 表示 高电平,GPIO_PIN_RESET 表示 低电平。
/**
* @brief GPIO Bit SET and Bit RESET enumeration
*/
typedef enum
{
GPIO_PIN_RESET = 0u,
GPIO_PIN_SET
} GPIO_PinState;
- 函数返回值:
无;
【2】、HAL_GPIO_TogglePin() 函数
HAL_GPIO_TogglePin() 函数是 GPIO 口的电平翻转函数也是通过 GPIOx_BSRR 寄存器复位或者置位操作。其声明如下:
/**
* @brief Toggles the specified GPIO pin
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: Specifies the pins to be toggled.
* @retval None
*/
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
- 函数参数:
GPIOx 是 端口号,其中 x 可以是 A-G:
/** @addtogroup Peripheral_declaration
* @{
*/
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *)GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *)GPIOG_BASE)
GPIO_Pin 是引脚号,可以选择范围:GPIO_PIN_0 到 GPIO_PIN_15:
/** @defgroup GPIO_pins_define GPIO pins define
* @{
*/
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
- 函数返回值:
无;
6.4、读取输入状态
【1】、HAL_GPIO_ReadPin() 函数
HAL_GPIO_ReadPin() 函数是 GPIO 口的读引脚函数,通过 GPIOx_IDR 寄存器读取。其声明如下:
/**
* @brief Reads the specified input port pin.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to read.
* This parameter can be GPIO_PIN_x where x can be (0..15).
* @retval The input port pin value.
*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
- 函数参数:
GPIOx 是 端口号,其中 x 可以是 A-G:
/** @addtogroup Peripheral_declaration
* @{
*/
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *)GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *)GPIOG_BASE)
GPIO_Pin 是引脚号,可以选择范围:GPIO_PIN_0 到 GPIO_PIN_15:
/** @defgroup GPIO_pins_define GPIO pins define
* @{
*/
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
- 函数返回值:
GPIO_PinState 枚举类型的值,有 2 个,分别是:GPIO_PIN_RESET 表示 低电平;GPIO_PIN_SET 表示 高电平;
/**
* @brief GPIO Bit SET and Bit RESET enumeration
*/
typedef enum
{
GPIO_PIN_RESET = 0u,
GPIO_PIN_SET
} GPIO_PinState;
标签:selected,通用,07,Pin,PIN,uint16,GPIO,define
From: https://www.cnblogs.com/kurome/p/17739225.html