基于HAL库GPIO配置实验

1.学习目标 

2.技能目标 

3.素养目标 

任务分解 

任务一 通用型LED驱动控制 

基础知识 

  1. HAL库基本知识 
  2. 主控MCU基本知识 
  3. GPIO硬件基本知识 
  4. GPIO编程基本知识 
  5. GPIO外设配置基本知识 

22技能训练

  1. 任务目标 
  2. 任务流程
  3. 任务实施 

任务二 中断型LED驱动控制

基础知识

  1. 中断基本知识 
  2. NVIC中断基本知识 
  3. NVIC硬件基本知识 
  4. NVIC编程基本知识 
  5. 工具配置基本知识 

技能训练 

  1. 任务目标 
  2. 任务流程
  3. 任务实施 

项目2  基于HAL库GPIO配置实验

 本章导读

本章作为鲲鹏云服务技术的第一单元,以概念类介绍和技术的基本解析作为核心内容。本章主要将会介绍鲲鹏体系架构和华为云的入门基础,其中鲲鹏体系架构主要涉及鲲鹏计算产业和鲲鹏计算生态的概念,并且对计算、产业、生态等相关概念进行解释,同时对市场需求以及当前时代的技术状态进行简介。

1. 学习目标

(1)掌握STM32L431VCT6 MCU的基本概念、内部结构、外部引脚

(2)掌握STM32L431VCT6 MCU的I/O外设、GPIO输出模式配置

(3)掌握STM32L431VCT6 MCU的中断及处理等工作原理

2. 技能目标

(1)熟练使用Keil软件编辑、编译程序

(2)熟练使用STM32CubeMX软件工程参数配置

(3)熟练使用STM32 ST-LINK Utility软件烧录程序

(4)掌握STM32CubeMX软件时钟系统的配置方法

(5)掌握STM32CubeMX软件工程参数配置的技巧

3. 素养目标

(1)初步掌握工程名命名 及项目文件管理方法

(2)逐步养成与项目组成员之间的沟通交流、团结互助的学习习惯

 任务分解

本单元旨在让读者掌握GPIO操作,主要讲述基于HAL库函数实现GPIO操作,控制LED交替闪烁,本单元共两个任务。任务分解具体表如表2-1所示。

表2-1  章节2任务分解

任务名称

任务目标

安排课时

任务1.1 通用型LED驱动控制

能够独立完成GPIO配置并实现LED交替闪烁

2

任务1.2 中断型LED驱动控制

能够独立完成中断配置并实现键控LED交替闪烁

2

总计

4

任务一  通用型LED驱动控制

 基础知识

1. HAL库基本知识

HAL (Hardware Abstraction Layer) 是意法半导体公司(ST公司)推出的STM32Cube软件包中提供的一种硬件抽象层,用于简化STM32微控制器的编程。通过HAL库,开发者可以更轻松地访问微控制器的硬件资源,而不需要直接处理底层寄存器级别的操作。

HAL库提供了API函数接口,用于配置和控制STM32微控制器的各种功能,如GPIO、定时器、串口通信、IIC、SPI总线通信等。开发者可以使用这些API函数来编写相对独立于具体硬件的代码,从而实现更好的可移植性和易维护性。

意法半导体公司为了方便用户开发 STM32芯片开发提供了三种库,它们分别是LL库、标准外设库以及HAL库。SPL库STMicroelectronics 最早提供的库,提供了对 STM32 系列微控制器的底层驱动支持,包括对 GPIO、定时器、串口、总线、USB等外设的控制。SPL 是基于寄存器级编程的,需要开发者直接操作寄存器来控制硬件,操作难读系数较高。HAL库是一种抽象层库,提供了更高级别的 API 接口,简化了对 STM32 外设的配置和控制。HAL 提供了一套易于使用的函数接口,使开发者能够更快速地开发应用程序。LL库是STMicroelectronics提供的一种低层次的库,它位于标准外设库(SPL)和HAL之间。LL库提供了对STM32外设的低级别访问接口,使开发者可以更直接地控制硬件,同时提供了一些抽象层次,使代码更易于移植和维护

表2-2  库开发方式优劣性比较

序号

库名称

功能特点

1

SPL库

标准外设库(Standard Peripheral Libraries),仅支持主流MCU系列,如:F0、F1、F3、F2、F4、L1,目前团队已停止维护

2

LL库

底层库(Low Layer),与全系列MCU兼容,与HAL库捆绑使用,具有轻量级、效率高但是复杂外设不兼容的特点

3

HAL库

硬件抽象层库(Hardware Abstraction Layer),支持全系列MCU,目前ST公司主推的库,具有良好的兼容性、可移植性高、效率偏低的特点

HAL库的文件构成包括头文件、源文件、配置文件、驱动文件和中间件文件等部分,这些文件共同构成了HAL库的功能和特性,头文件(Include Files)包含了HAL库的API函数声明、宏定义、结构体定义等内容,开发者在编写应用程序时需要包含这些头文件才能使用HAL库提供的函数和功能。源文件(Source Files)包含了HAL库的API函数的具体实现过程,源文件通常以.c扩展名结尾,包含了对外设的初始化、配置和控制等操作的具体实现明细。配置文件(Configuration Files)包含了HAL库的配置信息,例如时钟配置、外设配置等。这些配置文件通常以.h扩展名结尾。驱动文件(Driver Files)包含了对外设的底层驱动代码,通常是对寄存器级别的操作。中间件文件(Middleware Files)包含了HAL库的中间件组件,例如USB库、文件系统库等。这些中间件文件提供了额外的功能和支持,使开发者能够更方便地实现特定功能。

图2-1 HAL库文件目录

表2-3  HAL库目录解读

序号

文件夹名称

功能特点

1

_htmresc

资源文件图标

2

Documentation

说明文档,固件库的说明文档

3

Drivers

驱动源码,包含BSP(板级支持包)、CMSIS(微控制器软件接口标准)、HAL(硬件抽象层库)驱动头文件及源文件

4

Middlewares

中间文件,包含ST官方提供USB库及触摸库及第三方提供FreeRTOS操作系统源文件

5

Projects

ST官方开发板例程

6

Utilities

系统公共组件

7

Package.xml

固件库版本信息

8

Release_Notes.html

补充及更新说明

HAL库(Hardware Abstraction Layer)是一个抽象层,用于将底层硬件和上层应用程序之间进行接口的标准化和抽象化。HAL库介于硬件与中间件操作系统之间,它提供了硬件抽象层函数接口(API)、板级支持包(BSP)的底层驱动以及HAL库函数样例,上层应用即为应用层级的Demo,系统层次图如下:

图2-2 系统层次图

