GPIO外部中断

STM32的“中断”机制很复杂,看了PM(Cortex-m4)和RM,对它只了解了一个大概。首先,与“中断”相关的术语就有 exception, interrupt, event 三个。Cortex-m4核中包含一个NVIC控制器,用于处理 exception。而 interrupt 是属于 exception 之一种,其它 exception 类型包括 SysTick等。interrupt 又叫作IRQ。

STM32之中、Cortex-m4核之外的“中断”,即为 interrupt/IRQ。STM32通过 IRQ Channel 向 NVIC 请求处理 IRQ,而 NVIC 处理包括 IRQ 在内的各种 exception,例如:优先级...等等。对于 IRQ,NVIC 将调用其“中断处理程序” ISR。

有些 STM32 外围接口直接通过 IRQ Channel 与 NVIC 接口,而 GPIO 外部中断则要通过另一个控制器--EXTI--与NVIC接口。GPIO与 EXTI 之间的接口称为 EXTI line;而 EXTI 与 NVIC之间则为 IRQ Channel。GPIO pin与EXTI line之间是n:1的关系,而EXTI line与 IRQ Channel之间也是n:1的关系。基本上,PXn 对应 EXTI line n,这里X=A, B, ... H,n=0, 1, 2 ... 15。例如,PX2(PA2, PB2 ...)都对应于 EXTI line 2。

EXTI line与 IRQ Channel之间的对应关系则稍微复杂,16个 EXTI line 占用7个 IRQ:

  • EXTI line 0 - 4 分别对应一个IRQ,因此,共有5个 IRQ
  • EXTI line 5 - 9 共用一个IRQ
  • EXTI line 10 - 15 共用一个IRQ

此外,EXTI line 上除了支持 interrupt 之外,还支持 event。event 被触发之后,并不传递给 NVIC 去处理(像 IRQ 那样),而是发送一个脉冲给电源管理模块,似乎是用来实现唤醒功能的。

GPIO、EXTI 与 NVIC 之间的关系,用下图简单表示:

因此,对于编程而言,需要对GPIO、EXTI、NVIC 3个模块分别进行配置和操作。所幸,Cube HAL 以及 CubeMX 工具大大地降低了开发的复杂度。

Nucleo 开发板上有一个用户按钮B1和一个用户LED LD2,可以用它们来实现一个简单的 GPIO 外部中断 Demo。Nucleo 原理图显示,B1 进行了 RC de-bouncing,因此可以作为外部中断源。未经 de-bouncing 的按钮,是不应该触发中断的。B1接在 PC13 口,已经设计了上拉电阻:

使用CubeMX,将B1口模式设置为 GPIO_EXIT13。可见,PC13 使用了 EXTI line 13。另外,由于使用了上拉电阻,选择中断为下降沿触发:

这样,GPIO和 EXTI 就配置好了。别忘了还需要配置 NVIC。这里只需要简单地启用它对应的 IRQ即可,其余保持默认:

简要分析一下 CubeMX 生成的代码。首先,中断向量表定义在启动代码 startup_stm32f303xe.s 中,在这个文件中可以看到所有 exception 处理程序(函数名),包括 EXTI ISR:

g_pfnVectors:
	.word	_estack
	.word	Reset_Handler
	.word	NMI_Handler
	...
	.word	SysTick_Handler
	...
	.word	EXTI0_IRQHandler
	.word	EXTI1_IRQHandler
	.word	EXTI2_TSC_IRQHandler
	.word	EXTI3_IRQHandler
	.word	EXTI4_IRQHandler
	...
	.word	EXTI9_5_IRQHandler
	....
	.word	EXTI15_10_IRQHandler
	....

  

其中,EXTI15_10_IRQHandler 就是按钮B1的中断处理程序。这个函数的实现在 stm32f3xx_it.c 中,它实际上仅仅调用了 Cube 库的 HAL_GPIO_EXTI_IRQHandler() 函数,将端口号作为参数传递进去:

/**
* @brief This function handles EXTI line[15:10] interrupts.
*/
void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */

  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */

  /* USER CODE END EXTI15_10_IRQn 1 */
}

  

检查 HAL_GPIO_EXTI_IRQHandler() 函数的实现,发现它位于 GPIO HAL 模块内,它又调用了一个回调函数 HAL_GPIO_EXTI_Callback(),而该回调函数的默认实现声明为 __weak 属性,我们可以覆盖:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
   ...

  

因此,我们在 stm32f3xx_it.c 增加 HAL_GPIO_EXTI_Callback() 的实现,每当B1按下,开/关LD2:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
}

  

另外,在gpio.c 中的 MX_GPIO_Init() 函数中,看到了 NVIC 的配置,但并没有看到与 EXTI 有关的配置。其实,EXTI 配置已由 HAL_GPIO_Init() 函数处理,不劳我们费心。也就是说,对 GPIO 的外部中断的处理,要使用 GPIO 和 NVIC 2个Cube 模块:

  ...
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
  ...
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

  

原文地址:https://www.cnblogs.com/vinccc/p/8273559.html

