首页 > 其他分享 >中断系统 外部中断(NVIC)

中断系统 外部中断(NVIC)

时间:2024-09-29 08:53:28浏览次数:8  
标签:中断 NVIC 外部 Init InitStructure GPIO EXTI

目录

EXTI外部中断操作步骤

1.配置RCC,把涉及的相关时钟时钟都打开;

2.配置GPIO,选择端口为输入模式

3.配置AFIO,选择我们需要用到的GPIO端口,连接到后面的EXTI;

4.配置EXTI,选择边沿触发方式(上升沿,下降沿,或者双边沿)选择选择触发响应方式(中断响应和事件响应)

5.NVIC中断分组

6.配置NVIC,给中断选择一个合适的优先级,通过NVIC外部中断信号就能够进入cpu

7.中断程序

代码示例

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

2.旋转编码器计次


EXTI外部中断操作步骤


1.配置RCC,把涉及的相关时钟时钟都打开;

(rcc.h文件)

 RCC_AHBPeriphClockCmd();  AHB对应的外设 

 RCC_APB1PeriphClockCmd();  APB1对应的外设

 RCC_APB2PeriphClockCmd();  APB2对应的外设 

(EXTI NVIC这两个外设时钟默认打开状态 不需要通过RCC配置)
  


2.配置GPIO,选择端口为输入模式

(定义 一个结构体通过结构体来调用GPIO里面的参数)

GPIO_InitTypeDef GPIO_InitStructure ;
        ......

GPIO_Init(GPIOx,&GPIO_InitStructure );
      

3.配置AFIO,选择我们需要用到的GPIO端口,连接到后面的EXTI;


(ST公司并没有给他分配专门的库函数文件,他的库函数文件在(GPIO.h)里)
GPIO_AFIODeInit(); (复位AFIO外设,调用该函数AFIO配置会全部清除)
GPIO_PinRemapConfig(GPIO_Remap,NewState);(引脚重映射)(第一个参数选择引脚重映射的方式,第二个参数是新的状态)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOx,GPIO_PoreSourcex);(外部中断所需要的函数,可以配置AFIO数据选择器,选择我们想要的中断引脚)


4.配置EXTI,选择边沿触发方式(上升沿,下降沿,或者双边沿)选择选择触发响应方式(中断响应和事件响应)


(exti.h文件)
EXTI_DeInit();(复位函数,清除EXTI所有配置)
EXTI_Init();(根据结构体里面指定的参数初始化EXTI)
EXTI_GenerateSWInterrupt();(软件触发外部中断)

(主程序查看清除标志位)

 EXTI_GetFlagStatus();(可以获取指定标志位是否被置1了)
 EXTI_ClearFlag();(可以对置1的函数进行清除)

(中断程序查看清除标志位)

 EXTI_GetITStatus();(获取中断标志位是否被置1了)

 EXTI_ClearITPendingBit();(清除中断挂起的标志位)


5.NVIC中断分组

(misc.h)
 NVIC_PriorityGroupConfig();(中断分组)

6.配置NVIC,给中断选择一个合适的优先级,通过NVIC外部中断信号就能够进入cpu

(misc.h)

NVIC_Init();(根据结构体里面指定的参数初始化NVIC)

7.中断程序


 中断函数名字一般在启动程序中,中断函数都是无参无返回值
 中断函数中,要进行一个中断标志位的判断      
 EXTI_GetITStatus();(获取中断标志位是否被置1了)
 清除标志位
 EXTI_ClearITPendingBit();(清除中断挂起的标志位)


代码示例

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

封装.C文件

#include "stm32f10x.h"                  // Device header

uint16_t CountSensor_Count;				//全局变量,用于计数

/**
  * 函    数:计数传感器初始化
  * 参    数:无
  * 返 回 值:无
  */
void CountSensor_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟
	
	/*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);						//将PB14引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
	
	/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;					//选择配置外部中断的14号线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		//选择配置NVIC的EXTI15_10线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}

/**
  * 函    数:获取计数传感器的计数值
  * 参    数:无
  * 返 回 值:计数值,范围:0~65535
  */
uint16_t CountSensor_Get(void)
{
	return CountSensor_Count;
}

/**
  * 函    数:EXTI15_10外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
		{
			CountSensor_Count ++;					//计数值自增一次
		}
		EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}

封装.h文件

#ifndef __COUNT_SENSOR_H
#define __COUNT_SENSOR_H

void CountSensor_Init(void);
uint16_t CountSensor_Get(void);

#endif

主函数

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

int main(void)
{
	/*模块初始化*/
	OLED_Init();			//OLED初始化
	CountSensor_Init();		//计数传感器初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Count:");	//1行1列显示字符串Count:
	
	while (1)
	{
		OLED_ShowNum(1, 7, CountSensor_Get(), 5);		//OLED不断刷新显示CountSensor_Get的返回值
	}
}

2.旋转编码器计次

封装.C文件

#include "stm32f10x.h"                  // Device header

int16_t Encoder_Count;					//全局变量,用于计数旋转编码器的增量值

/**
  * 函    数:旋转编码器初始化
  * 参    数:无
  * 返 回 值:无
  */
void Encoder_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟
	
	/*GPIO初始化*/
	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);						//将PB0和PB1引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//将外部中断的1号线映射到GPIOB,即选择PB1为外部中断引脚
	
	/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;		//选择配置外部中断的0号线和1号线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//选择配置NVIC的EXTI0线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设

	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			//选择配置NVIC的EXTI1线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//指定NVIC线路的响应优先级为2
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}

/**
  * 函    数:旋转编码器获取增量值
  * 参    数:无
  * 返 回 值:自上此调用此函数后,旋转编码器的增量值
  */
