STM32——外部中断

0.中断关系映射

STM32F103 的中断控制器支持 19
个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F103 的 19 个外部中断为:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
从上面可以看出,STM32F1 供 IO 口使用的中断线只有 16 个,但是 STM32F1 的 IO 口却 远远不止 16 个,那么 STM32F1 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32 就这样设计,GPIO 的管教 GPIOx.0-GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线 0~15。这 样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、 GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要 通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO 跟中断线的映射关系图:
在这里插入图片描述

1.使能 IO 口时钟,初始化 IO 口为输入

__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();

2.设置 IO 口模式,触发条件,开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系。

GPIO_InitTypeDef GPIO_Initure; 
GPIO_Initure.Pin=GPIO_PIN_0; //PA0 
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //外部中断,上升沿触发 
GPIO_Initure.Pull=GPIO_PULLDOWN; //默认下拉 
HAL_GPIO_Init(GPIOA,&GPIO_Initure); 

当我们调用 HAL_GPIO_Init 设置 IO 的 Mode 值为 GPIO_MODE_IT_RISING(外部中断上 升 沿 触 发 ), GPIO_MODE_IT_FALLING ( 外 部 中 断 下 降 沿 触 发 ) 或 者 GPIO_MODE_IT_RISING_FALLING(外部中断双边沿触发)的时候,该函数内部会通过判断 Mode 的值来开启 SYSCFG 时钟,并且设置 IO 口和中断线的映射关系。
此时如果有新的IO口在同一条中断线上映射,后面的会覆盖前面的,比如,此时PA0已经初始化了上升沿触发的中断线0,如果再配置PB0,就会清除PA0的中断配置,改为PB0,

3.配置NVIC优先级管理,并使能中断

HAL_NVIC_SetPriority(EXTI0_IRQn,2,0); //抢占优先级为 2,子优先级为 0 
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线 2 

4.编写中断服务函数。

我们配置完中断优先级之后,接着要做的就是编写中断服务函数。中断服务函数的名字是
在 HAL 库中事先有定义的。这里需要说明一下,STM32F1 的 IO 口外部中断函数只有 7 个,分
别为:

void EXTI0_IRQHandler(); 
void EXTI1_IRQHandler(); 
void EXTI2_IRQHandler(); 
void EXTI3_IRQHandler(); 
void EXTI4_IRQHandler(); 
void EXTI9_5_IRQHandler(); 
void EXTI15_10_IRQHandler(); 

中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中
断线 10-15 共用中断函数 EXTI15_10_IRQHandler

5.编写中断处理回调函数 HAL_GPIO_EXTI_Callback

我之前使用标准库开发的时候,对中断服务函数中直接编写逻辑,清除中断标志位,然后写中断对应的引脚功能。但是HAL库对后面所说的“中断对应引脚功能代码编写”又进行了库函数的封装,即HAL_GPIO_EXIT_Callback()回调函数。
那么在HAL库中的中断服务函数是:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) 
{ 
	if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u) 
	{ 
		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); 
		HAL_GPIO_EXTI_Callback(GPIO_Pin); 
	} 
} 

然后我们把中断功能的编写写在Callback回调函数中。
这个中断标志位是在中断触发的时候,硬件中断控制器就会设置中断标志位,我们进入中断服务函数先将中断标志位清除,表示正在处理这个中断,防止重复触发同一个中断,保证这个中断每次响应后只处理一次。

### STM32按键中的实现方法及常见问题解决方案 #### 一、STM32按键中的基础概念 在STM32微控制器中,按键中是一种通过外部设备触发CPU响应的方式。当中发生时,处理器会暂停当前的任务并跳转到相应的中服务程序(Interrupt Service Routine, ISR)[^1]。 为了确保按键操作能够被准确识别而不受机械抖动的影响,通常需要加入消抖机制。可以通过硬件或软件的方式来完成这一目标[^3]。 #### 二、按键中的具体实现流程 以下是基于STM32的按键中实现的一个典型例子: ##### 1. 初始化GPIO端口 首先需配置用于检测按键状态的GPIO引脚为输入模式,并启用上拉/下拉电阻以稳定电平信号。 ```c void GPIO_Init(void){ __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发中 GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` ##### 2. 配置NVIC (Nested Vectored Interrupt Controller) 使能对应外设的中线并向量表映射地址设置好之后才能接收到来自该源发出的通知请求。 ```c void NVIC_Configuration(void){ HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); } ``` ##### 3. 编写中服务程序(ISR) 当指定条件满足时即会产生一个异常事件进而激活下面定义好的函数体部分来进行相应处理逻辑编码工作。 ```c void EXTI0_IRQHandler(void){ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin == GPIO_PIN_0){ Key_Short_Pro(); // 调用短按处理函数 } } ``` 以上代码片段展示了如何初始化GPIO以及配置相关的中向量控制单元(NVIC),同时还给出了简单的ISR框架结构供参考使用[^1]。 #### 三、解决按键中中的常见问题 尽管上述步骤可以成功建立基本的功能模块,但在实际应用过程中可能会遇到一些挑战或者错误情况的发生。这里列举几个常见的案例及其可能的原因分析与对策建议: - **问题**: 当按下某个按钮后系统进入死循环无法正常退出. - 可能原因: 如果存在未清除标志位的情况,则每次都会重复触发相同的中直到堆栈溢出为止。 - 解决方案: 确保每一次进入ISRs之前都将关联的状态变量重置回初始值;另外也可以考虑适当增加延时语句以便给予足够的反应时间给外围器件恢复平静再继续下一步骤的操作[^2]. - **问题**: 使用定时器配合按键扫描发现长时间按住某键会出现多次计数的现象。 - 可能原因: 定时期间如果持续监测到低电平时就会不累加计数值造成误判。 - 解决方案: 引入额外的状态标记区分首次下降沿捕捉与其他后续动作的区别对待即可有效避免此类状况出现[^4]. - **问题**: 在调用了`HAL_Delay()`期间似乎忽略了来自外部的紧急事务通知而导致延迟响应甚至丢失某些重要数据包传输机会等问题的存在。 - 可能原因: 默认情况下SysTick timer 的抢占级别较低不足以打正在进行中的阻塞型APIs如 `HAL_Delay()`. - 解决方案: 提高SysTick interrupt priority level使之高于其他常规任务从而允许即时介入调整调度顺序达成实时性的需求标准[^5]. #### 结论 通过对STM32按键中的学习我们可以了解到其背后涉及到的知识点广泛而且深入细致之处颇多值得我们去探索研究。只有掌握了这些核心原理才能够灵活运用它们构建更加复杂可靠的电子控制系统出来服务于各行各业的实际应用场景之中。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值