文章内容偏向HAL库的移植和使用,以个人观点及了解为主,若与事实不符,则以www.st.com、www.stmcu.org.cn等平台为准。
使用的软件:
VSCode(1.36版,带C/C++ IntelliSense插件)
Keil MDK(5.26版)
芯片:STM32H743ZIT6(Nucleo-H743平台,B-01版)
所使用的库:STM32Cube_FW_H7_V1.3.0,下载地址:https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32cube-mcu-mpu-packages/stm32cubeh7.html
参考资料:STM32H743xI参考手册、数据手册、部分HAL库文件、NUCLEO-H743原理图(B-01)
程序下载:https://pan.baidu.com/s/124IrMzjdF15hEtk_hhi4iA

计算机的组成部分通常分为5类:运算器、控制器、储存器、输入设备、输出设备。对于STM32H743ZIT6来说,最基本的输入/输出设备就是IO口(GPIO,General-Purpose Input/Output,通用输入/输出口)。所以就以GPIO的操作作为第一个实验。
关于GPIO的内容,在参考手册的第10章。
STM32H743ZIT6共有11组GPIO,即GPIOA-GPIOK,除GPIOK只有PK0-PK7这8个引脚外,其他各组GPIO都有16个引脚Pn0-Pn15(n=A,B......J)。每一个IO口都可以独立地配置、操作。

GPIO的工作模式

GPIO的工作模式
如上图所示,GPIO有3种输入通用模式、1种模拟模式、2种通用输出模式和2种复用输出模式,从上到下依次为:
1、浮动输入模式
2、上拉输入模式
3、下拉输入模式
4、模拟输入模式
5、带上拉/下拉功能的开漏输出模式
6、带上拉/下拉功能的推挽输出模式
7、带上拉/下拉功能的开漏复用模式
8、带上拉/下拉功能的推挽复用模式
在这8种功能中,功能1-3类似,差别就是启用或禁用上拉/下拉电阻;功能4使用模拟信号,而且既可以作为输出口,又可以作输入口;功能5-8都是输出功能,但功能5、6可以直接用软件修改IO口的电平状态,而功能7、8的电平状态由硬件改变。
其实7、8的复用输出功能也可以归为输出功能,但是与通用输出功能不同的是,在复用模式下,有专门的驱动电路来驱动IO口,IO的电平状态不再受到GPIO相关寄存器的控制,其控制权将交给驱动IO口的外设,如UART、I2C等。不过GPIO的工作模式却没有复用输入模式,这是因为输入信号不需要专用的电路,只需要把信号直接送给对应的外设就可以了。但如果某一个IO口启用了复用功能(不论输入还是输出),虽然HAL库提供的GPIO读函数依然有效,但禁止使用HAL库提供的写函数修改IO口电平状态,同时也不建议读取IO口电平状态。

GPIO的结构:

GPIO的结构
GPIO的结构大同小异。就输入电压而言,可以分为两类,一类是支持5V容忍度的IO,一类是不支持5V容忍度的IO。所谓的5V容忍度,指的是某个IO口既可以使用3.3V高电平,又可以使用5V高电平且不会损坏,但要串接保护电阻。不过还是参考后者,即不支持5V容忍度的IO。
不管何种模式,图片右边的两个保护二极管都不会被禁用,也不会影响输入的电平,所以不做讨论。
对于3种输入模式,右边的上拉/下拉电阻可以根据选择使用,蓝色框为输入驱动器,实际上这部分主要是一个施密特触发器。在输入模式下,从IO输入的信号会先向模拟部分(橙色)提供一路信号(不管用不用,都会提供,由相应的模拟外设选择输入的信号,下同),之后经过施密特触发器,向复用输入功能部分(红色)提供一路信号,同时也向GPIO的输入数据寄存器(紫色)提供一路信号,作为从外部读取的电平。
在模拟功能下,除了橙色部分的模拟信号输入/输出外,其他部分都无效或者禁止使用。
如果启用了输出功能,那么就有两路可用的输出驱动信号,一路是来自GPIO输出数据寄存器的驱动信号(来自紫色的框中),另一路是复用功能驱动信号(来自左下黄色框中),具体选用哪一路信号,由输出驱动电路(绿色框)种的选择器确定,并将这一路信号送给输出控制部分,用来产生MOS管的驱动信号,通过MOS管的关断和导通,实现电平的变换。
如果和功能5-8关联起来的话,功能5、6使用的驱动信号由GPIO输出数据寄存器提供,功能7、8使用的驱动信号由复用功能驱动信号提供。在开漏模式下,P-MOS始终关闭,通过启用上拉电阻或者外接上拉电阻的形式来产生高电平,如果没有有效的上拉电阻,那么IO口的电平状态是不确定的。如果是推挽模式,那么P-MOS和N-MOS会交替导通和关断,保证高电平足够高、低电平足够低。