2. 主控MCU基本知识

 STM32L431VCT6是STMicroelectronics推出的一款低功耗微控制器,采用Arm Cortex-M4内核,工作频率高达80MHz。该微控制器集成了丰富的外设,包括多个通用定时器、通用异步串行接口、SPI接口、I2C接口、以太网MAC接口等,以满足各种应用场景的需求。此外,它还具有丰富的模拟和数字接口,包括ADC、DAC、PWM、USART等,可实现多种外围设备的连接和控制。STM32L431VCT6采用了STMicroelectronics的低功耗技术,支持多种低功耗模式。它还具有丰富的内存配置,包括闪存、SRAM和EEPROM,以满足不同应用的存储需求。

图2-3 STM32L431VCT6 物理资源

GPIO基本知识:是指单片机的通用输入输出端口,用于连接外部设备,进行数字输入输出控制。GPIO可以通过编程控制单片机与外部设备的通信和交互,是单片机系统中非常重要的部分。通过设置GPIO的工作模式、输入输出状态和电平状态,可以实现单片机与外部设备的数据传输和控制。在嵌入式系统中,GPIO的操作通常是通过多个寄存器共同配合来实现控制的,实物中GPIO即为MCU的物理引脚,如下图所示:

图2-4 STM32F103实物图

图2-5 STM32L431 IO引脚资源分布

表2-4  引脚全量功能统计表

引脚号

引脚名称

引脚所支持所有功能

1

VBAT

Batter Input

2

PD5

RTC_OUT_ALARM、RTC_OUT_CALIBRATION、RTC_TAMP1、RTC_TS、SYS_WAKEUP2、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI13

3

PC14

RCC_OSC32_IN、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI14

4

PC15

ADC1_EXTI15、RCC_OSC32_OUT、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI15

5

PH0

RCC_OSC_IN、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI10

6

PH1

RCC_OSC_OUT、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI1

7

NRST

RESET

8

PC0

ADC1_IN1、I2C3_SCL、LPTIM1_IN1、LPTIM2_IN1、LPUART1_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI10

9

PC1

ADC1_IN2、I2C3_SDA、LPTIM1_OUT、LPUART1_TX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI1

10

PC2

ADC1_IN3、LPTIM1_IN2、SPI2_MISO、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI2

11

PC3

ADC1_IN4、LPTIM1_ETR、LPTIM2_ETR、SA1_SD_A、SPI2_MOSI、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI3

12

VSSA

0V

13

VDDA

3.3V

14

PA0

ADC1_IN5、COMP1_INM、COMP1_OUT、OPAMP1_VINP、RTC_TAMP2、SAI1_EXTCLK、SYS_WAKEUP1、TIM2_CH1、TIM2_ETR、USART2_CTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI0

15

PA1

ADC1_IN6、COMP1_INP、I2C1_SMBA、OPAMP1_VINM、SPI1_SCK、TIM15_CH1N、TIM2_CH2、USART2_DE、USART2_RTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI1

16

PA2

ADC1_IN7、COMP2_INM、COMP2_OUT、LPUART1_TX、QUAD_SPI_BK1_NCS、RCC_LSCO、TIM15_CH1、TIM2_CH3、USART2_TX、SYS_WAKEUP4、TIM2_CH2、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI2

17

PA3

ADC1_IN8、COMP2_INP、LPUART1_RX、OPAMP1_VOUT、QUAD_SPI_CLK、SA1_MCLK_A、TIM15_CH2、TIM2_CH4、USART2_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI3

18

VSS

0V

19

VDD

3.3V

20

PA4

ADC1_IN9、COMP1_INM、COMP2_INM、DAC1_OUT1、LPTIM2_OUT、SAI1_FS_B、SPI1_NSS、SPI3_NSS、USART2_CK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI4

21

PA5

ADC1_IN10、COMP1_INM、COMP2_INM、DAC1_OUT2、LPTIM2_ETR、SPI1_SCK、TIM2_CH1、TIM2_ETR、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI5

22

PA6

ADC1_IN11、COMP1_OUT、QUAD_SPI_BK1_IO3、SPI1_MISO、TIM16_CH1、TIM1_BKIN、TIM1_BKIN_COMP2、USART3_CTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI6

23

PA7

ADC1_IN12、COMP2_OUT、I2C3_SCL、QUAD_SPI_BK1_IO2、SPI1_MOSI、TIM1_CH1N、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI7

24

PC4

ADC1_IN13、COMP1_INM、USART3_TX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI4

25

PC5

ADC1_IN14、COMP1_INP、SYS_WAKEUP5、USART3_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI5

26

PB0

ADC1_IN15、COMP1_OUT、QUAD_SPI_BK1_IO1、SAI1_EXTCLK、SPI1_NSS、TIM1_CH2N、USART3_CK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI0

27

PB1

ADC1_IN16、COMP1_INM、QUAD_SPI_BK1_IO0、LPTIM2_IN1、LPUART1_DE、LPUART1_RTS、TIM1_CH3N、USART3_DE、USART3_RTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI1

28

PB2

COMP1_INP、I2C3_SMBA、LPTIM1_OUT、RTC_OUT_ALARM、RTC_OUT_CALIBRATION、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI2

29

PB10

COMP1_OUT、I2C2_SCL、LPUART1_RX、QUAD_SPI_CLK、SAI1_SCK_A、SPI2_SCK、TIM2_CH3、TSC_SYNC、USART3_TX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI10

30

PB11

COMP2_OUT、I2C2_SDA、LPUART1_TX、QUAD_SPI_BK1_NCS、ADC1_EXTI1、TIM2_CH4、USART3_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI11

31

VSS

0V

32

VDD

3.3V

33

PB12

I2C2_SMBA、LPUART1_DE、LPUART1_RTS、SAI1_FS_A、SPI2_NSS、SWPMI1_IO、TIM15_BKIN、TIM1_BKIN 、TIM1_BKIN_COMP2 、TSC_G1_IO1、USART3_CK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI12

34

PB13

I2C2_SCL、LPUART1_CTS、SAI1_SCK_A、SPI2_SCK、SWPMI1_TX、TIM15_CH1N、TIM1_BKIN、TSC_G1_IO2、USART3_CTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI13

35

PB14

I2C2_SDA、SAI1_MCLK_A、SPI2_MISO、SWPMI1_RX、TIM15_CH1、TIM1_CH2N、TSC_G1_IO3、USART3_DE、USART3_RTS 、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI14

36

PB15

ADC1_EXTI15、RTC_REFIN、SAI1_SD_A、SPI2_MOSI、SWPMI1_SUSPEND、TIM15_CH2、TSC_G1_IO4、TIM1_CH3N、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI15

37

PC6

SDMMC1_D6、TSC_G4_IO1、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI6

38

PC7

SDMMC1_D7、TSC_G4_IO2、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI7

39

PC8

SDMMC1_D0、TSC_G4_IO3、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI8

40

PC9

SDMMC1_D1、DAC1_EXTI9、TSC_G4_IO4、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI9

41

PA8

