打印
[应用相关]

STM32实战总结:HAL之GPIO

[复制链接]
218|49
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GPIO概述
一、先认真阅读参考手册中GPIO部分内容



GPIO部分大概有25页,关键内容记录如下:

1、每个GPI/O端口有两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器 (GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。

2、端口可配置四种输入和四种输出:

─ 输入浮空

─ 输入上拉

─ 输入下拉

─ 模拟输入

─ 开漏输出

─ 推挽式输出

─ 推挽式复用功能

─ 开漏复用功能

GPIO八种模式的区别与应用

参考:单片机的GPIO端口的8中工作模式

使用特权

评论回复
沙发
结合国际经验|  楼主 | 2023-12-27 14:52 | 只看该作者
注意事项:

01

在IO口外接按键的情况下,如果按键未按下时是低电平,按下后是高电平,那么,单片机引脚在初始化时,最好设置成下拉,以保证单片机引脚处于按键未触发时的低电平,如果不设置成下拉,那么单片机引脚就会处于悬空状态,导致引脚的电平状态不定,从而影响引脚的功能实现;

02

模拟输入一般只有在ADC引脚时才会使用;

03

配置成输出时,为什么还要配置上拉和下拉?

其实,在思考这个上拉和下拉不必非得跟输入关联到一起,不管是输入还是输出,都有个空闲态,比如输入时按键未按下,或者输出时LED不亮,都有个空闲的状态,我们根据需要设置对应的上下拉即可。

这里附一张M4的GPIO原理图,就将上下拉移到了外面,让输入和输出通道都能用

使用特权

评论回复
板凳
结合国际经验|  楼主 | 2023-12-27 14:52 | 只看该作者
04

配置成输出时,输入功能可以同时使用。即具有双向驱动口的功能。

具体参考:GPIO做输出还能作外部中断输入吗? - 知乎

不论GPIO通用输出还是复用输出,外部管脚的电平都可以连接到内部输入单元,管脚上的电平也可以被内部边沿检测器检测到。也就是说,当它被配置为输出时是具备双向特性的。

当然,一般来讲,如果希望GPIO做为双向驱动口使用时,建议将其配置为OD开漏结合上拉模式。比方在做I2C应用时,将通信GPIO端口配置为开漏模式结合上拉电阻即可进行双向数据通信,无须对通信口的GPIO模式来回切换。

使用特权

评论回复
地板
结合国际经验|  楼主 | 2023-12-27 14:52 | 只看该作者

使用特权

评论回复
5
结合国际经验|  楼主 | 2023-12-27 14:52 | 只看该作者
注意,开漏输出无法直接输出高电平,所以想输出1时,需要设置成上拉,以提供高电平。

3、端口位输出表:

使用特权

评论回复
6
结合国际经验|  楼主 | 2023-12-27 14:53 | 只看该作者
4、必须以字(32位)的方式操作这些外设寄存器。

更多内容详见参考手册。

二、GPIO有哪些变量和函数?

使用特权

评论回复
7
结合国际经验|  楼主 | 2023-12-27 14:53 | 只看该作者
更多内容详见源代码。

三、学会使用这些函数
static void Run(void)
{
    HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
    HAL_Delay(100);
}  
以上代码可以实现LED1的闪烁。

注意这里的名字中的LED1和MX中的标签名是一致的。

使用特权

评论回复
8
结合国际经验|  楼主 | 2023-12-27 14:53 | 只看该作者
GPIO复用和重映射

STM32上有很多I/O口,也有很多的内置外设如I2C、ADC、ISP、USART等,为了节省引出管脚,这些内置外设基本上是与I/O口共用管脚的,也就是I/O管脚的复用功能。

很多复用的I/O引脚可以通过重映射功能从其他的I/O管脚引出,即复用功能的引脚是可通过程序改变的。具体查看技术手册。

使用特权

评论回复
9
结合国际经验|  楼主 | 2023-12-27 14:53 | 只看该作者
数据手册上有说明:

复位后主功能是GPIO,只有启用了相应的外设功能,才会成为相对应的复用功能。

使用特权

评论回复
10
结合国际经验|  楼主 | 2023-12-27 14:54 | 只看该作者
阅读GPIO相关源码
从main函数开始。。。

一开始就是HAL初始化HAL_Init();这个函数是干什么的?在哪定义的?在哪声明的?

注意:在c中,基本上都是c和h文件成双成对的,头文件是在c文件前面被展开的。所以,需要配合头文件和c文件才完整。要看就两个一起看。

使用特权

评论回复
11
结合国际经验|  楼主 | 2023-12-27 14:54 | 只看该作者
main.h

在该头文件中,包含了一个头文件stm32f1xx_hal.h,这个头文件看起来像是总的头文件,因为它的命名中,只有32和hal,没有其他任何外设的信息。

有错误处理函数的声明,另外有个void SystemClock_Config(void);是main的私有函数,所以就没有声明在头文件中,不过,该私有函数并没有加上static来限制其私有性。不加也可以,只要没有声明出去,别的地方调用时就会报错,但是此时可以选择声明出去。而一旦加上了static,就无法声明出去了,一旦声明出去就会报错。

使用特权

评论回复
12
结合国际经验|  楼主 | 2023-12-27 14:54 | 只看该作者
该头文件中的这段代码关注一下,这是main.h中最关键的代码:

/* Private defines -----------------------------------------------------------*/
#define LED1_Pin GPIO_PIN_4
#define LED1_GPIO_Port GPIOE
#define LED2_Pin GPIO_PIN_5
#define LED2_GPIO_Port GPIOE
#define LED3_Pin GPIO_PIN_6
#define LED3_GPIO_Port GPIOE

使用特权

评论回复
13
结合国际经验|  楼主 | 2023-12-27 14:54 | 只看该作者
这里对应的是MX中配置引脚时的标签名,本来我们还要去查看原理图去查看配置的到底是哪个端口,这个端口的哪个引脚,但是,这里自动生成了相应的宏定义,通过这种定义别名的方式,让我们直接面向“对象”编程。用LED1/LED2/LED3相关符号就可以了。

上面宏定义中的GPIO_PIN_4和GPIOE这些名称是啥意思?打开定义和声明查看。

首先,看到这些名称都是大写,猜想可能是一个宏定义。

使用特权

评论回复
14
结合国际经验|  楼主 | 2023-12-27 14:55 | 只看该作者
先打开GPIO_PIN_4的声明/定义(对于宏定义来说,打开声明或者定义都是同一个地方)

跳转到了stm32f1xx_hal_gpio.h文件。

里面对各个引脚进行了编号。

使用特权

评论回复
15
结合国际经验|  楼主 | 2023-12-27 14:55 | 只看该作者
用的是个16位的二进制数,通过最低位到高位依次赋予高电平来选择。

uint16_t是什么意思?

再次跳转定义。

发现无法跳转。说明其既不是宏定义,也不是变量,而是一种c语言的语法。

其实,我知道这是单片机中自定义的一种类型,也就是unsigned short,只不过进行了类型重定义,以简化使用。

怎么找到其源头?

既然能使用,那么肯定有地方进行了类型重定义,要么就在文件上面,要么就在包含的头文件中。

使用特权

评论回复
16
结合国际经验|  楼主 | 2023-12-27 14:55 | 只看该作者
上面没有,那就只能在头文件中。其包含了一个头文件stm32f1xx_hal_def.h
******************************************************************************
  * @file    stm32f1xx_hal_def.h
  * @author  MCD Application Team
  * @brief   This file contains HAL common defines, enumeration, macros and
  *          structures definitions.
  ******************************************************************************

使用特权

评论回复
17
结合国际经验|  楼主 | 2023-12-27 14:55 | 只看该作者
可知该头文件包含了HAL共用的定义、枚举、宏定义以及结构体定义。

但在该头文件中,依然没有找到uint16_t,那就只能继续找其包含的头文件stm32f1xx.h,看名字像一个最顶层的头文件。继续找,还是没找到。

还是没找到,奇了怪了。

那就只能直接搜索了。搜索太多了,不好找。

无意中发现,uint32_t右键能够跳转。。。。跳到了stdint.h文件。

使用特权

评论回复
18
结合国际经验|  楼主 | 2023-12-27 14:55 | 只看该作者
……
/* exact-width unsigned integer types */
typedef unsigned          char uint8_t;
typedef unsigned short     int uint16_t;
typedef unsigned           int uint32_t;
typedef unsigned       __INT64 uint64_t;
……

使用特权

评论回复
19
结合国际经验|  楼主 | 2023-12-27 14:56 | 只看该作者
看其描述:

/** @addtogroup Peripheral_declaration
  * @{
  */

使用特权

评论回复
20
结合国际经验|  楼主 | 2023-12-27 14:56 | 只看该作者
这好像是所有外设的什么声明,具体看:

以GPIOE为例

#define GPIOE               ((GPIO_TypeDef *)GPIOE_BASE)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

569

帖子

1

粉丝