Loading

STM32学习记录(三):外部中断EXTI

外部中断和外部事件的区别

粗略地解释中断和事件的区别:

  • 外部中断(External interrupt),什么是中断?CPU正在执行某个任务时,突然接收到一个中断,CPU将当前正在执行的任务压入栈中,立刻去执行处理该中断(中断函数中处理该中断),中断结束后,返回到上次发生中断的地方继续执行之前的任务。
  • 外部事件(External event),当发生某个事件时,CPU不会立刻去执行,而是在CPU空闲的时候,按照每个事件发生的先后次序依次处理。

大多数情况下都是使用中断,而不是事件。

外部中断线与中断处理函数对应关系

STM32F103C8T6外部中断线与中断处理函数对应关系:

中断线 中断通道 中断处理函数
GPIO_Pin0 EXTI0_IRQn EXTI0_IRQHandler
GPIO_Pin1 EXTI1_IRQn EXTI1_IRQHandler
GPIO_Pin2 EXTI2_IRQn EXTI2_IRQHandler
GPIO_Pin3 EXTI3_IRQn EXTI3_IRQHandler
GPIO_Pin4 EXTI4_IRQn EXTI4_IRQHandler
GPIO_Pin5~GPIO_Pin9 EXTI9_5_IRQn EXTI9_5_IRQHandler
GPIO_Pin15~GPIO_Pin10 EXTI15_10_IRQn EXTI15_10_IRQHandler

GPIO_Pin5~GPIO_Pin9共用一个中断通道,GPIO_Pin10~GPIO_Pin15共用一个中断通道。

启动文件startup_stm32f10x_md.s中已经使用汇编伪指令DCD定义中断处理函数的名称。某些外设要使用中断,只需实现中断函数void PPP_IRQHander(void),其中PPP是外设的名称。

启动文件中的部分汇编代码如下,假设要实现外部中断线4的中断,只需在.c文件中实现void EXTI4_IRQHandler(void)这个函数。 同理,要实现USART1中断,只需实现void USART1_IRQHandler(void)中断处理函数是满足对应的中断条件时自动触发的,用户无需自行调用。

; External Interrupts
DCD     WWDG_IRQHandler            ; Window Watchdog
DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
DCD     TAMPER_IRQHandler          ; Tamper
DCD     RTC_IRQHandler             ; RTC
DCD     FLASH_IRQHandler           ; Flash
DCD     RCC_IRQHandler             ; RCC
DCD     EXTI0_IRQHandler           ; EXTI Line 0
DCD     EXTI1_IRQHandler           ; EXTI Line 1
DCD     EXTI2_IRQHandler           ; EXTI Line 2
DCD     EXTI3_IRQHandler           ; EXTI Line 3
DCD     EXTI4_IRQHandler           ; EXTI Line 4

嵌套向量中断控制器(NVIC)

嵌套向量中断控制器(Nested vectored interrupt controller:NVIC),NVIC的作用就是管理所有中断,包括处理器核心异常。STM32F103C8T6中的NVIC存在于Cortex-M3处理器之中。

《Cortex-M3编程手册》1.3 About the STM32 Cortex®-M3 processor and core peripherals中写道:

Cortex-M3处理器紧密集成了可配置的嵌套中断控制器(NVIC),提供业界领先的中断性能。NVIC包括不可屏蔽中断(NMI),并提供高达256个中断优先级。

每个中断的可编程优先级为0-15。较高的级别对应较低的优先级,因此级别0是最高的中断优先级。NVIC将优先级值分组为组优先级(group priority)和次优先级(subpriority)字段。在STM32F10x固件库中的misc.h文件中说明了NVIC的分组情况:

image

举个例子,可以看到当分组为NVIC_PriorityGroup_2时,抢占优先级可以设置为0~3,次优先级可以设置为0~3。

有关中断向量表的具体内容参见《STM32F10x参考手册》。

外部中断配置流程

外部中断(EXTI)配置就是一个套路,按照对应的套路配置即可,配置流程图如下:

flowchart TB id["开启GPIO和AFIO时钟"] --> id1["配置GPIO初始化结构体"] -->id2["配置外部中断源"] --> id3["配置外部中断初始化结构体"] -->id4["设置NVIC优先级分组、配置NVIC初始化结构体"]

举个例子,配置PB11作为外部中断的程序如下:

/* 开始AFIO时钟和GPIOB时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);

/* GPIO结构体配置 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* 配置中断源为PB11 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,  GPIO_PinSource11);

/* 外部中断初始化结构体配置 */
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line11;				//外部中断线11
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;		//外部中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;				//使能外部中断
EXTI_Init(&EXTI_InitStructure);

/* 设置NIVC优先级分组 */
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);

/* NIVC初始化结构体配置 */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;		//NVIC_IRQChannel取值参考stm32f10x.h文件
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//次优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

按键控制LED

需求

使用外部中断的方式实现按键控制LED灯的亮灭

分析

GPIO控制LED灯,使用推挽输出即可。如表格所示,使用外部输入中断,GPIO要配置成浮空输入、上拉输入或下拉输入。STM32F103C8T6芯片中内置有上拉电阻,因此按键可以配置成上拉输入,让GPIO默认输出高电平。要使用外部中断必须打开AFIO的时钟,AFIO即Alternate-Function I/O,IO口的复用功能

image

程序

int main(void)
{
	LED_Init();
	EXIT1_Init();

	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	while (1)
	{
		
	}
}

/* 初始化连接LED的GPIO */
void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/**
 * @brief 初始化外部中断0
 * @details EXTI中断线与GPIO是一一对应关系
 * 
 * 中断线5~9公用一个中断通道,10~15公用一个中断通道
 * 
 * 	中断线						中断通道			 中断处理
 * 	GPIO_Pin0	    			EXTI0_IRQn     		EXTI0_IRQHandler
 * 	GPIO_Pin1	    			EXTI1_IRQn     		EXTI1_IRQHandler
 *  GPIO_Pin2	    			EXTI2_IRQn     		EXTI2_IRQHandler
 * 	GPIO_Pin3	    			EXTI3_IRQn     		EXTI3_IRQHandler
 * 	GPIO_Pin4	    			EXTI4_IRQn     		EXTI4_IRQHandler
 * 	GPIO_Pin5-GPIO_Pin9	    	EXTI9_5_IRQn     	EXTI9_5_IRQHandler
 * 	GPIO_Pin15-GPIO_Pin10	    EXTI15_10_IRQn      EXTI15_10_IRQHandler
 * 
 */
void EXIT1_Init(void)
{
	/* 开始AFIO时钟和GPIO时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
	
	/* GPIO结构体初始化 */
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/* 配置中断源为PB1 */
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,  GPIO_PinSource1);

	/* 外部中断结构体初始化 */
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line1;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;	
	EXTI_Init(&EXTI_InitStructure);
	
	/* 设置NIVC优先级分组 */
	NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);

	/* NIVC初始化 */
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/**
 * 外部中断1处理函数,中断函数参照启动文件startup_stm32f10x_md.s中定义的函数名
 * 
 */
void EXTI1_IRQHandler(void)
{
	// delay_ms(10);	//消除抖动
	if(EXTI_GetFlagStatus(EXTI_Line1) != RESET)	//检测到触发条件时,Pending bit被置为1
	{
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == RESET)
			GPIO_SetBits(GPIOA, GPIO_Pin_0);	//关闭LED灯
		else
			GPIO_ResetBits(GPIOA, GPIO_Pin_0);	//打开LED灯
		EXTI_ClearITPendingBit(EXTI_Line1);	 //清空EXTI1的中断请求Pending bit
	}
}

参考资料

《STM32F10x参考手册》

《Cortex-M3编程手册》

posted @ 2024-08-05 23:51  记录学习的Lyx  阅读(211)  评论(0编辑  收藏  举报