LPTIM2_OUT、RCC_MCO、SAI1_SCK_A、SWPMI1_IO、TIM1_CH1、USART1_CK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI8

42

PA9

DAC1_EXTI9、I2C1_SCL、SAI1_FS_A、TIM15_BKIN、TIM1_CH2、USART1_TX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI9

43

PA10

I2C1_SDA、SAI1_SD_A、TIM1_CH3、USART1_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI10

44

PA11

ADC1_EXTI11、CAN1_RX、COMP1_OUT、SPI1_MISO、TIM1_BKIN2、TIM1_BKIN2_COMP1、USART1_CTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI11

45

PA12

CAN1_TX、SPI1_MOSI、TIM1_ETR、、USART1_RTS、USART1_DE、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI12

46

PA13

IR_OUT、SAI1_SD_B、SWPMI1_TX、SYS_JTMS-SWDIO、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI13

47

VSS

0V

48

VDD

3.3V

49

PA14

I2C1_SMBA、LPTIM1_OUT、SAI1_FS_B、SWPMI1_RX、SYS_JTCK_SWCLK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI14

50

PA15

ADC1_EXTI15、SPI1_NSS、SPI3_NSS、SWPMI1_SUSPEND、SYS_JTDI、TIM2_CH1、TIM2_ETR、TSC_G3_IO1、USART2_RX、USART3_DE、USART3_RTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI15

51

PC10

SDMMC1_D2、SPI3_SCK、TSC_G3_IO2、USART3_TX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI10

52

PC11

SDMMC1_D3、SPI3_MISO、ADC1_EXTI11、TSC_G3_IO3、USART3_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI11

53

PC12

SDMMC1_CK、SPI3_MOSI、TSC_G3_IO4、USART3_CK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI12

54

PD2

SDMMC1_CMD、TSC_SYNC、USART3_DE、USART3_RTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI2

55

PB3

COMP2_INM、SAI1_SCK_B、SPI1_SCK、SPI3_SCK、 SYS_JTDO-SWO、TIM2_CH2、USART1_DE、USART1_RTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI3

56

PB4

COMP2_INP、SAI1_MCLK_B、SPI1_MISO、SPI3_MISO 、I2C3_SDA、 SYS_JTRST、TSC_G2_IO1、USART1_CTS、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI4

57

PB5

COMP2_OUT、LPTIM1_IN1、SPI3_MISO 、SAI1_SD_B、I2C1_SMBA、 SPI1_MOSI、SPI3_MOSI、TIM16_BKIN、TSC_G2_IO2、USART1_CK、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI5

58

PB6

COMP2_INP、I2C1_SCL、LPTIM1_ETR 、SAI1_FS_B、 SPI1_MOSI、SPI3_MOSI、TIM16_CH1N、TSC_G2_IO3、USART1_TX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI6

59

PB7

COMP2_INM、I2C1_SDA、LPTIM1_IN2、SYS_PVD_IN、 TSC_G2_IO4、USART1_RX、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI7

60

PH3

GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI3

61

PB8

CAN1_RX、I2C1_SCL、SAI1_MCLK_A、SDMMC1_D4、TIM16_CH1、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI8

62

PB9

CAN1_TX、DAC1_EXTI9、I2C1_SDA、IR_OUT、SAI1_FS_A、SDMMC1_D5、GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI9

63

VSS

3.3V

64

GND

0V

3. GPIO硬件基本知识

硬件原理图: 硬件原理图是一种图示化的设计文档,用于描述电子产品的硬件组成和连接关系。通常原理图中会包含电路中使用的各种电子元器件,如电阻、电容、晶体管、集成电路等,也详细的展示了各个元器件之间的物理连接关系,比如:信号传输路径以及电源的供电线路等。原理图的目的是帮助工程师理解电路的结构和功能,进行电路仿真和验证,以及进行电路板的布局和布线。硬件原理图通常使用专业的绘图软件如Altium Designer、Cadence Allegro等来绘制,并且需要遵循一定的标准和规范。以下电路仅包含实训硬件控制部分,不包含MCU最小系统电路,本次实训硬件原理图如下:

图2-6 MCU硬件原理图

根据上述硬件电路结构图可知,整个原理图由主控MCU STM32L431VCT6 、电阻R28、LED1、电源VCC端四部分组成,LED灯的状态由PD5引脚电平决定,PD5引脚输出低电平时,LED正常工作处于高亮状态,当PD5引脚为高电平时,LED处于熄灭状态。那么R6电阻在电路中,起到什么作用呢?事实上,LED灯与电阻R6构成分压电路,电阻R6起到限制电路中电流大小的作用。

PD5引脚类型为输入输出,可通过寄存器配置成输入/输出模式,该 引脚可以复用为事件触发功能,除此之外它可用作SPI、GPIO_Input、GPIO_Analog、EVENTOUT功能,后续实训环节,我们将该引脚配置成输出模式。

表2-5  PD5引脚基本功能信息

序号

引脚名称

引脚类型

引脚耐压

复用功能

附加功能

1

PD5

输入/输出

5V

EVENTOUT

QUADSPI_BK2_IO1

USART2_TX

GPIO_Input

GPIO_Output

GPIO_Analog

EVENTOUT

GPIO_EXTI5

备注1:引脚类型可配置为输入模式,也可配置成输出模式,STM32 系列MCU 通常情况下引脚电压为3.3V,但允许部分引脚可容纳5V电压,在配置复用资源功能时,可当做事件输出来使用,同时也可用作USART、EVENTOUT等其他输出配置来使用

备注2:I/O是Input/Output即为输入/输出

表2-6  PD5引脚输出电平真值表

序号

PD5引脚状态

引脚配置模式

现象

1

高电平

输出模式

LED1熄灭

2

低电平

输出模式

LED1高亮

GPIO引脚的输入输出模式是嵌入式系统开发中常用的功能,有助于了解更多的外设的,通过配置GPIO引脚的输入输出模式,可以实现对外部信号的读取和控制。对于输入模式大致可以分为三类,浮空输入(Floating Input)引脚处于高阻态,没有外部上下拉电阻。在此模式下,引脚可以接收外部信号,但由于没有上下拉电阻的作用,经常会受到干扰。上拉输入(Pull-Up Input)引脚通过内部上拉电阻连接到电源正极,当外部信号未连接时,引脚会被拉高至逻辑高电平。下拉输入(Pull-Down Input)引脚通过内部下拉电阻连接到地,当外部信号未连接时,引脚会被拉低至逻辑低电平。输出模式大致分为两类,推挽输出(Push-Pull Output)脚可以输出高电平或低电平,没有漏极电流。开漏输出(Open-Drain Output)引脚可以输出低电平,但输出高电平时处于高阻态,通常需要外部上拉电阻连接到电源正极,以实现输出高电平。

图2-7 GPIO输入/输出模式内部框图

表2-7  GPIO引脚输入/输出模式汇总

序号

模式

特点及应用