int16_t Encoder_Get(void)
{
	/*使用Temp变量作为中继,目的是返回Encoder_Count后将其清零*/
	/*在这里,也可以直接返回Encoder_Count
	  但这样就不是获取增量值的操作方法了
	  也可以实现功能,只是思路不一样*/
	int16_t Temp;
	Temp = Encoder_Count;
	Encoder_Count = 0;
	return Temp;
}

/**
  * 函    数:EXTI0外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI0_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line0) == SET)		//判断是否是外部中断0号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
		{
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)		//PB0的下降沿触发中断,此时检测另一相PB1的电平,目的是判断旋转方向
			{
				Encoder_Count --;					//此方向定义为反转,计数变量自减
			}
		}
		EXTI_ClearITPendingBit(EXTI_Line0);			//清除外部中断0号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}

/**
  * 函    数:EXTI1外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI1_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line1) == SET)		//判断是否是外部中断1号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)		//PB1的下降沿触发中断,此时检测另一相PB0的电平,目的是判断旋转方向
			{
				Encoder_Count ++;					//此方向定义为正转,计数变量自增
			}
		}
		EXTI_ClearITPendingBit(EXTI_Line1);			//清除外部中断1号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}

封装.h文件

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_Init(void);
int16_t Encoder_Get(void);

#endif

主函数

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

int16_t Num;			//定义待被旋转编码器调节的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Encoder_Init();		//旋转编码器初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Num:");			//1行1列显示字符串Num:
	
	while (1)
	{
		Num += Encoder_Get();				//获取自上此调用此函数后,旋转编码器的增量值,并将增量值加到Num上
		OLED_ShowSignedNum(1, 5, Num, 5);	//显示Num
	}
}


 

标签:中断,NVIC,外部,Init,InitStructure,GPIO,EXTI
From: https://blog.csdn.net/m0_59802543/article/details/142584859

相关文章

  • 单片机中断机制:提升系统效率与响应能力的关键技术
    单片机中断机制:提升系统效率与响应能力的关键技术在当今快速发展的嵌入式系统领域,单片机(MicrocontrollerUnit,MCU)作为核心控制单元,其性能与功能直接影响到整个系统的运行效率与可靠性。在众多关键技术中,中断机制(InterruptMechanism)作为单片机实现高效多任务处理的重要手段,......
  • 单片机中断优先级的解决办法
    为什么会有中断优先级呢?首先如果在INT0按键按下时   T0也刚好记满溢出  机器会先INT0CPU:先响应INT0,响应结束去响应T0 IP寄存器PT0=1保持定时的精度高优先级按自然优先级排序低优先级也按自然优先级排序中断的嵌套    ......
  • softirq和hardirq中断亲和度
    /proc/interrupts和/proc/softirqs两者是相互关联的,但它们各自记录的信息和作用有所不同,反映了硬中断和软中断的两个处理阶段。两者的关系:硬中断引发软中断:硬中断通常由外部设备(如网络卡、键盘等)触发,当CPU响应硬中断时,会暂时停止当前正在执行的任务,去处理该硬件中断。......
  • 如何判定是否丢中断
    关于是否“丢中断”,可以从以下几点进行分析:1.中断总开关的作用:中断总开关(如IE寄存器中的EA位)是控制CPU是否响应中断的总体开关。当EA=1时,CPU开放中断,即允许中断的发生;当EA=0时,则屏蔽所有的中断申请。2.中断位使能的意义:除了总开关外,每个中断源通常还有自己的使能位(如EX0、ET0......
  • STM32-使用串口空闲中断,实现串口不定长接收
    示例代码是直接操作寄存器的核心思路很简单:接收到消息后,打开串口总线空闲中断总线进入空闲中断后,关闭空闲中断代码如下:``点击查看代码#include"myusart2.h"#include"string.h"#include"tool.h"charusart2_rec_buff[usart2_rec_len];u8usart2_rec_flag=0;......
  • 如何集成化管理API_方便企业内外部调用?
    API已成为企业数字战略中不可或缺的一部分。它们使不同软件系统、应用程序和服务之间能够高效、灵活地相互沟通。API不仅能提升企业内部各部门之间的协作效率,还能加强与外部合作伙伴及客户之间的互动。API的集成化管理将成为企业实现更高效业务流程的重要手段。通过有效的API管......
  • k8s 访问一个 外部内部地址 代理到外网 作用是 k8s节点不直接开启外网ip
    nginx服务器访问本地的内网地址怎么代理访问到百度  要通过Nginx服务器代理访问到百度,你可以配置Nginx进行反向代理。以下是配置Nginx反向代理的步骤:安装Nginx:确保你的服务器上已经安装了Nginx。如果尚未安......
  • java如何调用外部程序
    java如何调用外部程序2017-03-1520:50179人阅读评论(0)收藏举报分类:Java应用(26)版权声明:本文为博主原创文章,未经博主允许不得转载。引言;有时候有些项目需求,直接使用Java编写比较麻烦,所有我们可能使用其他语言编写的程序来实现。那么我们如何在java中......
  • java 指定外部jar路径
    在Java中指定外部JAR文件的路径有多种方法,具体取决于你使用的开发环境和构建工具。以下是一些常见的方法:1.使用命令行如果你使用命令行来运行Java程序,可以通过-cp或-classpath参数来指定外部JAR文件的路径。示例假设你有一个主类MainClass和一个外部JAR文件exter......
  • 创建对外部存储库的拉取请求
    本周的重点是实验2,其中涉及通过创建拉取请求(pr)为我不拥有的存储库做出贡献。我首先选择一个同学的存储库来进行工作。鉴于javascript是我的主要编程语言,我选择了基于javascript的存储库来简化我的工作流程。虽然我愿意探索其他语言,但我选择js项目节省了时间,让我可以更......