STM32 - GPIO详解

本文以STM32F40 为例进行讲解,其它雷同

1. GPIO简介

GPIO(general purpose input output,通用输入输出端口)

简单来说就是软件可控制的引脚:STM32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。

1)GPIO引脚分布图

如上图

- GPIO有 PA ~ PG + PH0、PH1 总共114个GPIO pin
- PA~PG:每组包含 16 个IO

2)STM32引脚分类

序号 引脚类型 引脚 备注
1 电源 VBAT、VDD、VSS、VDDA、VSSA,VREF+、VREF-等 VBAT是备用电源
VDD和VSS是数字电源
VDDA和VSSA是模拟电源
VREF+和VREF-是参考电源。
2 晶振 主晶振IO、RTC晶振IO
3 下载&调试 用于JTAG下载的IO:JTMS、JTCK、JTDI、JTDO、NJRST
4 BOOT BOOT0、BOOT1 用于设置系统的启动方式
5 GPIO GPIOA ~ GPIOx 专用器件接到专用总线,如I2C、SPI、SDIO、FSM、DCMI等总线需要接到专用的IO。
普通元器件(如蜂鸣器、LED灯、按键灯),使用普通的GPIO功能即可

Notice:商标中,1/2/3/4引脚类型,构成了嵌入式的最小系统

2. 端口配置

GPIO的基本电路结构如下:

2.1 基本部件

1)保护二极管

芯片的引脚电平0~3.3V,部分引脚可以5V,超过5V,将会对芯片造成损害。

如上图 ① 标识,主要是保护芯片免受外部输入电平过高或者过低的影响,进而保护整个芯片。

其原理为:

  • 当输入电压高于VDD_FT,上面二极管导通,使得电压最大为VDD_FT
  • 当输入电压低于VSS,上面二极管导通,使得电压最低为VSS

2)上拉/下拉电阻

用于输定输入电压

3)MOS管

用于实现推挽和开漏输出

4)施密特触发器

具有 稳压 和 滤波 的作用,就是让通过的电平输出稳定的高低电平

输入的电平往往存在着失真、不稳定、波动等,使用施密特触发器,可以过滤掉噪声干扰,最大限度的稳定输出电压

原理:

● 当电压大于正向阈值Vth,输出高电平
● 当输入电压低于阈值Vtl,输出低电平
● 当输入电平处于 Vtl ~ Vth 之间,输出保持不变

2.2 模式配置

GPIO 各个端口位分别配置为多种模式:

模式 性质 备注
输入浮空 数字输入 可读取引脚电平
若悬空,则电平不确定
输入上拉 数字输入 可读取引脚电平
若悬空,则电平为高
输入下拉 数字输入 可读取引脚电平
若悬空,则电平为低
模拟功能 模拟输入 GPIO无效
引脚直接接入内部ADC
开漏输出 数字输出 可输出引脚电平
高电平为高阻态,低电平为Vss
推挽输出 数字输出 可输出引脚电平
高电平接Vdd,低电平为Vss
复用功能推挽 数字输出 由片上外设控制
高电平为高阻态,低电平为Vss
复用功能开漏 数字输出 由片上外设控制
高电平接Vdd,低电平为Vss

1)浮空、上拉、下拉 输入

输入模式下,输出被禁止,施密特触发器打开。

由于电阻阻值很大,因此这里的上拉、下拉输入都是弱上拉、弱下拉,为了不对外部输入产生很大的影响

上拉输入:给一个默认的高电平,当没有外部输入时,默认输入高电平

下拉输入:给一个默认的低电平,当没有外部输入时,默认输入低电平

悬空输入: 如果输入引脚啥都不接,此时输入电平极易受外界的干扰导致输入电平不确定,完全由外部的输入决定

2)模拟输入

该模式主要为片上外设ADC而配置,从外部读取模拟信号

对 I/O 端口进行编程作为模拟配置时:

● 输出缓冲器被禁止。
● 施密特触发器输入停用,I/O 引脚的每个模拟输入的功耗变为零。施密特触发器的输出被 
强制处理为恒定值 (0)。
● 弱上拉和下拉电阻被关闭。
● 对输入数据寄存器的读访问值为“0”。

3)开漏、推挽 输出

对 I/O 端口进行编程作为输出时:

● 输出缓冲器被打开:
  — 开漏模式:输出寄存器中的“0”可激活 N-MOS,而输出寄存器中的“1”会使端保持高组态 (Hi-Z)(P-MOS 始终不激活)。
  — 推挽模式:输出寄存器中的“0”可激活 N-MOS,而输出寄存器中的“1”可激活 P-MOS。