1

输入浮空

输入时配置使用,完全浮空,电平状态不确定

2

输入上拉

输入时配置使用,用内部上拉,默认是高电平

3

输入下拉

输入时使用,用内部下拉,默认是低电平

4

模拟功能

模数转换、数模转换

5

开漏输出

可以驱动较大电流的负载,且具有较好的抗干扰能力,在使用开漏输出时,通常需要外部上拉电阻

6

推挽输出

驱动能力强,大约25mA电流输出能力,用作通用输出

7

开漏复用功能

复用某些引脚功能,用在片上外设功能

8

推挽复用功能

复用某些引脚功能,用在片上外设功能

4. GPIO编程基本知识

寄存器(Register)基本概念:是一种用于存储和操作数据的高速临时存储器,在计算机程序执行过程中,寄存器起着重要的作用。它们用于存储程序运行时产生的临时数据、中间结果以及控制信息,帮助CPU高效地执行指令和计算任务。开发者在编写程序时可以通过寄存器来进行数据操作和传递,提高程序的执行效率和性能。在嵌入式系统开发中,对寄存器的直接访问和操作也是常见的编程技巧,可以实现对硬件设备的底层控制和配置。

表2-8  GPIO相关常用寄存器介绍

序号

寄存器类型

寄存器名称

功能特点

1

32位IO控制类型

GPIOx_MODER

配置输入/输出/复用/模拟模式

2

GPIOx_OTYPER

配置输出类型(推挽/开漏)

3

GPIOx_OSPEEDR

配置输出速度

4

GPIOx_PUPDR

配置上拉/下拉以及输入输出方向

5

16位IO数据类型

GPIOx_IDR

输入数据寄存器

6

GPIOx_ODR

输出数据寄存器

7

32位IO位运算类型

GPIOx_BSRR

位运算寄存器

8

32位IO复用功能类型

GPIOx_AFRL

复用功能低位寄存器

9

GPIOx_AFRH

复用功能高位寄存器

HAL库函数外设在使用过程步骤比较相似,往往都要经历开启外设时钟、外设初始化、读写外设数据、外设中断函数及回调等过程,操作顺序如下:

图2-8 HAL库常规操作步骤

表2-9  GPIO相关常用库函数

序号

函数

类型

函数名称

函数功能

1

时钟

__HAL_RCC_GPIOA_CLK_ENABLE()

__HAL_RCC_GPIOA_CLK_DISABLE()

打开/关闭PA端口时钟

2

__HAL_RCC_GPIOB_CLK_ENABLE()

__HAL_RCC_GPIOB_CLK_DISABLE()

打开/关闭PB端口时钟

3

__HAL_RCC_GPIOC_CLK_ENABLE()

__HAL_RCC_GPIOC_CLK_DISABLE()

打开/关闭PC端口时钟

4

__HAL_RCC_GPIOD_CLK_ENABLE()

__HAL_RCC_GPIOD_CLK_DISABLE()

打开/关闭PD端口时钟

5

__HAL_RCC_GPIOE_CLK_ENABLE()

__HAL_RCC_GPIOE_CLK_DISABLE()

打开/关闭PE端口时钟

6

__HAL_RCC_GPIOF_CLK_ENABLE()

__HAL_RCC_GPIOF_CLK_DISABLE()

打开/关闭PF端口时钟

7

__HAL_RCC_GPIOG_CLK_ENABLE()

__HAL_RCC_GPIOG_CLK_DISABLE()

打开/关闭PG端口时钟

8

__HAL_RCC_GPIOH_CLK_ENABLE()

__HAL_RCC_GPIOH_CLK_DISABLE()

打开/关闭PH端口时钟

9

初始化/逆初始化

HAL_GPIO_Init()

根据输入的参数初始化GPIOx外设(x=A…H)

10

HAL_GPIO_DeInit()

将GPIOx外设寄存器取消初始化为其默认复位值(x=A…H)

11

IO操作类

HAL_GPIO_ReadPin()

读取指定的输入端口引脚电平

12

HAL_GPIO_WritePin()

设置或清除所选数据端口位电平

13

HAL_GPIO_TogglePin()

翻转电平

14

HAL_GPIO_LockPin()

锁定引脚配置寄存器

15

HAL_GPIO_EXTI_IRQHandler()

处理 EXTI 中断请求

16

HAL_GPIO_EXTI_Callback()

中断回调函数

本案例GPIO_LED_Control\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_gpio.h HAL_GPIO_WritePin函数为例讲解库函数的具体使用方法,HAL_GPIO_WritePin函数声明在stm32l4xx_hal_gpio.h文件中,函数体的定义在stm32l4xx_hal_gpio.c文件中,该函数主要操作的寄存器有两个分别是GPIOx_BSRR与GPIOx_BRR,共有3个输入形式参数,GPIOx是指针变量,它指向的地址是GPIO端口所在的基地址,如:使用 C端口,则写成GPIOC,第二个参数为GPIO_Pin引脚号,STM32 MCU每个端口包含16个引脚,引脚编码从0~15,如:某端口13号引脚,则写成GPIO_PIN_13,第三个参数为引脚的状态,该参数结构为枚举类型,只有高电平及低电平两种选择。

HAL_GPIO_WritePin库函数原型:

void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)

{

/* Check the parameters */

assert_param(IS_GPIO_PIN(GPIO_Pin));

assert_param(IS_GPIO_PIN_ACTION(PinState));

if(PinState != GPIO_PIN_RESET)

{

GPIOx->BSRR = (uint32_t)GPIO_Pin;

}

else

{

GPIOx->BRR = (uint32_t)GPIO_Pin;

}

}

//第一个形式参数GPIOx主要是使用的端口选择:

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)

#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)

#define GPIOH               ((GPIO_TypeDef *) GPIOH_BASE)

//GPIOx端口可操作的寄存器

typedef struct

{

  __IO uint32_t MODER;       /*!< GPIO port mode register,               Address offset: 0x00      */

  __IO uint32_t OTYPER;      /*!< GPIO port output type register,        Address offset: 0x04      */

  __IO uint32_t OSPEEDR;     /*!< GPIO port output speed register,       Address offset: 0x08      */

  __IO uint32_t PUPDR;       /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */

  __IO uint32_t IDR;         /*!< GPIO port input data register,         Address offset: 0x10      */

  __IO uint32_t ODR;         /*!< GPIO port output data register,        Address offset: 0x14      */

  __IO uint32_t BSRR;        /*!< GPIO port bit set/reset  register,     Address offset: 0x18      */

  __IO uint32_t LCKR;        /*!< GPIO port configuration lock register, Address offset: 0x1C      */

  __IO uint32_t AFR[2];      /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */

  __IO uint32_t BRR;         /*!< GPIO Bit Reset register,               Address offset: 0x28      */

} GPIO_TypeDef;

//第二个形式参数GPIO_Pin 主要是使用的引脚选择:

