STM32-EXTI外部中断

一、中断系统

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

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

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

二、STM32中断

 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设

使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

三、NVIC(嵌套中断向量控制器)基本结构

作用:统一分配中断优先级和管理中断

四、NVIC优先级分组

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级

抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队

五、EXTI外部中断

5.1 外部中断基本知识

①EXTI(Extern Interrupt)外部中断

②EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
③支持的触发方式:上升沿/下降沿/双边沿/软件触发
④支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
⑤通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
⑥触发响应方式:中断响应/事件响应

中断响应:引脚电平变化触发中断

事件响应:不触发中断,触发其他外设操作

5.2 外部中断(EXTI)基本结构

5.2.1开发步骤: 

①配置RCC,把涉及到的外设时钟都打开

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

③配置AFIO,选择用的某一路GPIO,连接到后面的EXTI

④配置EXTI,选择边沿触发方式、触发响应方式(中断响应/事件响应)

⑤配置NVIC,给中断选择合适的优先级

5.3 AFIO复用IO口

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

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

5.4 EXTI内部框图

六、AFIO库函数

void GPIO_AFIODeInit(void);//复位AFIO

//配置AFIO事件输出功能

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

//配置AFIO的数据选择器,本节中断用到的函数


void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

//以太网相关

AFIO中断选择函数详解

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); 

第一个参数:GPIO_PortSourceGPIOx where x can be (A..G)

第二个参数:GPIO_PinSourcex where x can be (0..15)

七、EXTI库函数 

void EXTI_DeInit(void);//清除所有EXTI配置,复位
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);//结构体方式初始化EXTI
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);//给结构体变量赋默认值


void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);//软件触发外部中断

/*主函数查看和清除标志位*/
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);//获取指定标志位是否被置1
void EXTI_ClearFlag(uint32_t EXTI_Line);//对置1的标志位清除

/*中断函数查看和清除标志位*/
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

八、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);//系统低功耗配置

九、中断函数

每个通道对应一个中断函数,在启动文件中可查看

开发技巧:

在中断函数中,先进行中断标志位的判断,确保是我们想要的中断源触发的函数;然后再使用清除标志位函数清除,否则会一直执行中断函数,在中断函数里卡死。

以上函数具体使用请参考”第十章、实验“ 

十、实验

10.1对射式红外传感器计次

main.c

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

int main(void)
{
	OLED_Init();
	CountSensor_Init();
	
	OLED_ShowString(1,1 ,"Count:");
	
	
	while (1)
	{
		OLED_ShowNum(1,7,CountSensor_Get(),5);
	}
}

CountSensor.c

#include "stm32f10x.h"                  // Device header

uint16_t CountSensor_Count;

void CountSensor_Init(void)
{
	/*一、开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启APB2时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启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);
	
	/*三、AFIO配置*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
	
	/*四、EXTI第14个线路配置为中断模式,下降沿触发,开启中断*/
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;//EXTI线
	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);
}

uint16_t CountSensor_Get(void)
{
	return CountSensor_Count;
}

void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line14) == SET)    //判断标志位,是否是EXTI_Line14触发的中断
	{
		CountSensor_Count++;  
		EXTI_ClearITPendingBit(EXTI_Line14);//清除标志位
	}
	
}

CountSensor.h

#ifndef __COUNTSENSOR_H
#define __COUNTSENSOR_H

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

#endif

10.2旋转编码器计次

 mian.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#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);  
	}
}

Encoder.c

#include "stm32f10x.h"                  // Device header

int16_t Encoder_Count;//无符号变量

/*初始化操作*/
void Encoder_Init(void)
{
	/*一、开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启APB2时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启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);
	
	/*三、AFIO配置*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
	
	/*四、EXTI第0/1个线路配置为中断模式,下降沿触发,开启中断*/
	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*/
	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;
}

/*正转中断函数*/
void EXTI1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line1) == SET)					//B相下降沿(中断)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) == 0)	//A相低电平
		{
			Encoder_Count ++;
		}
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

