本帖最后由 正点原子运营 于 2024-3-27 16:29 编辑
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板
2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版
6)正点原子STM32技术交流QQ群:725095144
前两章介绍了GPIO在输出模式和输入模式下最基本的的操作,本章将介绍如何将GPIO引脚作为外部中断输入来使用。通过本章的学习,读者将学习到GPIO作为外部中断输入的使用。 本章分为如下几个小节: 12.1 硬件设计 12.2 程序设计 12.3 下载验证
12.1 硬件设计 12.1.1 例程功能 1. 按下WKUP按键,LED0状态翻转。 2. 按下KEY0按键,LED1状态翻转。
12.1.2硬件资源 1. LED LED0 - PB5 LED1 - PE5 2. 按键 WKUP - PA0 KEY0 - PE4
12.1.3 原理图 本章实验使用的两个M144Z-M3最小系统板STM32F103版板载按键,分别为KEY0按键和WKUP按键,其于板载MCU的连接原理图,如下图所示: 从上面的原理图中可以看出,WKUP按键和KEY0按键的一端连接到了电源正极,而另一端分别与MCU的PA0引脚和PE4引脚相连接,并且在上一小节的介绍中,也说明了对于该硬件设计,PA0引脚和PE4引脚应当配置为下拉,这样一来,在按键被按下的时候,PA0引脚或PE4引脚就会从原来的低电平状态变为高电平状态,在这期间就会有一个上升沿的跳变,因此可以使用该上升沿信号作为中断的触发源。
12.2 程序设计 12.2.1 HAL库的GPIO驱动 针对本章的实验要求,仅需将对应的GPIO引脚配置为下拉并且上升沿触发中断模式即可,请见第10.2.1小节中配置GPIO引脚的相关内容。 ①: 配置EXTI中断 该函数用于配置NVIC(嵌套向量中断控制器)中外设的中断优先级,因此不仅能用于配置EXTI的中断,还能配置其他外设等的中断,其函数原型如下所示: - void HAL_NVIC_SetPriority( IRQn_Type IRQn,
- uint32_t PreemptPriority,
- uint32_t SubPriority);
复制代码该函数的形参描述,如下表所示: 表12.2.1.1 函数HAL_NVIC_SetPriority()形参描述 该函数的返回值描述,如下表所示: 表12.2.1.2 函数HAL_NVIC_SetPriority()返回值描述 该函数的使用示例,如下所示: - #include"stm32f1xx_hal.h"
- void example_fun(void)
- {
- /* 配置EXTI0的中断优先级 */
- HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
- }
复制代码②: 使能EXTI中断 该函数用于使能NVIC(嵌套向量中断控制器)中外设的中断优先级,因此不仅能用于使能EXTI的中断,还能使能其他外设等的中断,其函数原型如下所示: - void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
复制代码该函数的形参描述,如下表所示: 表12.2.1.3 函数HAL_NVIC_EnableIRQ()形参描述 该函数的返回值描述,如下表所示: 表12.2.1.4 函数HAL_NVIC_EnableIRQ()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- /* 使能EXTI0中断 */
- HAL_NVIC_EnableIRQ(EXTI0_IRQn);
- }
复制代码
12.2.2外部中断驱动 本实验的外部中断驱动主要就是配置GPIO引脚作为EINT的外部中断源,并在其对应的中断回调函数中处理按键被按下后执行的操作。 外部中断驱动中,对GPIO引脚、SYSCFG、EINT的相关定义,如下所示: - #define WKUP_INT_GPIO_PORT GPIOA
- #define WKUP_INT_GPIO_PIN GPIO_PIN_0
- #define WKUP_INT_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOA_CLK_ENABLE(); \
- } while (0)
- #define WKUP_INT_IRQn EXTI0_IRQn
- #define WKUP_INT_IRQHandler EXTI0_IRQHandler
- #define KEY0_INT_GPIO_PORT GPIOA
- #define KEY0_INT_GPIO_PIN GPIO_PIN_15
- #define KEY0_INT_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOA_CLK_ENABLE(); \
- } while (0)
- #define KEY0_INT_IRQn EXTI15_10_IRQn
- #define KEY0_INT_IRQHandler EXTI15_10_IRQHandler
复制代码外部中断驱动中,外部中断的初始化函数,如下所示: - /**
- *@brief 初始化外部中断
- *@param 无
- *@retval 无
- */
- void exti_init(void)
- {
- GPIO_InitTypeDef gpio_init_struct = {0};
-
- /* 使能GPIO端口时钟 */
- WKUP_INT_GPIO_CLK_ENABLE();
- KEY0_INT_GPIO_CLK_ENABLE();
-
- /* 配置WKUP控制引脚 */
- gpio_init_struct.Pin = WKUP_INT_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_IT_RISING;
- gpio_init_struct.Pull = GPIO_PULLDOWN;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(WKUP_INT_GPIO_PORT, &gpio_init_struct);
-
- /* 配置KEY0控制引脚 */
- gpio_init_struct.Pin = KEY0_INT_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_IT_RISING;
- gpio_init_struct.Pull = GPIO_PULLDOWN;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(KEY0_INT_GPIO_PORT, &gpio_init_struct);
-
- /* 配置中断优先级并使能中断 */
- HAL_NVIC_SetPriority(WKUP_INT_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(WKUP_INT_IRQn);
- HAL_NVIC_SetPriority(KEY0_INT_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(KEY0_INT_IRQn);
- }
复制代码在外部中断的初始化函数中,除了使能按键对应GPIO端口的时钟,还配置了对应的EXTI中断。 在外部中断的初始化函数中,开启了两个EXTI的中断,因此需要编写这两个EXTI中断对应的中断回调函数,如下所示: - /**
- *@brief WKUP按键外部中断服务函数
- *@param 无
- *@retval 无
- */
- voidWKUP_INT_IRQHandler(void)
- {
- HAL_GPIO_EXTI_IRQHandler(WKUP_INT_GPIO_PIN);
- }
- /**
- *@brief KEY0按键外部中断服务函数
- *@param 无
- *@retval 无
- */
- voidKEY0_INT_IRQHandler(void)
- {
- HAL_GPIO_EXTI_IRQHandler(KEY0_INT_GPIO_PIN);
- }
- /**
- *@brief HAL库外部中断回调函数
- *@param GPIO_Pin: 外部中断线对应的引脚
- *@retval 无
- */
- voidHAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- /* 机械按键消抖(仅演示,切勿在实际工程的中断服务函数种进行阻塞延时) */
- delay_ms(20);
-
- switch (GPIO_Pin)
- {
- case WKUP_INT_GPIO_PIN: /* WKUP按键对应引脚发生中断 */
- {
- LED0_TOGGLE(); /* 翻转LED0状态 */
- break;
- }
- case KEY0_INT_GPIO_PIN: /* KEY0按键对应引脚发生中断 */
- {
- LED1_TOGGLE(); /* 翻转LED1状态 */
- break;
- }
- }
- }
复制代码在按键被按下的一瞬间,其与MCU连接的GPIO引脚会收到一个上升沿的信号,就会触发EXTI的中断,并运行对应中断回调函数。
12.2.3 实验应用代码 本章实验的应用代码,如下所示: - int main(void)
- {
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 配置时钟,72MHz */
- delay_init(72); /* 初始化延时 */
- usart_init(115200); /* 初始化串口 */
- led_init(); /* 初始化LED */
- exti_init(); /* 初始化外部中断 */
-
- while (1)
- {
-
- }
- }
复制代码本实验的应用代码很简单,在初始化完LED和外部表中断后,就进入一个什么都不做的while循环,这是因为按键控制LED亮灭状态翻转的操作都在对应EXTI的中断回调函数中完成了。
12.3 下载验证 在完成编译和烧录操作后,可以看到板子上的LED0和LED1默认是处于熄灭的状态,若此时按下WKUP按键,则能够看到LED0的亮灭状态发生了一次翻转,同样的,若此时按下KEY0按键,则能够看LED1的亮灭状态发生了一次翻转,与预期的实验现象效果相符。 |