EXTI_STM32

EXTI

一、各类概念简述

  • 中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。
  • 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。
    • 抢占优先级:抢占优先级高的中断允许中断嵌套(即可以打断当前正在运行的中断)。
    • 响应优先级:响应优先级高的优先排队,但不允许中断嵌套(即在当前正在运行的中断运行结束后优先执行)。
    • 抢占优先级和响应优先级均相同的中断,按中断号排队,没有先来后到的说法。
  • 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回(即把中断程序再次中断)。
  • 中断系统:管理和执行中断的逻辑结构。
  • STM32的中断
    • 最多有68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设。其中,EXTI(Extern Interrupt)外部中断,是STM32中能触发中断的众多外设之一。
    • 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,可以设置为抢占优先级或响应优先级。
      EXTI_STM32_第1张图片

二、NVIC

EXTI_STM32_第2张图片

  • 嵌套中断向量控制器,用来统一分配中断优先级和管理中断。
  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级,有以下五种切分方式:
    EXTI_STM32_第3张图片

三、EXTI 原理

3.1 EXTI简述

  • EXTI(Extern Interrupt)外部中断。

  • EXTI的中断源是GPIO口的电平变化。

  • 中断发起流程:EXTI监测指定GPIO口的电平信号 → \rightarrow 指定的GPIO口产生电平变化 → \rightarrow EXTI向NVIC发出中断申请 → \rightarrow NVIC经过裁决 → \rightarrow 中断CPU主程序,使CPU执行EXTI对应的中断程序。

  • 支持的触发方式:上升沿/下降沿/双边沿/软件触发(即没有电平变化,用程序代码触发)。

  • 触发响应方式:中断响应/事件响应

    • 中断响应:申请中断,使CPU停止主程序,执行相应中断程序。
    • 事件响应:EXTI的额外功能,中断源触发时,申请事件,触发其他外设进行操作,而不会通向CPU执行中断。
  • 通道数:共20个中断通道,分别是:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒(因为EXTI能从低功耗模式的停止模式下唤醒STM32)。

  • 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断,因为EXTI的16个GPIO_PIN通道分别对应了16个编号的PIN脚。
    eg:GPIOA_PIN0不能和GPIOB_PIN0同时触发中断,但可以和GPIOA_PIN1同时触发中断。

3.2 EXTI基本结构

EXTI_STM32_第4张图片

  • 因为EXTI只有16个GPIO_PIN的通道,所以需要先经过AFIO进行中断引脚选择。
    • AFIO就是16个7进1出的数据选择器,对PA0、PB0~PG0经过数据选择,取一个连到EXTI0,1-15同理。
  • 注意:EXTI9-5和15-10被分配到了同一个通道中,这意味着他们触发的是同一个中断函数,需要在该函数中用代码区分各个中断。
  • 图右下角即为EXTI的事件响应,它们作用于其他外设,而不经过NVIC和CPU。

3.3 EXTI内部框图

EXTI_STM32_第5张图片

四、配置EXTI(库函数)

4.1 初始化EXTI

'1. 配置RCC,使能需要用到的外设时钟'
// 注意:开启外设时钟的函数是与外设所在的总线对应的,APB1/APB2/AHB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	  // 使能GPIOA口的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	  // 使能AFIO的时钟
//EXTI比较特殊,不需要开启时钟;而NVIC作为内核的外设,也不需要开启时钟(RCC只管内核外的外设)

'2. 配置GPIO'
// 见GPIO章,需设置为输入模式

'3. 配置AFIO'
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource14);		// 选择GPIOA_Pin14作为中断引脚

'4. 配置EXTI'
EXTI_InitTypeDef EXTI_InitStructure;				// 结构体初始化,然后填入结构体
// 填入结构体
EXTI_InitStructure.EXTI_Line = EXTI_Line14;		// 选择需要配置的中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE;		// 选择中断线使能/失能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			// 选择外部中断线的模式(中断模式/事件模式)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		// 选择触发信号的有效边沿(上升沿触发/下降沿触发/双边触发)

EXTI_Init(&EXTI_InitStructure);					// 初始化EXTI

'5. 配置NVIC'
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		// 配置中断优先级的分组方式(整个工程只能用一种分组方式,即整个工程只需要配置一次分组方式)

NVIC_InitTypeDef NVIC_InitStructure;		// 结构体初始化,然后填入结构体
// 填入结构体
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		// 选择中断通道 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				// 选择中断通道使能/失能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	// 指定所选通道的抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			// 指定所选通道的响应优先级

NVIC_Init(&NVIC_InitStructure)// 初始化NVIC

4.2 编写中断函数

在启动文件中找到中断向量表,其中以IRQHandler结尾的字符串就是中断函数的名字

void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line14) == SET):		// 判断指定通道的中断标志位是否为1
	{
		xxx功能块
		EXTI_ClearITPendingBit(EXTI_Line14);		// 清除中断标志位
	}
}

4.3 AFIO常用库函数

void GPIO_AFIODeInit(void); 
		// AFIO复位函数
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
		// 设置引脚重映射;参数一:重映射方式;参数二:新的状态;
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
		// 配置AFIO的数据选择器,选择中断引脚;参数一:GPIO口;参数二:PIN脚数字;

4.4 EXTI常用库函数

void EXTI_DeInit(void);
		// EXTI复位函数
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
		// EXTI初始化函数
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct)// 初始化EXTI结构体,用默认值填充每个EXTI_InitStruct成员
void EXTI_GenerateSWInterrupt(uint_32_t EXTI_Line);
		// 用于软件触发外部中断
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
		// 获取EXTI标志位(和下面的清除函数用于在主函数中操作标志位)
void EXTI_ClearFlag(uint32_t EXTI_Line);
		// 清除EXTI标志位
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
		// 获取中断标志位(和下面的清除函数用于在中断函数中操作标志位)
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
		// 清除中断标志位

4.5 NVIC常用库函数

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
		// 选择中断分组
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
		// 初始化NVIC
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
		// 设置中断向量表
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
		// 系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

五、补充

  • 中断程序所在的子函数不需要人为调用,中断条件触发时由硬件自动调用。
  • 中断向量表:表中记录了STM32的所有中断(内核中断、外设中断)以及各个中断对应的地址。
    • 中断地址的作用是:每当中断条件触发,硬件都会自动跳转到固定地址,但由于编写的中断函数的地址不固定,因此需要在固定地址处再做一个跳转(编译器自动执行,不需要管)。

Reference
STM32入门教程-2023版(江科大)

你可能感兴趣的:(stm32,单片机,嵌入式硬件)