【STM32】GPIO


一、GPIO是什么?

GPIO全称general-purpose input/output ,即通用输入输出端口。

二、外设框图

在这里插入图片描述

输入通道整体输入逻辑: 外界信号通过IO口进入单片机后,首先由保护二极管检查是否具有破坏性,检查通过后经过上下拉电路,该电路是设置默认电平的,从这里开始,信号要么直接输入,即模拟输入,要么经过触发器转化为数字信号,然后再分叉,要么保存在输入数据寄存器由用户读取,要么复用,被片上外设读取。

1、保护二极管

利用二极管达到阈值电压单向导通的特性,防止从引脚输入过大或过小电压。

当输入电压超过VDD+0.7V(假使是硅管),则上面的二极管导通。
当输入电压小于Vss-0.7V,则下面的二极管导通。

由此将真正输入芯片的电压钳位在Vss-0.7V至VDD+0.7V之间。

2、上下拉电阻

通过软件可以控制内部是否接入上下拉电阻,一共有三种情况:
①仅开启上拉电阻,引脚默认输出高电平
②仅开启下拉电阻,引脚默认输出低电平
③上拉下拉电阻都不开启,此时引脚处于浮空状态

浮空模式下,引脚的电压是不确定的,可能为1,也可能为0,来回摇摆。

根据拉电阻的阻值大小,可以分为强拉弱拉

拉电阻较小时为强拉,可以抵抗外部噪声的能力较强,代价是相应的功耗也较大。

STM32内部的拉电阻属于弱拉,通过查阅数据手册可知拉电阻阻值在40K左右,通过此拉电阻输出的电流很小,如果想要输出一个大电流。那么就需要外接阻值较小的拉电阻了,其实就是增加导线的输出电流。
在这里插入图片描述

3、输入数据寄存器

经过上下拉电阻的信号有三个去向,首先就是经过触发器转化为0/1进入输入数据寄存器。
在这里插入图片描述

4、模拟输入

其次信号如果不经过触发器,则可以将外部模拟信号直接输入内部,如ADC。

5、复用功能输入

第三个去向就是将信号转化为0/1后交由外设处理。


输出通道的整体逻辑: 输出的数据来源有3个,首先我可以控制位设置/清除寄存器,将IO口写1/0,我也可以将多个二进制数据写入数据输出寄存器让IO口依次输出,我还可以将控制权交给片内外设,让它控制IO输出它想要输出的信号。是用户控制还是外设控制由输出控制左边的梯形结构进行切换,输出信号经过双MOS 结构可以调整为推挽模式还是开漏模式,最后经过IO口输出。

6、输出数据寄存器

将想要输出的数据放入该寄存器内
在这里插入图片描述

7、位设置/清除寄存器

将IO口置0或置1。

其中高16位负责reset,低16位负责set。

在这里插入图片描述
除了GPIOx_BSRR,还有一个类似的寄存器叫GPIOx_BRR,它相当于GPIOx_BSRR的高16位
在这里插入图片描述
这个“多余“的寄存器只是为了方便IO口清0,不像BSRR要清零还得先将数据左移16位再写入。

8、复用功能输出

将GPIO输出控制权交给内部外设,输出外设想要输出的信号。

9、双MOS管结构

该结构可以实现推挽输出开漏输出

(1)推挽输出

推挽输出两个MOS管都工作。

当输入为1时,经过反相器得到0,此时PMOS导通,NMOS截止,电流从VDD“推向”输出端,最后输出1;

当输入为0时,经过反相器得到1,此时PMOS截止,NMOS导通,电流从输出端被“拉回”地,拉回也就是挽的意思,最后输出0;
在这里插入图片描述

(2)开漏输出

开漏输出只用到了NMOS。

当输入为1时,经过反相器得到0,此时NMOS截止,引脚相当于在内部被断开,既不输出1也不输出0,对输出高阻态;

当输入为0时,经过反相器得到1,此时NMOS导通,对外输出0;

在这里插入图片描述
想要输出高电平则需要外加上拉电阻:
在这里插入图片描述
这种结构有一个重要的特性就是线与特性,即当有多个设置为开漏输出模式的引脚连在一起时,只要有一个引脚输出0,则整个线路为0,只有所有引脚输出为高阻态,线路上电平才为1。
在这里插入图片描述

开漏输出的应用:
①I2C通讯,该通讯协议通过线与解决多主机同时发送数据时的优先级判断,详见【STM32】I2C
②电平转换,如果要用3.3V单片机控制5V外设,则可以用开漏输出模式,外加一个连接5V的上拉电阻

10、端口配置寄存器(不在框图中)

端口配置寄存器有两个,其中GPIOx_CRL控制低8位,GPIOx_CRH控制高8位。
在这里插入图片描述
在这里插入图片描述
这两个32位寄存器分别控制16个IO口,每个IO口都有一个专属的MODE[1:0]和CNF[0:1]控制。