● 施密特触发器输入被打开
● 根据 GPIOx_PUPDR 寄存器中的值决定是否打开弱上拉电阻和下拉电阻
● 输入数据寄存器每隔 1 个 AHB1 时钟周期对 I/O 引脚上的数据进行一次采样
● 对输入数据寄存器的读访问可获取 I/O 状态
● 对输出数据寄存器的读访问可获取最后的写入值

①. 推挽输出

  • 当输出寄存器为高电平时,P-MOS导通,N-MOS截止,Vout=Vdd

  • 当输出寄存器为高电平时,N-MOS导通,P-MOS截止,Vout=Vss

②. 开漏输出

  • 当输出寄存器输出高电平,则引脚输出高阻态

  • 当输出寄存器输出低电平,则引脚输出低电平

4)复用输出

对 I/O 端口进行编程作为复用功能时:

● 可将输出缓冲器配置为开漏或推挽
● 输出缓冲器由来自外设的信号驱动(发送器使能和数据)
● 施密特触发器输入被打开
● 根据 GPIOx_PUPDR 寄存器中的值决定是否打开弱上拉电阻和下拉电阻
● 输入数据寄存器每隔 1 个 AHB1 时钟周期对 I/O 引脚上的数据进行一次采样
● 对输入数据寄存器的读访问可获取 I/O 状态

以串口为例:

  • 串口的发送引脚TX

  • 串口的接收引脚RX

3. 寄存器

对GPIO的控制,实际上就是对寄存器的读写,不同的配置,产生不同的功能。

GPIO含有10中寄存器:

● 4 个 32 位配置寄存器(GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR 和 GPIOx_PUPDR)
● 2 个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR)
● 1 个 32 位置位/复位寄存器 (GPIOx_BSRR)
● 1 个 32 位锁定寄存器 (GPIOx_LCKR) 
● 2 个 32 位复用功能选择寄存器(GPIOx_AFRH 和 GPIOx_AFRL)

1)GPIO 端口模式寄存器 (GPIOx_MODER) (x = A..I)

GPIO port mode register
偏移地址:0x00
复位值:
  ● 0xA800 0000(端口 A)
  ● 0x0000 0280(端口 B)
  ● 0x0000 0000(其它端口)

2) GPIO 端口输出类型寄存器 (GPIOx_OTYPER) (x = A..I)

GPIO port output type register
偏移地址:0x04
复位值:0x0000 0000


3) GPIO 端口输出速度寄存器 (GPIOx_OSPEEDR) (x = A..I/)

GPIO port output speed register
偏移地址:0x08
复位值:
  ● 0x0000 00C0(端口 B)
  ● 0x0000 0000(其它端口)

4) GPIO 端口上拉/下拉寄存器 (GPIOx_PUPDR) (x = A..I/)

GPIO port pull-up/pull-down register
偏移地址:0x0C
复位值:
  ● 0x6400 0000(端口 A)
  ● 0x0000 0100(端口 B)
  ● 0x0000 0000(其它端口)


5) GPIO 端口输入数据寄存器 (GPIOx_IDR) (x = A..I)

GPIO port input data register
偏移地址:0x10
复位值:0x0000 XXXX(其中 X 表示未定义)

6) GPIO 端口输出数据寄存器 (GPIOx_ODR) (x = A..I)

GPIO port output data register
偏移地址:0x14
复位值:0x0000 0000

7) GPIO 端口置位/复位寄存器 (GPIOx_BSRR) (x = A..I)

GPIO port bit set/reset register
偏移地址:0x18
复位值:0x0000 0000

8) GPIO 端口配置锁定寄存器 (GPIOx_LCKR) (x = A..I)

GPIO port configuration lock register
当正确的写序列应用到第 16 位 (LCKK) 时,此寄存器将用于锁定端口位的配置。位 [15:0] 的 
值用于锁定 GPIO 的配置。在写序列期间,不能更改 LCKR[15:0] 的值。将 LOCK 序列应用 
到某个端口位后,在执行下一次复位之前,将无法对该端口位的值进行修改。

注意: 可使用特定的写序列对 GPIOx_LCKR 寄存器执行写操作。在此写序列期间只允许使用字访问 32 位长)。

每个锁定位冻结一个特定的配置寄存器(控制寄存器和复用功能寄存器)。

偏移地址:0x1C
复位值:0x0000 0000
访问:仅 32 位字,读/写寄存器


9) GPIO 复用功能低位寄存器 (GPIOx_AFRL) (x = A..I)

GPIO alternate function low register
偏移地址:0x20
复位值:0x0000 0000

