EXTI外部中断

文章详细介绍了STM32中的中断系统,包括外部中断(EXTI)、NVIC中断控制器以及AFIO复用功能。EXTI用于检测GPIO口的电平变化,支持多种触发方式。NVIC管理中断优先级,处理中断嵌套。文中还给出了EXTI中断在旋转编码器和对射式红外传感器中的应用实例,展示了如何初始化中断和处理程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.中断系统

外部中断是指来自CPU外部的突发事件所引发的中断。这些事件可能是硬件设备的信号,如定时器到期、键盘输入、数据输入/输出操作完成,或者其他外部信号。当CPU接收到外部中断信号时,它会暂停当前执行的程序,并立即跳转到中断处理程序中执行响应的处理程序。外部中断是计算机系统中常见的一种异步事件处理机制,它可以帮助处理时间敏感的任务。

中断优先级:当多个中断源同时申请中断时,CPU根据中断的轻重缓急进行分析,优先处理紧急的中断。

中断嵌套:在执行一个中断程序时又来了个优先级更高的中断,则CPU会停止当前执行的中断程序,去执行优先级更高的中断,处理完成后继续上一个中断。

在stm32中,有68个可屏蔽中断通道,包括EXTI、TIM、ADC等多个外设。通过NVIC统一管理中断,NVIC主要控制中断优先级,对于外部中断有16个优先级,0优先级最高,15最低。

2.NVIC介绍

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的相应优先级。抢占优先级高度的可以中断嵌套,相应优先级高的可以优先排队,抢占优先级和相应优先级均相同的按中断号排队。
相应优先级:相当于诊所诊断完上一个病人空闲时(外面有人排队)可以直接插队进去诊断。
抢占优先级:相当于诊所中虽然有病人在诊断,但是能一脚把别人踹一边,直接让医生诊断自己,自己诊断完后再继续诊断被踹一边的病人。

3.EXTI介绍

 EXTI通过检测GPIO口的电平变化,向NVIC发出中断申请,经过NVIC处理后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。
支持的触发方式:上升沿/下降沿/双边沿/软件触发;
支持的GPIO口:所有GPIO口,但相同的PIN不能同时触发中断
通道数:16个GPIO_Pin,外加VD输出,RTC闹钟,USB唤醒,以太网唤醒
触发响应方式:中断响应/事件响应

EXTI基本结构

从GPIO口发出电平信号,AFIO进行中断引脚选择(选择16个) ,EXTI控制触发方式、触发响应方式和Pin口选择,NVIC进行将分组和响应优先级、抢占优先级配置。

4.AFIO介绍

AFIO主要功能主要有:复用功能引脚重映射、中断引脚选择。

5.使用EXTI中断实现功能的模块

本文章EXTI外部中断主要配合旋转编码器和对射式红外传感器使用。因为旋转编码器和对射式红外传感器的电平信号是持续变化的,没有中断的情况下,上一个传入的信号没处理完成,下一个信号就随之而来,导致信号处理不及时而产生错误。

旋转编码器:
旋转编码器是一种用于测量旋转角度和转速的传感器。它通常由旋转部分、编码器芯片和接口电路组成。
旋转部分通常由两个旋转部件组成,它们通过一个凸起的轴相互连接。当旋转轴旋转时,旋转部件也跟随旋转,使两个部件之间的距离发生变化。编码器芯片通过对这种距离变化的检测来计算旋转角度和转速。
接口电路通常包括数字电路和模拟电路。数字电路通常将编码器输出转换为数字信号,供外部系统使用。模拟电路通常将编码器输出转换为数字信号后,将其转换为模拟信号,以便用于控制系统。

6.具体代码

1.对射式红外传感器计次

/*
    模块CountSensor.c
*/

#include "stm32f10x.h"                  // Device header

uint16_t CountSensor_Count;

/**
  * @brief EXTI外部中断初始化
  * @param 无
  * @retval 无
  */
void CountSensor_Init(void)
{
	//GPIO、AFIO定时器启动
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	//GPIOB配置
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//AFIO配置
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
	
	//EXTI配置
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;  	//配置GPIO_Pin_14作为中断电平信号判断口
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;    	//启用EXTI
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	//配置为中断相应
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //配置为下降沿触发
	EXTI_Init(&EXTI_InitStructure);
	
	//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);
}

/**
  * @brief 返回记录的次数
  * @param 无
  * @retval CountSensor_Count 记录的次数
  */
uint16_t GetCountSensor_Count(void)
{
	return CountSensor_Count;
}

/**
  * @brief 中断程序
  * @param 无
  * @retval 无
  */
void EXTI15_10_IRQHandler(void)
{
    //判断是否中断程序被正确执行
	if(EXTI_GetITStatus(EXTI_Line14) == SET)
	{
        //通过判断Pin口电平,提高信号捕捉准确率
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == 0)
			CountSensor_Count++;
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
}

需要配合OLED模块(B站江协科技有提供)

/*
    main.c模块
*/

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "CountSensor.h"

uint16_t Count;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1,1,"Count:");
	CountSensor_Init();
	while(1)
	{
		Count = GetCountSensor_Count();
		OLED_ShowNum(1,7,Count,4);
	}
}

2.旋转编码器实现正反旋转计次

/*
    Encoder.c模块
*/

#include "stm32f10x.h"                  // Device header

int16_t Encoder_Count;

void Encoder_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_InitStructure);
	
}

int16_t Encoder_Get(void)
{
//	int16_t Temp;
//	Temp = Encoder_Count;
//	Encoder_Count = 0;
//	return Temp;
	return Encoder_Count;
}

void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0) == SET)
	{
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
		{
			if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
			{
				Encoder_Count--;
			}	
		}

		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}

void EXTI1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line1) == SET)
	{
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
			{
				Encoder_Count++;
			}
		}
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

同样要配合OLED模块

/*
    main.c模块
*/

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Encoder.h"

int16_t Num;

int main(void)
{
	OLED_Init();
	Encoder_Init();
	OLED_ShowString(1,1,"Num:");
	while(1)
	{
		Num = Encoder_Get();
		OLED_ShowSignedNum(1,5,Num,5);
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值