一.GPIO的寄存器

32位配置寄存器:GPIOx_CRL,GPIOx_CRH

32位数据寄存器:GPIOx_IDR,GPIOx_ODR

32位置位/复位寄存器:GPIOx_BSRR

16位复位寄存器:GPIOx_BRR

32位锁定寄存器:GPIOx_LCKR

 

gpioset寄存器 gpio寄存器配置_gpioset寄存器

 

 

 

 

GPIOx_CRL :端口配置低寄存器 (控制P0--P7端口)

一个IO位占4个位(4*8=32)P0--P7刚好32位,例如:P0端口:0-1控制输入模式或者输出模式及输出速度,2-3控制输入模式或者输出模式的具体工作方式

 

gpioset寄存器 gpio寄存器配置_gpioset寄存器_02

GPIOx_CRH:端口配置高寄存器 (控制P8--P15端口)

一个IO位占4个位(4*8=32)P8--P15刚好32位,例如:P8端口:0-1控制输入模式或者输出模式及输出速度,2-3控制输入模式或者输出模式的具体工作方式

gpioset寄存器 gpio寄存器配置_gpioset寄存器_03

GPIOx_IDR:端口输入寄存器 

一个位控制一个IO口,0--15对应P0--P15

(注意:IDR寄存器低16位,每个位控制该组IO的一个IO口。对应的是IO口的输入电平)

gpioset寄存器 gpio寄存器配置_数据寄存器_04

 

GPIOx_ODR:端口输出寄存器

一个位控制一个IO口,0--15对应P0--P15

(注意:ODR寄存器跟IDR寄存器相反,是控制IO口输出。低16位每个位控制一个IO口的输出电平的高低。)

gpioset寄存器 gpio寄存器配置_数据寄存器_05

输入模式的上下拉输入到底是上拉还是下拉由端口输出寄存器ODR决定。在输入模式时,可设置ODR寄存器的第一位来决定上拉还是下拉

 

gpioset寄存器 gpio寄存器配置_gpioset寄存器_06

GPIOx_BSRR:端口位设置/清除寄存器

低16位(0--15)是置位,当对应位为1时对应端口置1,对应位为0时对应端口置不受影响

高16位(16--31)是复位,当对应位为1时对应端口置0,对应位为0时对应端口置不受影响

高低位同时作用时,则只有低16位起作用!

gpioset寄存器 gpio寄存器配置_gpioset寄存器_07

GPIOx_BRR :端口位清除寄存器

低16位对应16个端口,作用和GPIOx_BSRR的高16位一样,都是复位清除功能

低16位(0--15)是复位,当对应位为1时对应端口置0,对应位为0时对应端口置不受影响

gpioset寄存器 gpio寄存器配置_寄存器_08

 

 

 GPIOx_LCKR:端口配置锁存寄存器

 

 

 

 

二.GPIO的工作模式

 

根据数据手册中列出的每个I/O端口的特定硬件特征, GPIO端口的每个位可以由软件分别配置成多种模式。

4种输入模式: 输入浮空     

                        输入上拉         

                        输入下拉       

                        模拟输入

4种输出模式: 开漏输出   

                        开漏复用功能   

                        推挽式输出   

                        推挽式复用功能

 

1.浮空输入GPIO_IN_FLOATING ——浮空输入,可以做按键识别,IO状态不确定,完全由外部输入决定

施密特触发器是开启的,IO口的状态可以直接送到输入寄存器中,CPU可以直接读取输入寄存器。

电平进入后,不经过上下拉,在触发施密特触发器后,进入输入数据寄存器,最后由CPU读取。
浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定(输入达到条件就触发),如果在该引脚悬空的情况下,读取该端口的电平是不确定的。

       

gpioset寄存器 gpio寄存器配置_寄存器_09

 

2.输入上拉GPIO_IPU——IO内部上拉电阻输入

 与前面浮空输入模式相比,仅仅在数据通道的上部,接入一个上拉电阻,根据STM32的数据手册,这个上拉电阻阻值介于30K~50K。同样的,CPU可以随时在输入数据寄存器的另一端,读取IO端口的电平状态。

原本需要低电平触发,有上拉电阻存在,使得端口为高电平,达到抗干扰作用,只接受低电平!

         

gpioset寄存器 gpio寄存器配置_寄存器_10

 

3.输入下拉GPIO_IPD—— IO内部下拉电阻输入

 与前面浮空输入模式相比,仅仅在数据通道的上部,接入一个下拉电阻,根据STM32的数据手册,这个下拉电阻阻值介于30K~50K。同样的,CPU可以随时在输入数据寄存器的另一端,读取IO端口的电平状态。

原本需要高电平触发,有下拉电阻存在,使得端口为低电平,达到抗干扰作用,只接受高电平!

         

gpioset寄存器 gpio寄存器配置_寄存器_11

 

4.模拟输入GPIO_AIN ——应用ADC模拟输入,或者低功耗下省电

施密特触发器是关闭的,信号直接到ADC输入;这里我们能看到所有的上拉、下拉电阻和施密特触发器,均处于断开状态,因此输入数据寄存器将不能反映端口上的电平状态,也就是说模拟输入模式下CPU不能在数据寄存器上读到有效的数据

         

gpioset寄存器 gpio寄存器配置_gpioset寄存器_12

 

 

 

1.开漏输出GPIO_OUT_OD ----开漏模式时,只有 N-MOS 管工作,输出数 据 寄 存 器 可 控 制 I/O 输 出 高 阻 态 或 低 电 平 。