GPIO的复用:
STM32H743的外设非常多,其中某一些外设需要使用GPIO来输入、输出信号,此时就要把某些GPIO的控制权交给外设,由外设管理IO的电平状态。此时GPIO不能再作为通用IO使用,而是工作于由用户选定的功能,这种工作状态就叫做GPIO的复用。GPIO有16种复用模式,从AF0-AF15,详细的复用功能表再STM32H743xI的数据手册中,位于第五章靠后的部分。

GPIOA的复用功能
虽然一个引脚支持数种复用功能,但同一时刻,只能选择一种复用功能。
另外,所有GPIO都可以挂接在EXTI上,实现外部的上升沿、下降沿和跳变沿中断。关于EXTI的内容,目前不会使用太多,所以就先不细讲。

现在,来编写一个程序,使用1个按键和3个LED,当按键按下时,LED的状态随之改变。也就是这个视频实现的效果。

00:10
【STM32H743】第一个实验当然是玩灯了
2951观看 0弹幕

首先,来分析需求。
NUCLEO-H743 B-01(B-01是版本号)开发板带有3个LED和1个用户按键。为了使用更多的硬件,也就是使用EXTI,所以把与按键连接的GPIO配置为中断模式,进入中断后按照一定的顺序修改LED状态,如果多次按下按键则循环给定的状态。LED的状态分4种:红、蓝、绿、全亮。如果LED已经是全亮的状态,那么下一个状态时红色,并开始循环。而按键是以按下触发中断的。

因为ST官网提供的NUCLEO-H743原理图只有C-01版,所以原理图就参考NUCLEO-F767开发板。

红色LED阴极接地,阳极通过保护电阻连接PB14,蓝色LED也类似,连接在PB7,按键连接在PC13,按下按键产生高电平,释放按键产生低电平。

LED_G原理图
而绿色LED配备了由运放组成的专用驱动电路,这种连接方式,会将同相端输入的直接反应到输出端。输入的信号可以又两路:PB0和PA5,这么做也许是考虑到了PA5带有DAC功能(DAC1_OUT2),但输出的电流不足以驱动LED,而设计的驱动电路。对于PB0来说,因为信号是同相的,所以也是高电平点亮LED。
所以硬件信息就是:
LED_R PB14 高电平点亮
LED_B PB7 高电平点亮
LED_G PB0 高电平点亮
KEY PC13 上升沿中断

拷贝一份工程模板,将文件夹命名为"STM32H743_LED按键",在Driver/src下新建LED.c、KEY.c,在Driver/inc下新建LED.h、KEY.h。

因为是已经写好的程序,所以就不重新编写了。
先同时打开KEY.h和LED.h。

动图
打开两个文件
现在来看一看代码