/*反转中断函数*/
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0) == SET)					//A相下降沿(中断)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)	//B相低电平
		{
			Encoder_Count --;
		}
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}

Encoder.h

#ifndef __ENCODER_H
#define __ENCODER_H

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

#endif

十一、中断编程建议

①在中断函数中,不要执行耗时过长的代码,中断函数要简短快速,不要执行Delay函数,防止主程序受到严重阻塞

②不要在主函数和中断函数中调用相同的函数或者操作同一个硬件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/228140.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2021年第十届数学建模国际赛小美赛B题疾病传播的风险解题全过程文档及程序

2021年第十届数学建模国际赛小美赛 B题 疾病传播的风险 原题再现: 空气传播疾病可以通过咳嗽或打喷嚏、喷洒液体或灰尘传播。另一方面,一些常见的传染病只能通过飞沫传播。请建立一个模型,以评估密闭空间内空气传播和液滴传播疾病的可能性。…

查看电脑cuda版本

1.找到NVODIA控制面板 输入NVIDIA搜索即可 出现NVIDIA控制面板 点击系统信息 2.WINR 输入nvidia-smi 检查了一下,电脑没用过GPU,连驱动都没有 所以,装驱动…… 选版本,下载 下载后双击打开安装 重新输入nvidia-smi 显示如下…

喜讯:加速度商城系统全系列产品品牌全新升级为Shopfa

2月1日讯:经过1年多的品牌文化塑造,深圳市加速度软件开发有限公司经过研究决定,将旗下的多商户商城系列、小程序商城系列、B2B商城系列、供应商集采系列、电子元器件商城系列、跨境独立站商城系列、MRO工业品商城系列、外卖商城系列、智慧零售…

C++笔记:动态内存管理

文章目录 语言层面的内存划分C语言动态内存管理的缺陷new 和 delete 的使用了解语法new 和 delete 操作内置类型new 和 delete 操作自定义类型 new 和 delete 的细节探究new 和 delete 的底层探究operator new 和 operator new[]operator delete 和 operator delete[] 显式调用…

体验官分享 | 用户眼中的OK3588-C开发板究竟有多优秀?

编者荐语:飞凌嵌入式今年共发起了5期【产品体验官】活动,让更多热爱嵌入式的朋友免费体验到了自己感兴趣的产品,飞凌嵌入式也收获了很多宝贵的建议。活动期间体验官们创作了许多优质的体验报告,今天小编就与大家分享一篇来自体验官…

Django讲课笔记01:初探Django框架

文章目录 一、学习目标二、课程导入(一)课程简介(二)课程目标(三)适用人群(四)教学方式(五)评估方式(六)参考教材 三、新课讲授&#…

SAP UI5 walkthrough step2 Bootstrap

我的理解&#xff0c;这就是一个引导指令 1.我们右键打开命令行--执行 ui5 use OpenUI5 2.执行命令&#xff1a;ui5 add sap.ui.core sap.m themelib_sap_horizon 执行完之后&#xff0c;会更新 yaml 文件 3.修改index.html <!DOCTYPE html> <html> <head&…

Java安全之Commons Collections6分析

CC6分析 import org.apache.commons.collections.*; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; impo…

[⑧ADRV902x]: Digital Pre-Distortion (DPD)学习笔记

前言 DPD 数字预失真技术&#xff0c;是一种用于抑制功率放大器非线性失真的方法。 它通过在信号输入功率放大器&#xff08;PA&#xff09;之前插入一个预失真模块&#xff0c;对输入信号进行适当的调制&#xff0c;以抵消功率放大器引起的非线性失真&#xff0c;使功率放大器…

线上盲盒扭蛋机,开启潮玩新玩法

盲盒近几年非常火爆&#xff0c;因其不确定性、随机性吸引着盲盒爱好者&#xff0c;引起了潮玩文化风潮。扭蛋机是盲盒的一种新抽取模式&#xff0c;线上扭蛋机小程序在具有盲盒的优势外&#xff0c;还具有较大吸引力&#xff0c;用户参与率较高&#xff0c;这也使得扭蛋机成为…

