STM32 GPIO操作指南(寄存器级别)

(注:此为乐某学习记录,若有出错的地方欢迎各位指出!)

前言

本人使用的开发板的芯片是STM32H743XIH6,所以外设也是根据此芯片来介绍。

在使用HAL库配置的时候,需要安装STM32CubeMX。此软件可在ST官网下载,剩下的安装步骤比较简单,不会单独出篇进行讲解。

STM32CubeMX下载网址:https://www.st.com/zh/development-tools/stm32cubemx.html

一、什么是GPIO?可以做什么?

GPIO是General Purpose Input/Output的简写,翻译为通用输入/输出。在STM32里是可以对其进行控制或读取的引脚,通俗点讲,可以对它们输出高/低电平或者读取它们的实时电平。

GPIO可以实现跟硬件设备之间的通信(UART、IIC、SPI等),控制硬件设备的工作(LED、蜂鸣器等),读取硬件设备的状态等(中断读取,引脚状态读取等)。

我们知道了GPIO可以做这么多事,但是要怎么去实现呢?这里就提到一个复用的说法,就是将需要用的引脚用复用器去连接到其他的外设,这样的引脚功能就不会有冲突。有的操作就是,复用配置后,先执行这个外设的功能,然后再复用到其他的外设上使用。

我使用的这个芯片一共有11组IO,分别是GPIOA~K。其中GPIOA~J是16个IO口,GPIOK是只有8个IO,大家使用时请仔细阅读数据手册或参考手册。单个IO的称呼,例如GPIOA的PIN0,就可以叫做PA0。

二、GPIO的基本结构

我们使用到的IO的内部结构基本都是这样,对关键器件的解析:

1、保护二极管

为了防止IO引脚接到了一个过高或者过低的电压,当引脚电压高于VDD时,上方的二极管导通;当引脚电压低于VSS时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。 所以,IO是无法直接接到高功率的器件工作的,需要有额外的电路去处理这部分的问题,否则可能会导致芯片的损坏或者无法驱动外接器件的工作。

2、P-MOS管和N-MOS管

由P-MOS管和N-MOS管组成的单元电路使得GPIO具有“推挽输出”和“开漏输出”的模式。推挽即使强高或者强低的输出,开漏只有强低的输出,无法进行强高的操作。

3、开关

将输入的信号转换为0和1的器件。例如,输入的电平为1.5V,但是我的低电平阈值是0-0.4V,高电平是2.8-VDD。那么这个电平,就会被视为浮空状态。输出同理,不会输出阈值之外的电平,输出0的范围就是0-0.4V,输出高就是2.8-VDD。如果看到有VDD_FT,就是兼容5V。

三、不同输入/输出模式

1、五种输入:

(1)浮空输入

此模式下的IO口的电平,由外部的电平信号决定,是不确定的信号,最终会直接进入输入数据寄存器。此模式容易会受到干扰来扰乱电平,通常用于配置USART的RX引脚,如下图所示:

(2)上拉输入

此模式下的IO口电平,若无信号接入(悬空),默认为高电平。若输入高电平,电平状态就会保持高电平;若输入低电平,电平状态就会被拉低为低电平,此上拉为弱上拉。最终会直接进入输入数据寄存器。此模式可用作与一些电平状态为浮空的器件,例如按键。若按键是一端接VSS,一端接IO。没有按下的情况就是浮空的,当按下按键后就是低电平。

(3)下拉输入

此模式下的IO口电平,若无信号接入(悬空),默认为低电平。若输入高电平,电平状态就会被拉高为高电平;若输入低电平,电平状态就会保持低电平,此下拉为弱下拉。最终会直接进入输入数据寄存器。此模式可用作与一些电平状态为浮空的器件,例如按键。若按键是一端接VDD,一端接IO。没有按下的情况就是浮空的,当按下按键后就是高电平。

(4)模拟输入

此模式下的IO,将不再是读取电平状态,获取的是IO口的电压值。最终会输入到外设使用。通常使用到ADC外设,用来读取模拟电压的。例如,读热敏电阻和固定电阻的分压来计算当前温度。