KEY.h与LED.h
每个文件的#ifndef-#define-#endif结构已经是惯例了,用于防止头文件重复编译。使用了HAL库的工程,用户头文件只需要添加stm32h7xx_hal.h即可,它通过包含stm32h7xx_hal_conf.h间接包含了所有已启用外设的头文件和stm32h7xx.h,不必再次包含每个外设的头文件。
在KEY.h文件中先是用两个宏定义,定义了按键的GPIO引脚(6-7行),PC13,又声明了一个按键初始化函数(9行)。
LED.h中也是类似,定义了每个LED的GPIO引脚,声明了三个函数,分别用于初始化LED(LED_Init())、点亮LED(LED_On())、熄灭LED(LED_Off())。另外6-12行定义了一个枚举类型LEDSelection_TypeDef,这个类型用于选择一个LED。

KEY.c中的程序
现在来看看KEY.c文件。
这个文件中的KEY_Init()函数大致分为3部分:开启GPIO时钟(7)、初始化GPIO引脚(9-12)、配置相应的中断(15-16).
在HAL库中,与RCC外设有关的内容全部都在stm32h7xx_hal_rcc.c/.h、stm32h7xx_hal_rcc_ex.c/.h中,__HAL_RCC_GPIOC_CLK_ENABLE()是一条位于stm32h7xx_hal_rcc.h中第938行的宏。stm32h7xx_hal_rcc.h中还有其他类似的宏,用于外设的时钟管理,可以在启用正则表达式搜索功能后用__HAL_RCC_.*_CLK_ENABLE()搜索到,对应的DISABLE宏可以用__HAL_RCC_.*_CLK_DISABLE()搜索,也可以使用__HAL_RCC.*ABLE()匹配所有项.

动图
HAL库提供的外设时钟使能宏
GPIO_InitStructure的数据类型是GPIO_InitTypeDef,它的定义在stm32h7xx_hal_gpio.h中

GPIO_InitTypeDef的定义
这个结构中有5个成员。
Pin:指定要配置的引脚,可单选或多选
Mode:指定要配置的IO模式
Pull:指定上拉/下拉电阻配置
Speed:指定输出速度(仅输出模式、复用模式有效)
Alternate:指定引脚的复用功能
其中,前4个成员的参数定义在stm32h7xx_hal_gpio.h中,复用功能参数定义在stm32h7xx_hal_gpio_ex.h中,因为还没有用到复用模式,所以就暂不讨论。上一张图使用了正则表达式搜索,搜索结果的大致位置在右侧预览窗口中有显示。如果不知道该怎么选,可以直接查看对应的代码,比如IO模式:

GPIO_InitTypeDef::Mode的各个参数
与上升沿中断对应的参数是143行的GPIO_MODE_IT_RISING。
KEY.c第9行的参数来自KEY.h中第7行的定义,这个定义是stm32h7xx_hal_gpio.h中参数的二次定义,主要目的是为了让程序更加灵活,KEY.c第12行的GPIOPort_KEY的用法和目的也是类似的。KEY.c第11行,启用下拉电阻,保证按键IO空闲时为低电平,按键按下有产生上升沿。
KEY.c的15、16行用于配置NVIC(嵌套向量中断控制器),15行用于配置NVIC的对应优先级,16行用于开启中断。NVIC是Cortex-M7内核的部分,所以暂不深入了解。经过HAL库的配置后,NVIC拥有4位抢占优先级和0位响应优先级(优先级分组4),但因为目前要编写的程序只有一个中断,所以这一部分可以随意配置。
在这个程序中,按键中断时通过EXTI来实现的,PC13占用了EXTI13,所以在配置中断优先级时,中断号参数为EXTI15_10_IRQn。关于中断号(IRQn)的全部定义,可以在stm32h743xx.h中找到。

stm32h743xx.h中定义的中断号
在LED.c中的LED_Init()函数的作用和代码与KEY_Init()类似,只不过没有中断优先级配置而已。

LED.c中的程序
两个LED操作的函数结构相同,都是利用switch-case结构选择对应的LED灯,唯一的区别就是点亮灯需要输出高电平,IO状态为SET;熄灭灯需要低电平,IO状态为RESET。