#define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */

#define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */

#define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */

#define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */

#define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */

#define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */

#define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */

#define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */

#define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */

#define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */

#define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */

#define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */

#define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */

#define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */

#define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */

#define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */

#define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */

//第三个形式参数PinState 主要是引脚状态的选择:

typedef enum

{

GPIO_PIN_RESET = 0U,  //置位为低电平

GPIO_PIN_SET         //置位为高电平

}GPIO_PinState;

说明:由于PD5引脚输入PC端口,引脚号为5,若将PD5引脚输出高电平,则调用形式:HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5,GPIO_PIN_SET), 若将PD5引脚输出低电平,调用形式:HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_RESET)。

5. GPIO外设配置基本知识

1)配置GPIO外设,将PC13引脚设定为输出模式

图2-9 PC13引脚设置输出模式

2)单击PD5引脚,设置输出模式为“GPIO_Output”,参数设置为默认

图2-10 PD5引脚基本参数设置

3)Keil 工程代码编辑与编译

图2-10 Keil工程业务代码编辑与编译

4)STM32 ST-LINK Utility 软件烧录

图2-11 STM32 ST-LINK Utility软件烧录

 技能训练

1. 任务目标

本任务通过STM32CubeMX软件生成LED_Control工程,并使用Keil打开该案例工程,编写相关业务逻辑代码经过Keil软件编辑业务控制代码并编译、烧录至开发板,实现LED灯每隔2秒交替闪烁,配置过程要求如下:

  1. 使用STM32CubeMX软件设置主控MCU为“STM32L431VCTx”,并启动工程
  2. 配置RCC外设时钟源为外部晶体振荡器 
  3. 配置SYS外设调试模式为“Disable”状态
  4. 配置GPIO外设PD5引设置为“GPIO_Output”输出模式,参数设置为默认
  5. 配置系统时钟主频为72MHz
  6. 配置工程名为“LED_Control”,集成开发工具(IDE Toolchain)为“MDK-ARM V5”,Application Structure为“Basic”,Code Generator选项中Generated files勾选“Generate peripheral initialization as a pair of .c/.h files per peripheral”
  7. 使用STM32CubeMX 生成工程
  8. 使用Keil软件在main.c源文件中实现对PD5引脚拉高电平2秒钟,后拉低电平2秒钟,进而实现LED交替闪烁的目的
  9. 使用STM32 ST-LINK Utility软件实现对目标开发板连接及烧录LED_Control工程中的hex文件
  10. 关闭STM32 ST-LINK Utility软件
  11. 观察实验现象并记录
2. 任务流程

图2-12 任务执行流程

3. 任务实施

(1)启动STM32CubeMX软件,并设置主控MCU为“STM32L431VCTx”,创建工程

图2-13 创建工程

(2)配置RCC外设时钟,时钟源选择外部晶体振荡器,RCC其他参数配置为默认

图2-13 RCC外设配置

(3)配置SYS 调试模式为“Disable”,即为取消调试功能

图2-14 SYS外设配置

(4)配置PD5引脚为输出模式,其他参数设置为默认

图2-15 GPIO外设配置

(5)配置系统时钟主频为72MHz

图2-16 系统时钟配置

(6)配置工程参数,工程命名为“LED_Control”,集成开发工具设置为“MDK-ARM V5”,Application Structure设置为“Basic”

图2-17 工程基本参数配置

(7)配置工程参数,CodeGenerator选项中设置生成外设源文件

图2-18 工程代码文件生成配置

(8)使用STM32CubeMX软件生成工程

图2-19 工程创建完成

(9)使用Keil软件在LED_Control工程中打开main.c文件主循环结构中实现PD5引脚电平控制的代码

HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_RESET);

HAL_Delay(2000);

HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_SET);

HAL_Delay(2000);

图2-20 业务代码编辑

(10)使用Keil软件编译工程,0 Error 表示没有错误,即编译成功

图2-21 Keil软件工程代码编译

(11)硬件连接目标开发板 

图2-22 实验现象观察

(12)使用STM32 ST-LINK Utility 软件连接目标开发板

图2-23 STM32 ST-LINK Utility目标板连接

(13)使用STM32 ST-LINK Utility 软件加载LED_Control生成的hex文件,hex文件位于“LED_Control\MDK-ARM\GPIO_LED_Control”目录下

图2-24 STM32 ST-LINK Utility 加载hex文件

(14)使用STM32 ST-LINK Utility 软件进行烧录

图2-25 STM32 ST-LINK Utility 烧录程序

(15)确认是否烧录成功

图2-26 STM32 ST-LINK Utility 烧录结果确认

(15)观察实验现象

图2-27 开发板实验现象观察


任务二  中断型LED驱动控制

1. 中断基本知识

中断是计算机系统中一种重要的事件处理机制,用于在程序执行过程中响应和处理特定的事件或信号。当系统发生某种特定的事件时,如外部设备发送信号、定时器计时结束等,都会触发中断,CPU暂停当前程序的执行,转而执行中断服务程序,处理相应的事件。中断可以分为外部中断(来自外部设备或信号)和内部中断(来自CPU内部的事件)两种类型。中断系统主要由中断源、中断控制器、中断服务程序、中断向量表四部分组成。中断源:触发中断的事件源,可以是外部设备、定时器、通信接口等,当中断源发生相应事件时,会向CPU发送中断请求信号。中断控制器:用于管理和处理中断请求,确定中断优先级、响应方式等,中断控制器会将中断请求信号传递给CPU,并协助CPU进行中断处理。中断服务程序:中断发生时,CPU会暂停当前程序的执行,跳转到预先定义的中断服务程序中执行相应的处理逻辑,中断服务程序通常包括中断处理、保存现场、处理事件、恢复现场等步骤。中断向量表:存储不同中断源对应的中断服务程序入口地址,当中断发生时,CPU会根据中断号或中断向量找到对应的中断服务程序入口地址。

图2-28 中断示意图

2. NVIC中断基本知识

NVIC (Nested Vectored Interrupt Controller) 是 ARM 处理器中用于管理中断的模块。NVIC是一种用于处理中断请求的硬件设备,它负责管理和分发来自外部设备和内部处理器的中断信号。它的主要功能是按照优先级顺序处理和调度中断请求,确保系统能够及时响应并处理各种事件。NVIC中断管理主要分成五部分,分别是接收中断请求,优先级排序、分发中断请求、屏蔽中断、嵌套中断等。接收中断请求: NVIC 可以接收来自不同外设和软件的中断请求。优先级排序: NVIC 可以根据中断请求的优先级进行排序,并确保高优先级的中断请求优先处理。分发中断请求: NVIC 可以将中断请求分发给相应的处理程序。屏蔽中断: NVIC 可以屏蔽特定的中断请求,防止它们被处理。嵌套中断: NVIC 支持嵌套中断,允许高优先级的中断打断低优先级的中断处理。