时间: 2024-07-31 19:33:33

GPIO外部中断的相关文章

基于STM32F0的GPIO外部中断

背景:项目中需要使用hall传感器检测门锁状态,触发中断,发送门锁状态信息.(这儿中断服务中只是点了led灯说明了状况) 硬件情况:采用PB3管脚,因而使用中断线:EXTI_Line3和中断服务函数:EXTI2_3_IRQn. 具体过程: 1.设置中断时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 2.配置GPIO GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCm

嵌入式外部中断控制编程方法论—比較CC2541(51核)和S5PV210(ARM核)

这是一篇阐述怎样对嵌入式SOC外部中断进行控制编程的方法论文章.希望读者理解本篇文章后.能够具备对市场上全部已经面世和将来面世的嵌入式芯片的外部中断进行控制编程的能力. 笔者原创的技术分享一直都恪守下面原则: 从需求的角度去理解嵌入式各种软件和硬件模块的作用和组成.并从芯片系统设计的角度去阐述怎样进行控制编程. 前者对于理解复杂的系统(如linux的各个子系统)是非常有效的:后者所讲的是代表一个芯片设计project师的视觉,芯片模块由他负责设计,他对于该模块的控制编程自然是最有发言权的. 笔者

外部中断的使用

STM32学习笔记:外部中断的使用 中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大大增加,而且中断的设置也更加复杂.今天就将来探讨一下关于STM32中的中断系统. 1 基本概念 ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置.STM32目前支持的中断共84个(16个内部+68个外部),还有16级可编

LPC1768外部中断与GPIO中断

LPC1768的外部中断严格来说只有四个,分别是EINT0,EINT1,EINT2,EINT3,技术手册上有如下说明 控制这四个外部中断靠以下寄存器 这三个寄存器的0 1 2 3位分别代表中断的0 1 2 3,EXTINT寄存器表示中断是否发生,在发生中断的时候该寄存器会置位,可以通过写1清零,EXTMODE寄存器表示触发模式,有电平触发和变化沿触发两种,EXTPOLAR与EXTMODE,在电平触发模式下,决定高电平还是低电平触发,在变化沿触发的情况下决定上升沿还是下降沿触发 这三个中断分别相关

LPC1788的外部中断和GPIO中断

首先是gpio中断,这一点和1768不同,1768使用的中断时和eint3共用中断通道,到了1788,专门为gpio开辟了中断 #ifndef __JOYPAD_H_ #define __JOYPAD_H_ #include "sys.h" #include "delay.h" #define JOYPAD_A        0X01 #define JOYPAD_B        0X02 #define JOYPAD_C        0X03 #define

GPIO和外部中断/时间控制器(EXTI)

2.1          GPIO的8种工作模式 GPIO工作图如下: 4种输入模式 结构图的上半部分分为输入模式结构, 分为上拉模式,下拉模式,浮空模式和模拟输入模式. 上/下拉模式:通过设置配置寄存器(CRL,CRH)来控制1和2开关,于是得到GPIO的上拉输入模式(GPIO_Mode_IPU)和下拉输入模式(GPIO_Mode_IPD). 浮空输入模式(GPIO_Mode_IN_FLOATING):没有接上下拉电阻,经由TTL施密特触发器输入. 配置成这个模式直接用电压表测量其引脚电压为1

STM32基本GPIO操作:按键输入(扫描+外部中断)

(涉及专有名词较多,难免解释不到位,若有错误还请指出,谢谢!) 硬件连接图如下: 一.扫描 思路是在main函数中通过死循环来扫描端口电平状态检测,以此判断按键是否按下.实现较为简单. 1.初始化(注意C语言中变量声明需放在函数开头) 以下是初始化PB5端口(LED灯)的代码,每一条语句的含义在我另一篇博客里 GPIO_InitTypeDef GPIO_Init1; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_Init1.

《零死角玩转STM32》-17-EXTI外部中断/事件控制器

/* * 本文中的相关图片来自火哥的教程,只作为随笔记录,无侵权之意 * 21:25:46, 2017-04-08 */ EXTI:外部中断/事件控制器.STM32F429共有23根,其中EXTI0~EXTI15,分别对应GPIO中的PX0 ~ PX15,另外7根线有如下用途: (中间省略了EXTI1 ~ EXTI15) EXTI功能框图如下所示: 按照图中的序号标识,可以清晰的看出外部GPIO引脚上的电平变化是如何传递到内核,即GPIO -> EXTI -> NVIC,并触发相应的中断/事件

中断之外部中断

. ARM Cortex M3共有256个中断. STM32F103CB共有43个外部中断和16个内部中断. 具有相同数值编号的IO口被分配为同一组,共用一条中断请求线,如下图: 所以共有15条中断线,另外 ●EXTI线16连接到PVD输出●EXTI线17连接到RTC闹钟事件●EXTI线18连接到USB唤醒事件 寄存器:1.外部中断配置寄存器    AFIO_EXTxCR1------->用于选择输入中断源  Pin 0..3 AFIO_EXTxCR2------->用于选择输入中断源  Pi