其中,MODE控制是输入还是输出,输出又有详细的速度配置,支持速率越高,功耗越大。

CNF控制在输入和输出模式下具体的工作模式配置。

GPIO共有8种工作模式:
①模拟输入,如ADC采集
②上拉输入
③下拉输入
④浮空输入,如按键检测

⑤推挽输出,如点亮LED
⑥开漏输出,如I2C,电平转换
⑦复用推挽输出,即由外设控制输出
⑧复用开漏输出,即由外设控制输出

三、编程

首先初始化GPIO

void LED_GPIO_Config(void)
{		
		/*定义一个GPIO_InitTypeDef类型的结构体*/
		GPIO_InitTypeDef GPIO_InitStructure;

		/*开启LED相关的GPIO外设时钟*/
		RCC_APB2PeriphClockCmd( LED1_GPIO_CLK, ENABLE);
		/*选择要控制的GPIO引脚*/
		GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;	

		/*设置引脚模式为通用推挽输出*/
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

		/*设置引脚速率为50MHz */   
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

		/*调用库函数,初始化GPIO*/
		GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);	
		/* 关闭所有led灯	*/
		GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
}

然后就可以库函数了

void GPIO_DeInit(GPIO_TypeDef* GPIOx);//恢复默认设置
void GPIO_AFIODeInit(void);
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//将配置参数写入寄存器
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);//填充GPIO_InitStruct内的元素为复位值
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读指定IO引脚输入数据
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);//读指定端口输入数据
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读指定端口引脚输出数据
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);//读指定端口输出数据
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//置1指定的端口引脚
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//清0指定的端口引脚
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);//设置或清除选择的数据端口引脚
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);//写指定数据到GPIOx端口寄存器
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//选择GPIO引脚作为事件输出
void GPIO_EventOutputCmd(FunctionalState NewState);//允许或禁止事件输出
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//选择IO口作为事件线
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

四、答疑

1、GPIO引脚驱动能力?

在这里插入图片描述
25mA,可以驱动一般的发光二极管。

2、我怎么知道每个外设相应的引脚应该配置为什么模式?

参考手册中有明确规定
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考资料

1、《STM32库开发实战指南》
2、https://zhuanlan.zhihu.com/p/362467204

待补充内容:GPIO中断

### STM32 GPIO 配置与使用 STM32 的通用输入/输出 (GPIO) 是其核心功能之一,用于连接外部设备并与之交互。以下是关于如何配置和使用 STM32 GPIO 的详细介绍。 #### 使用 STM32CubeMX 工具配置 GPIO STM32CubeMX 提供了一种直观的方式来进行 GPIO 配置。用户可以在芯片引脚图上直接设置 IO 口的功能模式和其他参数。例如,在某一实例中,PB0 和 PB1 被选作目标 IO 口进行配置[^1]。这些配置可以通过图形界面完成,具体包括: - **模式选择**: 用户可以选择将 GPIO 设置为输入、输出、复用功能或者模拟功能。 - **速度设定**: 输出模式下可以调整驱动能力的速度选项(低速、中速、高速或超高速)。 - **上下拉电阻**: 支持无上下拉、上拉或下拉三种状态的选择。 #### 中断处理机制中的 GPIO 应用 除了基本的输入输出操作外,STM32 还支持通过嵌套向量中断控制器 (NVIC) 来管理由 GPIO 引发的中断事件。这种机制允许开发人员定义不同中断源之间的优先级关系,从而优化系统的实时性能[^3]。当中断发生时,程序可以根据预先设定好的抢占优先级以及子优先级来决定哪个中断应该被最先服务。 #### 编程实践示例 下面给出一段简单的代码片段展示如何初始化一个 GPIO 并读取它的值: ```c #include "stm32f1xx_hal.h" void GPIO_Init(void){ __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Configure PB0 as output */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } int main(void){ GPIO_Init(); while(1){ HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // Toggle the state of pin PB0 every second. HAL_Delay(1000); } } ``` 上述代码展示了如何利用 HAL 库函数 `__HAL_RCC_GPIOB_CLK_ENABLE()` 启用 GPIOB 时钟,并通过结构体变量 `GPIO_InitStruct` 完成对特定管脚的具体属性赋值过程;最后调用了 `HAL_GPIO_Init()` 函数实际执行硬件初始化工作。 #### 总结 通过对 STM32F103 系列的学习可以帮助初学者快速入门整个 STM32 家族的产品线[^2]。而掌握好 GPIO 的基础应用则是迈向更复杂项目的第一步。无论是简单 LED 控制还是复杂的传感器数据采集场景,合理规划并正确实施 GPIO 设定都是非常重要的环节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值