02:STM32--EXTI外部中断

目录

一:中断

1:简历

2:AFIO

3:EXTI

​编辑

4:NVIC基本结构

5:使用步骤

二:中断的应用

A:对外式红外传感计数器

1:连接图​编辑

2:函数介绍

3:硬件介绍

4:计数代码

B;旋转编码计数器

1:连接图

2:硬件介绍

3:旋转编码器代码:


一:中断

1:简历

中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回

STM32中断: 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级 (EXTI可以产生中断的,众多外设之一)

2:AFIO

使用这个函数GPIO_EXTILineConfig配置那个引脚为中断引脚: 调用这个函数,就可以配置AFIO的数据选择器,来选择我们想要的中断引脚

AFIO主要用于引脚复用功能的选择和重定义

在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择

3:EXTI

EXTI_Init:

调用这个函数,就可以根据这个结构体里的参数配置EXTI外设, 使用方法和GPIO Init也是一样;

选择那个IO口为中断IO口(和前面的AFIO引脚配置保持一致),

选择那个方式触发中断(中断模式,事件模式)

选择触发中断的方式 (上升沿触发,下降沿触发,上升沿和下降沿触发)

EXTI简介:

EXTI(Extern Interrupt)外部中断

EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序

支持的触发方式:上升沿/下降沿/双边沿/软件触发

支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断 (PA1、PB1、PC1这样的,PAO和PBO这样的相同的Pin只能选1个作为中断引脚) PA6和PA7、PA9和PB15、PBO和PB1这样的都可以

原因:AFOI会在APIOA,APIO,APIOC中选择一个GPIO的16个引脚连接到后面的EXTI

通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒

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

基本结构:

EXTI框图

4:NVIC基本结构

嵌套中断向量控制器: 用来统一分配断优先级和管理中断的

A:使用NVIC_PriorityGroupConfig函数先分组;分组完成后抢占优先级和响应优先级的号不能超过表中的范围

B:使用NVIC_Init初始化 (1:选择通道,选择抢占优先级和响应优先级)

NVIC优先级分组:

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级(更加紧急) 和低4-n位的响应优先级(紧急) 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队 (中断号:EXTI简历中的优先级)

抢占优先级>响应优先级

优先级的数是值越小,优先级越高,0就是最高优先级

5:使用步骤

1:第一步,配置RCC,把我们这里涉及的外设的时钟都打开(GPIO,AFIO)

2:第二步,配置GPIO,选择我们的端口为输入模式

3:第三步,配置AFIO,选择我们用的这一路GPIO,连接到后面的EXT

4:第四步,配置EXTI,选择边沿触发方式比如上升沿、下降沿或者双边沿, 还有选择触发响应方式,可以选择中断响应和事件响应

5:第五步,配置NVIC,给我们这个中断选择一个合适的优先级

最后,通过NVIC,外部中断信号就能进入CPU了

1:EXIT和NVIC的时钟一直是打开状态不需要开启

二:中断的应用

A:对外式红外传感计数器

1:连接图

2:函数介绍

配置AFIO在文件中stm32f10x_gpio.h

void GPIO_AFIODeInit(void);

void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

void GPIO_EventOutputCmd(FunctionalState NewState);

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

GPIO_AFIODeInit: 用来复位AFIO外设,调用这个函数AFIO外设的配置就会全部清除

GPIO_PinLockConfig: 参数指定位那个引脚, 那这个引脚的配置就会被锁定,防止意外更改

**GPIO_EventOutputConfig 和GPIO_EventOutputCmd :**配置AFIO的事件输出功能的

**GPIO_PinRemapConfig:**引脚重新映射, 第一个参数可以选择你要重映射的方式,第二个参数是新的状态

GPIO_EXTILineConfig: 调用这个函数,就可以配置AFIO的数据选择器,来选择我们想要的中断引脚

GPIO_ETH_MediaInterfaceConfig:关于以太网的

配置EXTI在stm32f10x exti.h文件中

void EXTI_DeInit(void);

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);

void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);

FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);

void EXTI_ClearFlag(uint32_t EXTI_Line);

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);

void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

**EXTI_DeInit:**EXTI的配置都清除,恢复成上电默认的状态

EXTI_Init:调用这个函数,就可以根据这个结构体里的参数配置EXTI外设, 使用方法和GPIO Init也是一样

EXTI_StructInit: 可以把参数传递的结构体变量赋一个默认值

**EXTI_GenerateSWInterrupt:**软件触发外部中断

在主函数中你想查看标志位和清除标志位使用下面的函数

EXTI_GetFlagStatus:可以获取指定的标志位是否被置1了

EXTI_ClearFlag: 可以对置1的标志位进行清除

在中断函数里,如果你想查看标志位和清除标志位使用下面的函数

EXTI_GetITStatus: 获取中断标志位是否被置1了(检测外部中断的状态)

**EXTI_ClearITPendingBit:**清除中断挂起标志位

配置NMIC在misc.h文件中的函数

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

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);

NVIC_PriorityGroupConfig:用来中断分组的,参数是中断分组的方式

**NVIC_Init:**根据结构体里面指定的参数初始化NMIC

NVIC_SetVectorTable: 设置中断向量表

NVIC_SystemLPConfig :系统低功耗配置