10) GPIO 复用功能高位寄存器 (GPIOx_AFRH) (x = A..I)

GPIO alternate function high register
偏移地址:0x24
复位值:0x0000 0000

AF0-15到底代表什么意思呢,可见下图

4. 代码示例

1)GPIO配置

对GPIO的配置,其实就是根据寄存器功能列表,对寄存器进行配置。

//GPIO 通用设置
//GPIOx:GPIOA~GPIOI.
//BITx:0X0000~0XFFFF,位设置,每个位代表一个 IO,
//第 0 位代表 Px0,第 1 位代表 Px1,依次类推.比如 0X0101,代表同时设置 Px0 和 Px8.
//MODE:0~3;模式选择,0,输入(系统复位默认状态);1,普通输出;2,复用功能;3,模拟输入.
//OTYPE:0/1;输出类型选择,0,推挽输出;1,开漏输出.
//OSPEED:0~3;输出速度设置,0,2Mhz;1,25Mhz;2,50Mhz;3,100Mh. 
//PUPD:0~3:上下拉设置,0,不带上下拉;1,上拉;2,下拉;3,保留.
//注意:在输入模式(普通输入/模拟输入)下,OTYPE 和 OSPEED 参数无效!!
void GPIO_Set(GPIO_TypeDef* GPIOx, u32 BITx, u32 MODE, u32 OTYPE, u32 OSPEED, u32 PUPD) {
	u32 pinpos=0,pos=0,curpin=0;

	for(pinpos=0;pinpos<16;pinpos++) {
		pos=1<<pinpos; //一个个位检查
		curpin=BITx&pos;//检查引脚是否要设置
		if(curpin==pos) {	//需要设置 
			GPIOx->MODER&=~(3<<(pinpos*2)); //先清除原来的设置
			GPIOx->MODER|=MODE<<(pinpos*2); //设置新的模式

			if((MODE==0X01)||(MODE==0X02)) {  //如果是输出模式/复用功能模式
				GPIOx->OSPEEDR&=~(3<<(pinpos*2)); //清除原来的设置
				GPIOx->OSPEEDR|=(OSPEED<<(pinpos*2));//设置新的速度值 
				GPIOx->OTYPER&=~(1<<pinpos) ; //清除原来的设置
				GPIOx->OTYPER|=OTYPE<<pinpos; //设置新的输出模式
			}

			GPIOx->PUPDR&=~(3<<(pinpos*2)); //先清除原来的设置
			GPIOx->PUPDR|=PUPD<<(pinpos*2); //设置新的上下拉
		}
	}
}

2)GPIO复用

USART的Rx和Tx,是复用了GPIO的引脚实现的,因此此处有必要介绍一一下GPIO引脚复用功能

//GPIO复用设置
//GPIOx:GPIOA~GPIOI.
//BITx:0~15,代表IO引脚编号.
//AFx:0~15,代表AF0~AF15.
//AF0~15设置情况(这里仅是列出常用的,详细的请见407数据手册,56页Table 7):
//AF0:MCO/SWD/SWCLK/RTC   AF1:TIM1/TIM2;            AF2:TIM3~5;               AF3:TIM8~11
//AF4:I2C1~I2C3;          AF5:SPI1/SPI2;            AF6:SPI3;                 AF7:USART1~3;
//AF8:USART4~6;           AF9;CAN1/CAN2/TIM12~14    AF10:USB_OTG/USB_HS       AF11:ETH
//AF12:FSMC/SDIO/OTG/HS   AF13:DCIM                 AF14:                     AF15:EVENTOUT
void GPIO_AF_Set(GPIO_TypeDef* GPIOx,u8 BITx,u8 AFx) {  
	GPIOx->AFR[BITx>>3]&=~(0X0F<<((BITx&0X07)*4));		//复位该bit
	GPIOx->AFR[BITx>>3]|=(u32)AFx<<((BITx&0X07)*4);		//设置该bit的功能
} 
  • BITx>>3:在 MDK 里面,AFRL 和 AFRH 被定义成 AFR[2],其中 AFR[0]代表 AFRL,AFR[1]代表 AFRH。
  • AFx<<((BITx&0X07)*4): 设置AF的复用功能到寄存器

因为GPIO在配置AF时候,分成了两组AFL(GPIO每组的[7..0]) & AFH(GPIO每组的[15..8])
BITx&0X07 : 假设bit为10,那么应该在AFH寄存器中的第3组
x4: 每组由4Bit组成

4. 附录

参考文档

posted @ 2023-01-05 15:33  Jimmy_Nie  阅读(1538)  评论(0编辑  收藏  举报