(5)复用输入

此模式下的IO,会复用到单片机的其他外设,最终输入到外设使用。例如,USART的串口接收引脚,SPI的MISO引脚等。

2、四种输出:

(1)推挽输出

此时的IO上的P-MOS管和N-MOS管都进行工作,当我们输出设置"0"时,N-MOS管打开,P-MOS管关闭,输出低电平。当我们输出设置"1"时,P-MOS管打开,N-MOS管关闭,输出高电平。此模式输出的是强电平,是可以驱动一些器件的,带负载能力较强,开关速度高。

此时施密特触发器时开启的,我们也可以读取输出数据寄存器的值,可以看是否设置正确,不过这很少用。同时我们也可以通过输入数据寄存器来读取电平状态,注意!我们的IO电平不一定就是我们想要输出的电平。

(2)开漏输出

此时的IO上的P-MOS管不工作,只有N-MOS管工作。当我们输出设置"0"时,N-MOS管打开,P-MOS管关闭,输出低电平。当我们输出设置"1"时,P-MOS管关闭,N-MOS管关闭,此时的电平状态由外部决定。此模式只可输出强低电平,想输出高电平只能够靠外部提供。

此时施密特触发器时开启的,我们也可以读取输出数据寄存器的值,可以看是否设置正确,不过这很少用。同时我们也可以通过输入数据寄存器来读取电平状态,注意!我们的IO电平不一定就是我们想要输出的电平。

(3)模拟输出

此模式下的IO,将不再是设置电平状态,是设置IO口的电压值。最终会输出到外部使用。通常使用到DAC外设,用来设置模拟电压的。例如,设置电压到电压控制器件工作。

(4)复用输出

此模式下的IO,会复用到单片机的其他外设,输出数据寄存器无法使用。输出的电平状态将会由外设控制。复用推挽输出和复用开漏输出在此方面功能相同。

同时我们也可以通过输入数据寄存器来读取电平状态,注意!我们的IO电平不一定就是我们想要输出的电平。

四、GPIO的寄存器介绍

这里会拿配置IO的基本输入输出来介绍寄存器。我的开发板上的LED灯连接到PB0,按键连接到了PA0。前面介绍了不同的输入输出模式的区别,所以PB0需要配置成输出,PA0需要配置成输入。

1、端口模式寄存器

在每个位的介绍里,并没有看到具体的输入输出介绍,所以PB0配置为通用输出模式(01),PA0配置成输入模式(00)。

//PB0的模式配置
GPIOB->MODER &= ~(0x03 << 0);    //先对需要配置的为作清零
GPIOB->MODER |=  (0x01 << 0);
//按键1的模式配置
GPIOA->MODER &= ~(0x03 << 0);    //先对需要配置的为作清零
GPIOA->MODER |=  (0x00 << 0);

2、端口输出类型寄存器

只有PB0是配置为输出,所以PA0不需要配置此寄存器。因为是驱动LED灯亮,所以需要配置为推挽输出(0),使用开漏输出只有强低。

//PB0的输出类型配置
GPIOB->OTYPER &= ~(0x01 << 0);    //先对需要配置的为作清零
GPIOB->OTYPER |=  (0x00 << 0);

3、端口输出速度寄存器

只有PB0是配置为输出,所以PA0不需要配置此寄存器。速度多少都行,这里没有什么讲究,我设置为超高速。

//PB0的输出速度配置
GPIOB->OSPEEDR &= ~(0x03 << 0);    //先对需要配置的为作清零
GPIOB->OSPEEDR |=  (0x03 << 0);

4、端口上拉/下拉寄存器

PB0是做强高或强低输出的,没有必要做上拉下拉处理。PA0的外接了下拉电阻,所以这里也没必要做上下拉处理。

//PB0的上下拉配置
GPIOB->PUPDR &= ~(0x03 << 0);    //先对需要配置的为作清零
GPIOB->PUPDR |=  (0x00 << 0);
//PA0的上下拉配置
GPIOA->PUPDR &= ~(0x03 << 0);    //先对需要配置的为作清零
GPIOA->PUPDR |=  (0x00 << 0);