3:硬件介绍

4:计数代码

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"

uint16_t CountSensor_count;
void CountSensor_Init(void){
	//1:配置RCC,把我们这里涉及的外设的时钟都打开(GPIO,AFIO)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	//2:配置GPIO,选择我们的端口为输入模式
	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);
	//3:配置AFIO,选择我们用的这一路GPIO,连接到后面的EXT
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
	//4: 第四步,配置EXTI,选择边沿触发方式比如上升沿、下降沿或者双边沿, 还有选择触发响应方式,可以选择中断响应和事件响应
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line=EXTI_Line14;//14IO口作为中断
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	EXTI_Init(&EXTI_InitStructure);
	//5:配置NVIC,给我们这个中断选择一个合适的优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;//到NVIC的通道
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);
}

uint16_t CountSensor_Get(void)
{
	return CountSensor_count;
}

//STM32的中断函数名字不能变,在启动文件里面查看
void EXTI15_10_IRQHandler(void){ 
	//在中断函数里,查看中断标志位是否被置1了,看是不是PB14口引发的中断(通道10~15都可以进去)
	if (EXTI_GetITStatus(EXTI_Line14)==SET){
				/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		//读取PB14IO口是否为低电频
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==0){
			CountSensor_count++;
		}
//清除中断挂起标志位
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
}

int main(void)
{    
//OLED屏幕代码省略
	OLED_Init();
	CountSensor_Init();
	
	OLED_ShowString(1, 1, "Count:");
	
	while (1)
	{
		OLED_ShowNum(1, 7, CountSensor_Get(), 5);
	}
}

B;旋转编码计数器

1:连接图

2:硬件介绍

我们使用判断正反转的条件:

正转-----B相下降沿和A相低由平时同时满足时;

反转----在A相下降沿和B相低电频同时满足时;

本次使用了两个中断注意:

PB0和PB1设置为中断:

A:配置AFIO时:需要配置两个引脚

B:配置EXTI时:X.EXTI_Line需要配置两个 (X.EXTI_Line = EXTI_Line0 | EXTI_Line1)

C:配置NVIC时: 一次分组,2次初始化

中断函数分析:

当A为中断IO口时: A为下降沿触发中断,B1和B0同时为低电频时满足正转

当B为中断IO口时: A为下降沿触发中断,B0和B1同时为低电频时满足反转

(中断函数处理全局变量时,可以改变全局变量的值)

3:旋转编码器代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"

int16_t Encoder_Count;

void Encoder_Init(void)
{
	//1:配置RCC,把我们这里涉及的外设的时钟都打开(GPIO,AFIO)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	//2:配置GPIO,选择我们的端口为输入模式  注意打开了2个中断
	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);
	//3:配置AFIO,选择我们用的这一路GPIO,连接到后面的EXT
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	//4: 第四步,配置EXTI,选择边沿触发方式比如上升沿、下降沿或者双边沿, 还有选择触发响应方式,可以选择中断响应和事件响应
	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);
	//5:配置NMIC,给我们这个中断选择一个合适的优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; 到NVIC的通道
	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的通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_InitStructure);
}

//返回每次调用这个Get函数之后,返回Count的变化值
//每次调用这个函数都会加1或者减1

int16_t Encoder_Get(void)
{

	int16_t Temp;
	Temp = Encoder_Count;
	
	/*返回的temp是局部变量,在栈区,也就是该函数一旦执行完,
	就会被系统释放,当再次循环调用到该函数时,
	get里的temp就需要被重新赋值,temp被赋值0,
	无论主函数如何循环都是变成了NUM+=0*/
	
	
	/*如果返回函数不清零的话,
		数字就变成等差数列求和,清零的话就疯狂加或者减一*/
	Encoder_Count = 0;
	return Temp; 
}

//void EXTI0_IRQHandler(void)
//{检测外部中断状态,如果状态为SET,会返回真(true),否则返回假(false)。
//	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 EXTI0_IRQHandler(void)
{检测外部中断状态,如果状态为SET,会返回真(true),否则返回假(false)。
	if (EXTI_GetITStatus(EXTI_Line0) == SET)
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
				//中断函数的处理可以改变全局变量的值
				Encoder_Count --;
			
		}
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}
//void EXTI1_IRQHandler(void)
//	{	//检测外部中断状态,如果状态为SET,会返回真(true),否则返回假(false)。
//	if (EXTI_GetITStatus(EXTI_Line1) == SET)
//	{
//		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
//		
//		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //PB1为低电频
//		{
//			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)  //PB0为低电频
//			{//中断函数的处理可以改变全局变量的值
//				Encoder_Count ++;
//			}
//		}
//		//清除中断挂起标志位
//		EXTI_ClearITPendingBit(EXTI_Line1);
//	}
//}
void EXTI1_IRQHandler(void)
	{	//检测外部中断状态,如果状态为SET,会返回真(true),否则返回假(false)。
	if (EXTI_GetITStatus(EXTI_Line1) == SET)
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		
		
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)  //PB0为低电频
			{//中断函数的处理可以改变全局变量的值
				Encoder_Count ++;
			}
		
		//清除中断挂起标志位
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}
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 小时前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
智商偏低7 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen8 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森10 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白10 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D11 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术14 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt14 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘15 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang15 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c