在STM32的NVIC中断管理编程中,抢占优先级与响应优先级是两个重要的概念。抢占优先级,顾名思义,是指当多个任务同时发生时,哪个任务拥有更高的优先级能够抢占CPU资源,即优先执行。在STM32中,抢占优先级通过设置中断优先级组来实现。不同的中断可以设置不同的抢占优先级,越高的优先级代表其在同时发生中能够更早地抢占CPU资源。响应优先级则是指在发生多个中断时,优先处理哪个中断。同样在STM32中,通过设置中断使能和禁止来控制响应优先级。高优先级的中断将会被优先处理,以确保对重要任务的及时响应。抢占优先级和响应优先级之间存在一定的关系。通常情况下,抢占优先级应该大于等于响应优先级,以确保高优先级的中断能够顺利执行。在STM32的实战编程中,正确设置抢占优先级和响应优先级对于系统的稳定性和性能至关重要。合理地设置这两个参数,不仅能够确保高优先级任务的及时处理,还可以避免优先级倒置和死锁等问题的出现。

表2-4  NVIC中断功能特点

序号

基本功能

1

支持多高达240个中断

2

支持每个中断的可编程优先级为0-15,其中0是最高优先级,数字越大优先级越低

3

支持中断信号的优先级和脉冲检测

4

支持中断的动态重排优先级

5

支持优先级分组,分为组优先级和子优先级字段

6

支持外部不可屏蔽中断(NMI)

在嵌入式系统开发中,NVIC中断向量表(Nested Vectored Interrupt Controller)是系统处理中断的关键,充当着调度中断服务例程的“指挥官”,也是硬件与软件之间协同工作的桥梁。什么是中断向量表呢?简而言之,它是一张记录着不同中断类型对应的中断服务例程的表格,当发生中断时,系统会根据中断类型找到相应的中断服务例程,并立即执行,以实现对中断事件的有效响应。总结来说,中断向量表就是系统对不同中断进行分门别类,使系统能够迅速而准确地作出相应反应的依据。在NVIC中断向量表中,每个中断类型都有对应的地址,这些地址指向了相应的中断服务例程。因此,在系统启动时,必须在中断向量表中正确地填写每个中断的地址,以确保中断的正常处理。

 2-5  M4内核中断向量表

序号

优先级

类型

内核中断类型

基本功能

1

固定

Reset

复位中断

2

固定

NMI

不可屏蔽中断。RCC 时钟安全系统(CSS)链接到 NMI 矢量。

3

固定

HardFault

异常错误中断

4

可调

MemMange

内存管理中断

5

可调

BusFault

预取故障、内存访问故障

6

可调

UsageFault

未定义的指令或非法状态

7

可调

SVCall

指令系统服务调用

8

可调

Debug

调试中断

9

可调

PendSV

可挂起的系统服务请求

10

可调

SysTick

系统滴答计时器

EXTI外部中断,即外部中断控制器,它是一种用于处理外部事件触发的机制。它允许外部信号,如按键、传感器或其他外部事件,通过引脚触发微控制器的中断。传统做法采用持续轮询的方式,通过EXTI外部中断就可以立即响应外部事件,实现了真正的实时性,无论是监控系统、智能家居、工业自动化还是其他领域的应用,EXTI外部中断都可以为您的项目增添不可或缺的智能和灵活性,提高了系统的灵活性和响应速度。

此外,EXTI外部中断的配置也相对简单灵活。通过简单的设置,您可以指定哪些引脚将触发中断,以及触发中断时的行为,如触发边沿(上升沿、下降沿或双边沿触发)或电平触发。

2-5  部分外设中断

序号

优先级

类型

外部中断类型

基本功能

1

可调

WWDG

窗口看门狗中断

2

可调

RTC_WAKEUP

 实时时钟唤醒中断

3

可调

FLASH

FLASH全局中断

4

可调

RCC

复位时钟控制全局中断

5

可调

EXTI0

EXTI0中断

6

可调

EXTI1

EXTI1中断

7

可调

EXTI2

EXTI2中断

8

可调

EXTI3

EXTI3中断

9

可调

EXTI4

EXTI4中断

10

可调

DMA1_CH1

DMA1通道1中断

GPIO(通用输入/输出引脚)是单片机外设中非常宝贵的资源,它们可以通过配置为输入或输出模式来与外部设备进行通信。而EXTI(外部中断)是一种特殊的GPIO功能,可以将外部事件作为中断触发源。GPIO与EXTI之间存在有一种映射关系,将某个GPIO引脚映射到EXTI的某个中断线上,当GPIO引脚的电平发生变化时,就可以触发对应的EXTI中断。

图2-29 GPIO口与EXTI2映射关系图

图2-30 GPIO口与EXTI3映射关系图

3. NVIC硬件基本知识 

PD5引脚类型为输入输出,可通过寄存器配置成输入/输出模式,该 引脚可以复用为事件触发功能,除此之外它可用作RTC_TAMP、RTC_OUT、RTC_TS、WAKEUP功能,后续实训环节,我们将该引脚配置成输出模式。

表2-5  引脚基本功能信息

序号

引脚名称

引脚类型

引脚耐压

附加功能

1

PA4

输入/输出

5V

ADC1_IN9、COMP1_INM、COMP2_INM、DAC1_OUT1、LPTIM2_OUT、SAI1_NSS、SPI3_NSS、USART2_CK、

GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI4

2

PA5

输入/输出

5V

ADC1_IN、COMP1_INM、COMP2_INM、DAC1_OUT2、LPTIM2_ETR、TIM2_CH1、SPI1_SCK、TIM2_ETR、

GPIO_Input、GPIO_Output、GPIO_Analog、EVENTOUT、GPIO_EXTI5

3

PD5

输入/输出

5V

RTC_TAMP1

RTC_OUT

RTC_TS

WKUP2

GPIO上拉输入是指将GPIO引脚设置为输入模式,并通过上拉电阻将引脚电平拉高。这种设置可以使引脚在无外部输入时保持一个稳定的高电平状态,同时可以通过外部输入信号来改变引脚电平。它可以用于检测外部事件,例如按键、开关等。当外部事件触发时,GPIO引脚的电平会随之改变,我们可以通过读取引脚电平来判断事件是否发生。其次,GPIO上拉输入还可以用于接收传感器的输入信号。许多传感器的输出信号是以电平高低的形式进行传递的,我们可以将其连接到GPIO引脚上,在程序中读取引脚电平来获取传感器的测量值。

图2-31 GPIO输入/输出内部框图

实训硬件电路共使用3个GPIO引脚,分别是PD5、PB2、PB3,PD5作为输出模式来使用,其余两个均为输入模式,PB2、PB3分别外接两个按键,通过按下按键触发MCU中断系统,在各自的中断函数中定义相应的功能,实现对中断的处理,实现相应的功能,如:PB2中断处理中,可以设定开灯动作,PB3中可以设定关灯动作。以下电路仅包含实训硬件控制部分,不包含MCU最小系统电路:

图2-32 实训硬件简约原理图

4. NVIC编程基本知识 

首先,NVIC代表嵌入式系统中的中断控制器。在STM32L431VCT6中,NVIC寄存器起着至关重要的作用,它们管理着中断请求和优先级,确保系统能够高效地响应外部事件。让我们来认识一下NVIC编程相关的寄存器:

表2-8  NVIC相关寄存器介绍

序号

寄存器

功能

寄存器名称

功能特点

1

中断使能

NVIC_ISERx

该寄存器用于启用特定中断。通过设置相应的位,您可以激活需要的中断,使其能够触发系统响应

2

中断禁用

NVIC_ICERx

该寄存器用于禁用特定的中断

3

中断优先级

NVIC_IPRx

该寄存器用于设置中断的优先级

4

中断挂起

NVIC_ISPRx

该寄存器用于设置中断的挂起状态

5

中断清除

NVIC_ICPRx

该寄存器用于清除中断的挂起状态

6

中断激活

NVIC_IABRx

该寄存器用于中断激活标志

7

软件触发

中断

NVIC_STIR

该寄存器用于软件触发中断

HAL库NVIC(Nested Vector Interrupt Controller)函数在中断编程中起着重要的作用。通过合理的使用NVIC函数,可以实现中断管理和优先级控制,提高系统的可靠性和性能下面是对几个常用的NVIC函数进行简要介绍:

表2-9  NVIC相关常用库函数

序号

函数名称

函数功能

1

NVIC_EnableIRQ(IRQn_Type IRQn)

该函数用于使能指定的中断

2

HAL_NVIC_DisableIRQ(IRQn_Type IRQn)

该函数用于禁用特定的中断

3

HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

该函数用于设置中断的优先级

4

HAL_NVIC_GetPendingIRQ(IRQn_Type IRQn);

该函数检测某个中断是否处于挂起状态

5

HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);

该函数用于手动触发某个中断

6

HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn);

该函数用于清除某个中断的挂起状态

7

HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);

该函数用于设置组优先级

HAL_NVIC_SetPriorityn函数声明在stm32l4xx_hal_cortex.h文件中,函数体的定义在stm32l4xx_hal_cortex.c文件中,该函数主要操作的寄存器有两个分别是NVIC_IPR,共有3个输入形式参数,IRQn是中断向量号,用它来分辨中断源,第二个参数为PreemptPriority,它用4比特来表示抢占优先级,所以它的取值范围为0~15,第三个参数为SubPriority,它用4比特来表示响应优先级,它的取值范围为0~15。

//函数功能:设置中断的优先级

void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

{

  uint32_t prioritygroup = 0x00;

  /* Check the parameters */

  assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));

  assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));

  prioritygroup = NVIC_GetPriorityGrouping();

  NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));

}

//参数一IRQn:外部中断号,实训中需要的选项为:

 // EXTI4_IRQn                  = 10,      /*!< EXTI Line4 Interrupt                                              */

//  EXTI9_5_IRQn              = 23,      /*!< EXTI Line9_5 Interrupt                                              */

//参数二PreemptPriority: IRQn通道的抢占优先级,取值范围0 ~ 15

//参数三SubPriority:        IRQn通道的响应优先级,取值范围0 ~ 15

说明:实训中采用PA4、PA5两个GPIO端口通过按键的形式来触发中断,PB2引脚的中断号为EXTI2_IRQn则调用形式:HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 2),同理PA5引脚中断号为EXTI9_5_IRQn ,调用形式:HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 2)。

中断处理函数是针对硬件中断或异常事件产生的响应机制,用于在事件发生时实时处理相关的任务。无论是处理硬件故障、捕捉异常情况,还是监听用户输入信号,中断处理函数都起着非常重要的作用。

中断处理函数的工作机制可以简单理解为在发生中断事件时,计算机系统会立即中断当前正常的执行过程,转而执行与中断事件相关的处理程序。这一机制保证了系统能够及时、有效地应对各种异常情况,以保证系统的稳定性和可靠性。

在编程中,中断处理函数的编写是非常重要的一环。合理设计和实现中断处理函数能够提高系统的响应速度和处理效率,保障系统的可用性。通常,中断处理函数需要根据具体的中断类型和需求编写相应的代码逻辑,以确保在事件发生时能够快速准确地进行处理。

//函数功能:中断处理函数

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)

{

  /* EXTI line interrupt detected */

  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)

  {

    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

    HAL_GPIO_EXTI_Callback(GPIO_Pin);

  }

}

//参数一GPIO_Pin:引脚号,参数可选项为:

#define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */

#define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */

#define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */

#define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */

#define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */

#define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */

#define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */

#define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */

#define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */

#define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */

#define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */

#define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */

#define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */

#define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */

#define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */

#define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */

#define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */  

//实训中中断使用的引脚号:       

    //GPIO_PIN_4

//GPIO_PIN_5

//EXTI 外部中断回调函数

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

  /* Prevent unused argument(s) compilation warning */

  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,

           the HAL_GPIO_EXTI_Callback could be implemented in the user file

   */

}

//__weak 是弱类型函数,需要用户自己实现函数体内容

说明:实训中当按下按键时,会自动触发中断,调用HAL_GPIO_EXTI_IRQHandler来进入中断程序,则调用形式:HAL_GPIO_EXTI_IRQHandler (GPIO_PIN_4),在中断回调函数中执行用户自定义业务功能,调用形式:HAL_GPIO_EXTI_Callback(GPIO_PIN_4),同理PA5也是如此。

5.工具配置基本知识

1)配置GPIO外设,将PC13引脚设定为输出模式

图2-33 PC13引脚设置输出模式

2)单击PC13引脚,设置输出模式为“GPIO_Output”,参数设置为默认

图2-34 PC13引脚基本参数设置

3)设置PB4引脚输入模式为“GPIO_EXTI4”,输入模式设置为下拉

图2-35 PA4引脚模式配置

4)设置PA5引脚输入模式为“GPIO_EXTI5”,输入模式设置为上拉

图2-36 PA5引脚模式配置

5)Keil 工程代码编辑与编译

图2-37 Keil工程业务代码编辑与编译

6)STM32 ST-LINK Utility 软件烧录

图2-38 STM32 ST-LINK Utility软件烧录

 技能训练

1. 任务目标