C++_命名空间(namespace)

目录 1、namespace的重要性 2、 namespace的定义及作用 2.1 作用域限定符 3、命名空间域与全局域的关系 4、命名空间的嵌套 5、展开命名空间的方法 5.1 特定展开 5.1 部分展开 5.2 全部展开 结语&#xff1a; 前言&#xff1a; C作为c语言的“升级版”&#xff0c;其在…

西南科技大学C++程序设计实验十一(泛型程序设计与C++标准模板库)

一、实验目的 1. 掌握泛型程序设计概念; 2. 掌握vector、deque、list容器使用方法; 3.了解set、map容器使用方法。 二、实验任务 1.分析完善以下程序,理解vector容器使用方法: #include <iostream> __#include <vector>_______ //补充vector模板头文件 …

(C语言实现)高精度除法 (洛谷 P2005 A/B Problem II)

前言 本期我们分享用C语言实现高精度除法&#xff0c;可通过该题测试点我点我&#xff0c;洛谷 p2005。 那么话不多说我们开始吧。 讲解 大家还记不记得小学的时候我们是怎么做除法的&#xff1f;我们以1115为例。 我们的高精度除法也将采用这个思路进行&#xff0c;分别用两…

selenium 解决 id定位、class定位中,属性值带空格的解决办法

一、前置说明 selenium遇到下面这种元素&#xff1a; <th id"demo id" class"value1 value2 value3 ">1、虽然id一般不会有空格&#xff0c;但是前端错误的这种写法(如下图)&#xff0c;会造成使用id定位不到元素&#xff0c;如&#xff1a; find…

Windows本地如何添加域名映射?(修改hosts文件)

1. DNS(域名系统) Domain Name System(域名系统)&#xff1a;为了加快定位IP地址的速度, 将域名映射进行层层缓存的系统. 目的&#xff1a;互联网通过IP&#xff08;10.223.146.45&#xff09;定位浏览器建立连接&#xff0c;但是我们不易区别IP&#xff0c;为了方便用户辨识I…

SAP 后继物料简介

后继物料(Discontinued Part)是SAP系统提供的一项用于物料继承与物料永久性替换的功能。在企业的日常生产业务中,经常会出于技术原因或成本原因进行大批量的物料替换或物料升级。比如说,企业可以用一种可靠性更高的组件替换先前使用的组件,或者出于节省成本的目的,使用一…

Google Gemini Pro 测试

谷歌新发布了Gemini模型&#xff0c;说是吊打GPT4&#xff0c;上手使用了下&#xff0c;感觉一般&#xff0c;没有感觉到预期的吊打。下面是与Bard的对话。

条码生成器与Zint使用

文章目录 目的条形码zint支持条形码种类下载编译qt pro配置code保存条形码目的 1: 了解条形码数据理论知识 2: 了解zint第三方库相关, 如何编译引用到项目中 条形码 条形码(Barcode)一维码 和二维码(QR code)都是用于存储信息的图形化表示方式,通常应用于商品标识、库…

led护眼灯真的能护眼吗?热门口碑好的护眼台灯推荐

2023年我国青少年近视率为53.6%&#xff0c;其中6岁以下儿童近视率为14.5%&#xff0c;小学生近视率为36%&#xff0c;初中生近视率为71.6%&#xff0c;高中生近视率为81%&#xff0c;大学生近视率为90%。 也就是孩子上了大学&#xff0c;十个里面有九个是近视&#xff0c;不戴…

【C语言】vfprintf函数

vfprintf 是 C 语言中的一个函数&#xff0c;它是 fprintf 函数的变体&#xff0c;用于格式化输出到文件中。vfprintf 函数接受一个格式化字符串和一个指向可变参数列表的指针&#xff0c;这个列表通常是通过 va_list 类型来传递的。vfprintf 函数的主要用途是在需要处理不定数…