普冉(PUYA)单片机开发笔记(12): 获取外部中断
概述
将单片机的 GPIO 引脚作为外部按键的输入端是单片机较为常用的方式,例如把这颗 MCU 部署在一块控制面板的触点底板,使用者按压按钮(按键)对产品进行控制。本着学以致用的原则,使用 PY32F003 对外部中断如何处理是一项必须完成的学习内容了。今天我们就来操练一把。
参考厂家的例程,使用 PA12 作为外部中断的输入管脚,掌握一下 PY32F003 对外部中断处理的代码。PA12 设置为突变检测,当 PA12 上产生高低电平的变化时,翻转一次板载 LED 可以验证 MCU 是否正确捕捉了外部中断。
在我的这一个系列的实验,Keil 的文件组织都是沿用下来的,请参见我的任意一期《开发笔记》,这里就不罗嗦了,直接上代码。
实现代码
1. 在 main.h 中加一个预定义,然后定义和外部中断相关的函数原型
代码片段如下。
#define TIM_PWM_TEST 0
#define ADC_SAMPLE_TEST 0
#define FLASH_WR_TEST 0
#define I2C_COMM_TEST 0
#define I2C_SLAVE 0
#define EXTI_TEST 1
...
...
#if(EXTI_TEST)
void EXTI_Config(void);
void EXTI_Demo(void);
#endif
...
...
文件新定义了预编译开关: EXTI_TEST,其它的开关全部设置为 0(关掉其它功能,免得产生冲突)。然后声明了 Config 和 Demo 两个函数。
2. app_exti.c 中实现相关函数
这一次我们将获取外部中断的相关函数都写到 app_exti.c 这一个文件中,包括 main.h 中预定义的 EXTI_Config() 函数,HAL_EXTI_MspInit() 函数和 EXTI4_15_IRQHandler() 函数,酱紫就不需要再“麻烦” 去修改 py32_f0xx_hal_msp.c 文件了。
完整代码如下。
/**
******************************************************************************
* @file app_exti.c
* @brief External Interrupt test functions.
******************************************************************************
* @copyright
*
* Copyright (c) 2023 CuteModem Intelligence.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "main.h"
#if(EXTI_TEST)
/** ----------------------------------------------------------------------------
* @name : void EXTI_Config(void)
* @brief : EXTI 初始化, 配置引脚 PA12 为下降沿中断
* @param :
* @retval : void
* @remark :
*** ----------------------------------------------------------------------------
*/
void EXTI_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿中断
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 速度为高速
GPIO_InitStruct.Pin = GPIO_PIN_12;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn); // 使能EXTI中断
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0); // 配置中断优先级
}
/** ----------------------------------------------------------------------------
* @name : void EXTI4_15_IRQHandler(void)
* @brief : EXTI 初始化, 配置事件引脚 PA12
* @param : 每产生一次下降沿, LED翻转一次
* @retval : void
* @remark :
*** ----------------------------------------------------------------------------
*/
void EXTI4_15_IRQHandler(void)
{
BSP_LED_Toggle(LED3);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);//处理EXTI中断请求
}
/** ----------------------------------------------------------------------------
* @name : void EXTI_Demo(void);
* @brief : 由 main() 调用的外部中断实验程序
* @param :
* @retval : void
* @remark :
*** ----------------------------------------------------------------------------
*/
void EXTI_Demo(void)
{
EXTI_Config();
}
#endif
- 使用 EXTI_Config() 函数分配 PA12 为外部中断源,内部上拉,下降沿中断,GPIO 高速。
- 使用 EXTI4_15 中断,设置成 0 组最高优先级。
- 在 EXT4_15中断服务程序中,翻转板载 LED 一次,然后调用 HAL_GPIO_EXTI_IRQHandler(GPIO_Pinx) 函数清除这个 GPIO 的中断标志,以便下一次捕获。
- 定义了一个非常简单的 Demo 函数。
3. 修改一下 py32_f0xx_hal_it.c
已经在 app_exti.c 中实现了 EXTI_15_IRQ4_Handler,所以在 py32_f0xx_hal_it.c 中把那个函数关掉。
请注意这里不能重复定义其为 __weak 类型,这么做不会导致编译错误,但程序运行时会卡死。
/**
******************************************************************************
* @file py32f0xx_it.c
* @author MCU Application Team
* @Version V1.0.0
* @Date 2020-10-19
* @brief Interrupt Service Routines.
******************************************************************************
*/
...
...
#if(!EXTI_TEST)
void EXTI4_15_IRQHandler(void)
{
}
#endif
...
...
4. 在 main() 函数中调用
/**
******************************************************************************
* @file main.c
* @brief Main program entry.
******************************************************************************
...
...
*
******************************************************************************
*/
#include "main.h"
#include <stdio.h>
/**
* -------------------------------------------------------------------------
* @file : int main(void)
* @brief : main函数
* @param : 无
* @retval : 无限循环,无返回值
* @remark :
* -------------------------------------------------------------------------
*/
int main(void)
{
HAL_Init(); // systick初始化
SystemClock_Config(); // 配置系统时钟
if(USART_Config() != HAL_OK) Error_Handler();
printf("\r\n\r\n\r\n"
"[SYS_INIT] Debug port initilaized.\r\n");
printf("\r\n+---------------------------------------+"
"\r\n| PY32F003 MCU is ready. |"
"\r\n+---------------------------------------+"
"\r\n 10 digits sent to you! "
"\r\n+---------------------------------------+"
"\r\n");
HAL_Delay(0);
if (DBG_UART_Start() != HAL_OK) Error_Handler();
HAL_Delay(0);
#if(EXTI_TEST)
EXTI_Config();
#endif
while (1)
{
#if(!EXTI_TEST)
BSP_LED_Toggle(LED3);
HAL_Delay(500);
#endif
}
}
程序很短,如果不考虑打印的话,只需要 HAL_Init(); SystemClock_Config(); 和 EXTI_Config(); 三个函数。主循环用 #if(!EXTI_TEST)关掉了,实际上是空的。
实验结果
编译烧录后,使用一根杜邦线连接 PA12 引脚,杜邦线的另一头接上 GND,反复插拔,观察板载 LED 的明灭。可以发现板载 LED 随着杜邦线的插拔一明一灭,说明实验是成功了的。
总结
- 使用 PY32F003 的外部中断功能的配置很简单。
- 如果使用 GPIO 的高速模式,对捕获外部中断有好处,但要避免插拔抖动造成的多次触发。实测使用 GPIO_SPEED_FREQ_VERY_HIGH 时,一次接触会产生 LED 的多次明灭;使用 GPIO_SPEED_FREQ_MEDIUM 时,好像又有点丢失的感觉。在实用设计中,在使用 HIGH 或者 VERY_HIGH 的同时,应该加一套时间常数较为合适的 RC 低通电路用于防抖。
本实验只是完成了一个管脚作为外部中断源的捕获,如果有多个的话,想来可能大同小异吧,毕竟芯片的 NVIC 构架是相同的。
谬误之处,欢迎在评论区讨论指正。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!