本任务通过STM32CubeMX软件生成Key_LED_Control工程,并使用Keil打开该案例工程,编写相关业务逻辑代码经过Keil软件编辑业务控制代码并编译、烧录至开发板,实现LED灯每隔2秒交替闪烁,配置过程要求如下:

  1. 使用STM32CubeMX软件设置主控MCU为“STM32L431RCTx”,并启动工程
  2. 配置RCC外设时钟源为外部晶体振荡器 
  3. 配置SYS外设调试模式为“Disable”状态
  4. 配置GPIO外设PD5引设置为“GPIO_Output”输出模式,参数设置为默认
  5. 配置系统时钟主频为72MHz
  6. 配置工程名为“Key_LED_Control”,集成开发工具(IDE Toolchain)为“MDK-ARM V5”,Application Structure为“Basic”,Code Generator选项中Generated files勾选“Generate peripheral initialization as a pair of .c/.h files per peripheral”
  7. 使用STM32CubeMX 生成工程
  8. 使用Keil软件在main.c源文件中实现对PD5引脚拉高电平2秒钟,后拉低电平2秒钟,进而实现LED交替闪烁的目的
  9. 使用STM32 ST-LINK Utility软件实现对目标开发板连接及烧录Key_LED_Control工程中的Hex文件
  10. 关闭STM32 ST-LINK Utility软件
  11. 观察实验现象并记录
2. 任务流程

图2-39 任务执行流程

3. 任务实施

(1)启动STM32CubeMX软件,并设置主控MCU为“STM32L431RCTx”,创建工程

图2-40 创建工程

(2)配置RCC外设时钟,时钟源选择外部晶体振荡器,RCC其他参数配置为默认

图2-41 RCC外设配置

(3)配置SYS 调试模式为“Disable”,即为取消调试功能

图2-42 SYS外设配置

(4)配置PD5引脚为输出模式,其他参数设置为默认

图2-43 GPIO外设PD5配置

(5)配置PA4引脚为“GPIO_EXTI4”,基本参数设置上升沿触发、上拉输入模式

图2-44 GPIO外设PA4配置

(6)配置PA5引脚为“GPIO_EXTI5”,基本参数设置上升沿触发、上拉输入模式

图2-45 GPIO外设PA5配置

(7)配置系统时钟主频为72MHz

图2-46 系统时钟配置

(8)配置工程参数,工程命名为“Key_LED_Control”,集成开发工具设置为“MDK-ARM V5”,Application Structure设置为“Basic”

图2-47 工程基本参数配置

(9)配置工程参数,CodeGenerator选项中设置生成外设源文件

图2-48 工程代码文件生成配置

(10)使用STM32CubeMX软件生成工程

图2-49 工程创建完成

(11)使用Keil软件在gpio.c文件实现如下代码:

/* Includes ------------------------------------------------------------------*/

#include "gpio.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*----------------------------------------------------------------------------*/

/* Configure GPIO                                                             */

/*----------------------------------------------------------------------------*/

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/** Configure pins as

        * Analog

        * Input

        * Output

        * EVENT_OUT

        * EXTI

*/

void MX_GPIO_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOH_CLK_ENABLE();

  __HAL_RCC_GPIOA_CLK_ENABLE();

  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA4 PA5 */

  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;

  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

  GPIO_InitStruct.Pull = GPIO_PULLUP;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PD5 */

  GPIO_InitStruct.Pin = GPIO_PIN_5;

  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);

HAL_NVIC_SetPriority(EXTI9_5_IRQn, 1, 0);

HAL_NVIC_EnableIRQ(EXTI4_IRQn);

HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

}

/* USER CODE BEGIN 2 */

void EXTI4_IRQHandler(void)

{

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);

}

void EXTI9_5_IRQHandler (void)

{

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5);

}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

if(GPIO_Pin == GPIO_PIN_4)   HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5,GPIO_PIN_RESET);

           if(GPIO_Pin == GPIO_PIN_5)   HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5,GPIO_PIN_SET);

}

/* USER CODE END 2 */

图2-49 业务代码编辑

(12)使用Keil软件编译工程,0 Error 表示没有错误,即编译成功

图2-50 Keil软件工程代码编译

(13)目标板硬件连接 

图2-51 实验现象观察

(14)使用STM32 ST-LINK Utility 软件连接目标开发板

图2-52 STM32 ST-LINK Utility目标板连接

(15)使用STM32 ST-LINK Utility 软件加载Key_LED_Control生成的hex文件,hex文件位于“Key_LED_Control\MDK-ARM\LED_Control”目录下

图2-53 STM32 ST-LINK Utility 加载hex文件

(16)使用STM32 ST-LINK Utility 软件进行烧录

图2-54 STM32 ST-LINK Utility 烧录程序

(17)确认是否烧录成功

图2-55 STM32 ST-LINK Utility 烧录结果确认

(18)轻触KEY1按键及轻触KEY2按键观察实验现象

图2-56 开发板实验现象观察

### STM32 HAL GPIO 输出函数使用方法 #### 初始化与配置 为了使能GPIO端口时钟并设置指定引脚为输出模式,可以调用`__HAL_RCC_GPIOX_CLK_ENABLE()`宏定义来开启相应外设的时钟。接着创建一个`GPIO_InitTypeDef`结构体变量用于保存要初始化的GPIO参数。 ```c // 开启GPIOA时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; ``` 对于具体的引脚配置,在`GPIO_InitStruct`中设定Mode(工作模式)、Pull(上下拉电阻状态)、Speed(速度等级)以及Alternate(复用功能)。当目标是作为简单的推挽输出时: ```c GPIO_InitStruct.Pin = GPIO_PIN_5; // 设置具体哪个引脚, 这里假设PA5 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式 GPIO_InitStruct.Pull = GPIO_NOPULL; // 不带内部上下拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); ``` 上述代码片段展示了如何针对特定引脚执行基本的输出配置[^1]。 #### 控制IO电平高低 一旦完成了必要的硬件资源准备之后就可以通过下面两个API来进行高/低电平切换了: - `HAL_GPIO_WritePin()`: 将某个或某些位写入给定的状态。 ```c HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // PA5置高 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // PA5清零 ``` - `HAL_GPIO_TogglePin()`: 切换指定引脚当前逻辑电平 ```c HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 反转PA5电平 ``` 这些接口允许程序灵活地改变外部设备连接到MCU上的信号线的工作方式,从而达到控制外围电路的目的[^2]。 #### 完整示例 这里给出一段完整的例子用来说明怎样基于STM32 HAL编写一段能够周期性点亮熄灭LED的小实验。 ```c #include "stm32f1xx_hal.h" int main(void){ /* Reset of all peripherals, Initializes the Flash interface and Systick. */ HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Enable clock for GPIOA GPIO_InitTypeDef GPIO_InitStruct = {0}; // Configure LED pin as output push-pull mode without pull-up/pull-down resistor. GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); while (1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // Toggle state on PA5 HAL_Delay(1000); // Wait one second between toggles } } ``` 这段源码实现了每秒钟一次翻转PA5管脚电压的功能,如果该针脚接有一个LED,则会观察到灯光按照固定间隔闪烁的效果[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值