LED_On()和LED_Off()的参数s的类型就是在LED.h中定义的LEDSelection_TypeDef,用来选择LED灯,除单独选择红、绿、蓝之外,还有一个全部选择。

Driver文件夹下的4个文件编写好之后,要在stm32h7xx_it.c、main.c/.h中编写一些代码。首先是stm32h7xx_it.c,要在其中编写EXTI的中断响应程序,这个程序比较简单,只有4行(177-180)

其中只是调用了HAL_GPIO_EXTI_IRQHandler()函数,传递的参数为产生外部中断的引脚号,也就是GPIO_InitTypeDef::Pin的值。这个函数是由stm32h7xx_hal_gpio.c/.h提供的,在右侧窗口中可以看到函数的源码,先检测并复位中断标志,再调用HAL_GPIO_EXTI_Callback()函数,即产生回调。关于回调的内容,将在下一篇文件讲到,现在只需要知道,只要产生有效的中断,HAL_GPIO_EXTI_Callback会被HAL库调用即可。
之后,要在main.h中包含KEY.h和LED.h(同时要把对应的.c文件在MDK中添加到Driver组中,不然会报错)。

main.h中的代码
在main.c中,要通过调用LED.c和KEY.c中的函数达到预期效果,所以编写的程序比较多。

main.c中的部分代码
在main.c中,14、15、17行是添加的部分,注意要添加在10-12行的三个函数之后。前两行用于初始化按键及LED,最后一行是让程序进入一个初始状态,也就是上电后,红灯会立刻亮。之后编写这样一段程序:

还是main.c中的代码
这一部分负责响应回调(或者说响应中断),函数头部分就是stm32h7xx_hal_gpio.c中521行的函数头,不过要去掉__weak修饰符(下一篇文章讲)。这样相当于重写stm32h7xx_hal_gpio.c中的HAL_GPIO_EXTI_Callback()函数,当HAL_GPIO_EXTI_IRQHandler()调用HAL_GPIO_EXTI_Callback()时,会调用main.c中的函数,而不是stm32h7xx_hal_gpio.c中的。
第26行定义了一个静态变量LEDSelection,初值选择蓝色LED,之后用一个switch-case来选择按键按下这种情况(其实不用也可以,但如果允许多个引脚产生中断的话,就需要了)。第32-36行是实现LED状态改变的部分,先关闭全部LED(32行),在开启选中的LED(33行),最后选择下一个LED状态(35-36行)。其中35-36行选择不同LED状态的原理就是利用LEDSelection是枚举型变量,对其加一就会变成下一个成员的值,在用一个if作溢出判断即可。
上一篇:STM32 HAL库 模拟SPI驱动 DAC8564
下一篇:STM32CubeIDE嵌入式开发入门到入坟-软件篇-2、新建工程与GPIO(IO)口配置
推荐阅读最新更新时间:2026-03-20 10:27
- 使用 ON Semiconductor 的 FAN2518S 的参考设计
- LTC1530S8、3.3V/3A 稳压器
- 使用 ON Semiconductor 的 ADP3167 的参考设计
- 使用 Analog Devices 的 LT3420EDD 的参考设计
- 基于Kinetis® M的低成本单相电表参考设计
- LTC3708、具有上升/下降轨跟踪功能的 2.5V/15A 和 1.2V/15A 稳压器
- NXQ1TXH5插件板
- 应变仪仪表放大器
- WRL-13287,基于 ESP8266 802.11 无线局域网的 SparkFun Wi-Fi Shield
- 4.1W、3-LED 通用 LED 照明驱动器



stm32驱动屏IC rm68042
英飞凌PSoC 6 电位器控制LED闪烁状态并水墨屏显示——源码
非常经典的关于LLC的杨波博士论文
OP413EY
XC6406PP60DL






京公网安备 11010802033920号