如果CPU写入的是逻辑1,则编号3的N-MOS管将处于关闭状态,此时IO端口的电平将由外部的上拉电阻决定;如果CPU写入的是逻辑0,则编号3的N-MOS管将处于开启状态,此时IO端口的电平被编号3的N-MOS管拉到了VSS的零电位。

      在上图的上半部,施密特触发器处于开启状态,这意味着CPU可以在“输入数据寄存器”的另一端,随时监控IO端口的状态;通过这个特性还实现了虚拟的IO端口双向通信只要CPU输出逻辑1,由于编号3的N-MOS管处于关闭状态,IO端口的电平将完全由外部电路决定,因此,CPU可以在“输入数据寄存器”读到外部电路的信号,而不是它自己输出的逻辑1。

       GPIO口的输出模式下,有3种输出速度可选:2MHz、10MHz和50MHz。这个速度是指GPIO口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在IO口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能。当然如果要输出较高的频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。

         

gpioset寄存器 gpio寄存器配置_数据寄存器_13

2.推挽式输出GPIO_OUT_PP ——IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的

在输出模式中,推挽模式时双 MOS 管以推挽方式工作,输出数据寄存器GPIOx_ODR 可控制 I/O 输出高低电平。

gpioset寄存器 gpio寄存器配置_复用_14

 

3.推挽式复用功能GPIO_AF_PP ——片内外设功能(I2C的SCL,SDA)

复用功能模式中,输出使能,输出速度可配置,可工作在推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。 

gpioset寄存器 gpio寄存器配置_寄存器_15

 

 

4.开漏复用功能GPIO_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)

复用功能模式中,输出使能,输出速度可配置,可工作在开漏模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但般直接用外设的寄存器来获取该数据信号。 

gpioset寄存器 gpio寄存器配置_数据寄存器_16

 

GPIO整理后可分为三类:

1. 输入模式(模拟/浮空/上拉/下拉):在输入模式时,施密特触发器打开,输出被禁止,可通过输入数据寄存器 GPIOx_IDR读取 I/O 状态。其中输入模式,可设置为上拉、下拉、浮空和模拟输入四种。上拉和下拉输入很好理解,默认的电平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外部的输入决定,一般接按键的时候用的是浮空输入。模拟输入则用于 ADC 采集。

2. 输出模式(推挽/开漏):在输出模式中,推挽模式时双 MOS 管以轮流方式工作,输出数据寄存器GPIOx_ODR可控制 I/O 输出高低电平。开漏模式时,只有 N-MOS 管工作,输出数据寄存器可控制I/O输出高阻态或低电平。输出速度可配置,有 2MHz\10MHz\50MHz 的选项。此处的输出速度即 I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。
在输出模式时施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR可读取 I/O 的实际状态。

3.复用功能(推挽/开漏):复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。

 

应用场合

 ①上拉输入、下拉输入可以用来检测外部信号,例如按键等。

 ②浮空输入模式,由于输入阻抗较大,一般把这种模式用于标准通信协议的I2C、USART的接收端。

普通推挽输出模式一般应用在输出电平为0和3.3V的场合<。而普通开漏输出模式一般应用在电平不匹配的场合,如需要输出5V的高电平,就需要在外部一个上拉电阻。电源为5V,把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5V电平。

④对于相应的复用模式,复用输出来源片上外设,则是根据GPIO的复用功能来选择,如GPIO的引脚用作串口的输出(USART/SPI/CAN),则使用复用推挽输出模式。如果用在I2C、SMBUS这些需要线与功能的复用场合,就使用复用开漏模式。


每个I/O端口位可以自由编程,然而I/0端口寄存器必须按32位字被访问(不允许半字或字节访问)。GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器的读/更改的独立访问;这样,在读和更改访问之间产生IRQ时不会发生危险。下图给出了一个I/O端口位的基本结构。

 

通常有5种方式使用某个引脚功能,它们的配置方式如下:
      1、作为普通GPIO输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时不要使能该引脚对应的所有复用功能模块。
      2、作为普通GPIO输出:根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复用功能模块。
      3、作为普通模拟输入:配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
      4、作为内置外设的输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时使能该引脚对应的某个复用功能模块。
      5、作为内置外设的输出:根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所有复用功能模块。

 

 

 

三.GPIO的常用函数

1.初始化函数

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);        //初始化(端口引脚,工作模式,传输速度)

//初始化PB5为输出口.并使能这个端口的时钟            
//LED IO初始化
void LED_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
     
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能PB端口时钟
    
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;              //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);                 //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOB,GPIO_Pin_5);                        //PB.5 输出高

}

 

 

 

2.读取输入电平函数

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);       //读取某个位的输入电平(GPIOx,GPIO_Pin)

GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);      //读取PA1的输入电平

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);                                         //读取某个端口16位的输入数据(GPIOx)

GPIO_ReadInputData(GPIOA);                    //读取PA端口16位的输入数据

3.读取输出电平函数

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);     //读取某个位的输出电平(GPIOx,GPIO_Pin)

GPIO_ReadOutputDataBit( GPIOA, GPIO_Pin_1);     //读取PA1的输出电平

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);                                        //读取某个端口16位的输出数据(GPIOx)

GPIO_ReadOutputData(GPIOA);                    //读取PA端口16位的输出数据

 

4.设置输出电平函数

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);                               //置位(GPIOx,GPIO_Pin)

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);                           //复位(GPIOx,GPIO_Pin)

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);    //对某个位写(GPIOx,GPIO_Pin,0或1)

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);                                       //对某个端口16位写(GPIOx,0或1)