5、端口输入数据寄存器

这里会在获取按键引脚状态的时候使用到,我使用了宏定义来代替这操作。

#define KEY1_STATE GPIOA->IDR & (0x01 << 0)

6、端口输出数据寄存器

此寄存器在控制LED的输出操作时使用,统一写成宏定义的写法。我的开发板LED是低电平点亮,所以将第0位置1熄灭LED,置0点亮LED


#define LED_ON  GPIOB->ODR &= ~(0x01 << 0);
#define LED_OFF GPIOB->ODR |= (0x01 << 0);

7、端口复位/置位寄存器

这个寄存器的功能和输出寄存器的差不多,就是操作有点差别。在0-15位置1,就会把输出寄存器的对应位置1。在16-31位置一,就会把输出寄存器的对应位置0,就是16位对应0位,31位对应15位。

#define LED_ON  GPIOB->BSRR |= (0x01 << 16);
#define LED_OFF GPIOB->BSRR |= (0x01 << 0);

8、端口配置锁定寄存器

此寄存器较为少用, 简要来说,就是用来锁定GPIO的配置的,需要按照上面的解锁方式对第16位操作,将GPIO进行解锁。然后给16位置0,再给你想要锁定的端口置1即可。有兴趣可以去研究研究。

9、复用功能寄存器

这个寄存器的作用,是引脚用于外设时使用的。可以将引脚复用到其他的外设,其中的AFx就是想要复用的外设,一个引脚可能有好几种外设可以复用。后面写到其他外设的时候会使用这个寄存器,所以这里不多表述。

五、GPIO的配置方法

1、寄存器配置

//GPIOA和GPIOB的时钟开启
RCC->AHB4ENR |= (0x03 << 0);

//PB0的模式配置
GPIOB->MODER &= ~(0x03 << 0);
GPIOB->MODER |=  (0x01 << 0);

//PB0的输出模式配置
GPIOB->OTYPER &= ~(0x01 << 0);
GPIOB->OTYPER |=  (0x00 << 0);

//PB0的输出速度配置
GPIOB->OSPEEDR &= ~(0x03 << 0);
GPIOB->OSPEEDR |=  (0x03 << 0);

//PB0的上下拉配置
GPIOB->PUPDR &= ~(0x03 << 0);
GPIOB->PUPDR |=  (0x00 << 0);

//PA0的模式配置
GPIOA->MODER &= ~(0x03 << 0);
GPIOA->MODER |=  (0x00 << 0);

//PA0的上下拉配置
GPIOA->PUPDR &= ~(0x03 << 0);
GPIOA->PUPDR |=  (0x00 << 0);

2、HAL库配置

1、打开STM32CubeMX,点击这里

2、搜索到自己的芯片信号后,双击点进去

3、这就是默认的界面

4、选择使用的引脚和需要配置的类型

5、选择好之后,点击右边的这部分,进行引脚的具体配置。

6、配置系统时钟,这里我使用的内部高速时钟,直接在这里输入64,然后一直点击确定,然后就会自动帮忙配置好。

7、按下面的步骤,选择好项目名称和地址。

8、这里会创建一个文件夹,是专门做外设的初始化的,我比较建议勾上。

9、点击生成代码,然后就配置好了。

10、这里就是我们使用STM32CubeMX配置的GPIO方式,在MX_GPIO_Init函数里面,就是具体的配置操作,这里的操作和标准库的很相似。

六、总结

此篇对STM的GPIO外设进行了讲解,介绍了GPIO的基本结构,不同的输入输出模式,以及寄存器的介绍。学到这里,应该就能做出,通过按键控制LED灯的亮灭这种操作了。

HAL库的操作介绍比较简单,基本上只要学习了标准库就会HAL库了,而学了寄存器后,就能大致看懂库函数里面都做了什么,因为库函数的本质也就是操作寄存器。库函数的操作呢,多玩玩基本上就熟悉了,大部分的功能都有函数实现,除非想要做出想要的逻辑操作,所以就不再过多的介绍库函数。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 GPIO操作指南(寄存器级别)

发表评论