嵌入式学习笔记——STM32寄存器编程实现外部中断

外部中断

  • 前言
  • EXTI的介绍
    • EXTI是什么
    • EXTI的主要特性
      • 数量
      • 对应中断源的命名
    • EXTI的框图
    • 配置流程
  • 寄存器介绍
  • 编程思路
    • 编程
    • 效果

前言

上一篇中,介绍了关于STM32的中断管理以及具体配置,本文就使用之前的配置流程来实现一下外部中断的功能。

EXTI的介绍

EXTI是什么

还是老套路,先来搞清楚EXTI是个啥,EXTI就是STM32的外部中断,既然叫做外部中断,那么其中断一定是来自内核外的,下图的描述中说它可以用以检测外部事件,其实不太完整哈,后面看了框图就清楚了,其实外部中断还可以由软件来触发的。
在这里插入图片描述
上图的描述中还提到了EXTI可以配置为上升沿触发、下降沿触发、上升下降沿触发等多种触发模式,这些就是上一篇中提到的中断信号,也就是整个外部中断的各个分开关。

EXTI的主要特性

数量

外部中断/事件控制器包含多达 23 个用于产生事件/中断请求的边沿检测器
主要的作用是用于通过边沿检测产生中断请求具备23个EXTI中断线
其中,0~15的中断线用于处理GPIO口对应的边沿检测,
16~22用于处理其它的片上外设,例如RTC之类的。

对应中断源的命名

上一篇中我们提到过,对应的中断会有统一的中断源名称,那么这里的外部中断源的命名是怎样的呢,在stm32f4xx.h中查阅即可看到,EXTI0、EXTI1 EXTI2、 EXTI3、 EXTI4是独立的中断源,而EXTI5_9 使用的是同一个中断源、EXTI15_10 使用的是同一个中断源;至于另外的16-22这个后面遇到了再说。
在这里插入图片描述
在这里插入图片描述
在这里需要搞清楚一个事情,那就是GPIO口和EXTI中断如何联系起来的,
举个栗子:
外部中断线:EXTI1对应的 GPIO管脚: PA1 PB1 PC1 PD1 PE1 PF1 PG1 PH1 PI1
也就是说:每一根中断线对应GPIO口的管脚 0–15的中断线对应GPIO0~15管脚。
PA0对应的是EXTI0;PC9对应的是EXTI9;PD9对应的也是EXTI9。

EXTI的框图

再了解了外部中断的一些基本信息后,按照之前的套路,肯定是要了解该如何配置外部中断了,而这中间首要任务就是看懂它的框图,搞清楚其大致的工作流程以及编程流程。
官方的框图如下所示,但是由于我们主要使用的是外部中断,所以红框内的时间控制那一部分就可以直接忽略不看了。
在这里插入图片描述
简化后如下图所示:
在这里插入图片描述
按照输入方向,来梳理一下流程。
1.输入信号经过输入线首先到达的是1号红色框内的边沿检测电路,这个电路收到上方两个寄存器的控制,一个是上升沿触发选择寄存器,另一个是下降沿触发选择寄存器,有程序员编程来选择上升沿下降沿或者同时开启上升沿下降沿两种模式;
2.经过边沿检测电路后,紧接着来到2号橙色框的位置,这里有一个或门,这个或门的逻辑就是两个输入任意一个成立都可以往后走,也就是说,如果上一步没有配置边沿检测,直接在这里配置一个软件中断事件也是可以触发外部中断的,这就是刚刚提到的,外部中断不是只有检测边沿一种作用,它还可以用软件的方式来触发中断,这个软件中断寄存器也是程序员控制的,只要对该寄存器写入对应值它就会触发一次中断;
3.经过2框的或门后,紧接着就是一个与门,这个与门的逻辑是,输入双方同时成立,才会有对应的输出,这里的一个输入来自前面的边沿检测或者是软件触发,另一个输入是由一个叫做中断屏蔽寄存器的东西控制的,也就是说,编程者在操作时,这个寄存器一定要置一,整个电路才可以继续往下执行,其效果也就相当于前面提到的一个使能位,必须将它使能了才能执行后面的功能。
4.经过前面的操作和配置,信号来到了一个叫做挂起请求寄存器的东西,然后就直接进入了中断控制器,可以遇见的是,这个寄存器一定和是用来监测信号的状态的,可以通过它来判断是否产生了中断。
图中的/23代表的是23根外部中断线。

配置流程

通过上面的框图分析,我们可以大致的分析出外部中断的配置流程:
①确定IO口对应的中断线需要写入什么值
②配置对应的EXTI线的边沿触发
③开启EXTI线的中断使能
④配置EXTI线的中断源使能
⑤写中断服务函数

寄存器介绍

再分析完配置流程后,需要来研究一下具体的寄存器描述,注意EXTI的寄存器在中文参考手册的第10章第三节。
在这里插入图片描述
1.中断屏蔽寄存器 EXTI_IMR
写法:EXTI-> IMR
功能:每个位x表示对应的EXTIx
打开对应中断线中断请求(中断使能)对对应位写1即可打开对应的中断线使能。
在这里插入图片描述
2.事件屏蔽寄存器 (EXTI_EMR)
顾名思义,与上一个寄存器的功能刚好相反,可以用来屏蔽相关中断线的请求,一般不用,没必要屏蔽,不用的话不配置使能就可以了。

3.上升沿触发选择寄存器 (EXTI_RTSR)
写法:EXTI-> RTSR
功能:每个位x表示对应的EXTIx
打开对应中断线上升沿触发 ,对对应位置一即可使能上升沿触发。
在这里插入图片描述

4.下降沿触发选择寄存器 (EXTI_FTSR)
写法:EXTI-》FTSR
功能:每个位x表示对应的EXTIx
打开对应中断线下降沿触发 对对应位置一即可使能下降沿触发。
在这里插入图片描述
注意,边沿检测的时候是不能除夕拿毛刺信号的,也就是说,输入的波形一定要平滑,不能出现抖动。

5.软件中断事件寄存器 (EXTI_SWIER)
写法:EXTI->SWIER
功能:每个位x表示对应的EXTIx
让对应的EXTI线产生中断请求,通过软件置一的方式可以实现一次软件触发外部中断的效果。
在这里插入图片描述
6. 挂起寄存器 (EXTI_PR)
写法:EXTI->PR
功能:每个位x表示对应的EXTIx
对应的中断线产生了中断则置1
写入1可以对状态位做清除,中断的标志位,如果对应线上产生了中断,对应的寄存器就会被置一,判断中断时就是以这个作为标志的。
在这里插入图片描述
上面这部分都是在框图中可以找到的,实际上要使用外部中断还需要一个寄存器,前面提到过,一个EXTI线会对应多个管脚,那么系统要怎么知道具体是哪个管脚映射到了对应的EXTI线上呢,
这就需要使用到外部中断配置寄存器:SYSCFG->EXTICR,在手册的第八章,如下图所示,每四个为对应一个EXTI线,对这四个位写入对应的值即可选择到对应的管脚。
在这里插入图片描述
举个栗子:
我们需要配置PA0的外部中断,首先PA0对应的外部中短线是EXTI0,其对应的外部中断配置寄存器是SYSCFG_EXTICR1的0-3位,PA端口,应该写入的是0000。
具体写法:

SYSCFG->EXTICR[0] &=~(0xf<<0);
注意SYSCFG_EXTICR1的写法是SYSCFG->EXTICR[0]SYSCFG_EXTICR2的写法是SYSCFG->EXTICR[1],依次类推。

再举个例子
需要配置PE4的外部中断,首先,对应的外部中断线是EXTI4,其对应的外部中断配置寄存器是SYSCFG_EXTICR2的0-3位,PE端口,所以应该写入0100;
所以其具体的写法如下:

SYSCFG->EXTICR[1] &= ~(0xf<<0);   //先清零
		SYSCFG->EXTICR[1] |=  (0X4<<0);   //GPIOE4映射到EXTI4

编程思路

好了,至此就已经大致捋清楚了外部中断的配置流程,注意,不要忘记了,使用到了中断,所以必须要有昨天的NVIC控制器相关的配置,这里再来总结一个具体的伪代码:

新建exti文件
配置思路:
EXTI的初始化函数
{
  //打开时钟 PA时钟  SYSCFG时钟
  //IO口配置    属于特殊的映射  不需要配置
  //EXIT控制器
   SYSSFG_EXTICR寄存器 IO映射
   上下边沿检测
   中断使能
  //NVIC控制器
   优先级配置
   中断源使能
}

在nvic.c写中断服务函数 中断服务函数根据使用EXTI线
Void 中断服务函数(void{
   判断触发
   {
      //清除标志位
      //紧急事件
   }
}

编程

按照上面的要求,新建对应的文件,然后添加代码,这里就不贴出全部代码了,需要的请私信,笔者实现的效果是三个按键,按下对应的变量会自增
Exti.c

#include "Exti.h"

u16 K_UP_cnt,K0_cnt,K1_cnt;
/*******************************************
*函数名    :Exti0_Init
*函数功能  :外部中断0初始化函数
*函数参数  :无
*函数返回值:无
*函数描述  :
PA0——对应EXTI0中断线,上升沿触发
PE3——对应EXTI3中断线,下降沿触发
PE4——对应EXTI4中断线,下降沿触发
*********************************************/
void Exti0_Init(void)
{
		u32 pri;//存储优先级合成函数返回的优先级
		RCC->AHB1ENR  |= (1<<0);		//打开AHB1上GPIOA端口
		RCC->APB2ENR  |= (1<<14);   //打开SYSCFG的时钟使能,
/*---------------------------------------------------------------------------------*/	
		//IO配置GPIOA,通用输入,可不配置
	
/*-----------------------------------------------------------------------------------*/	
		SYSCFG->EXTICR[0] &= ~(0xf<<0);  //配置GPIOA0与EXTI0映射连接——第八章系统配置控制器 (SYSCFG)
	
		SYSCFG->EXTICR[0] &= ~(0XF<<12); //先清零
		SYSCFG->EXTICR[0] |=  (0X4<<12);  //(GPIOE3映射到EXTI3)
	
		SYSCFG->EXTICR[1] &= ~(0xf<<0);   //先清零
		SYSCFG->EXTICR[1] |=  (0X4<<0);   //GPIOE4映射到EXTI4
	
		EXTI->RTSR  |= (1<<0);//配置EXTI0为上升沿有效——第十章 10.3 EXTI 寄存器
		EXTI->FTSR  |= (1<<3);//配置EXTI3为下升沿有效
		EXTI->FTSR  |= (1<<4);//配置EXTI4为下升沿有效
	
		EXTI->IMR   |= (1<<0);//使能EXTI0的中断
		EXTI->IMR   |= (1<<3);//使能EXTI3的中断
		EXTI->IMR   |= (1<<4);//使能EXTI4的中断
/*------------------------------------------------------------------------------------*/			
		//NVIC控制器配置EXTI0
		pri=NVIC_EncodePriority(7-2,0,2);
		NVIC_SetPriority(EXTI0_IRQn,pri);
		NVIC_EnableIRQ(EXTI0_IRQn);
		
				//NVIC控制器配置EXTI3
		pri=NVIC_EncodePriority(7-2,1,0);
		NVIC_SetPriority(EXTI3_IRQn,pri);
		NVIC_EnableIRQ(EXTI3_IRQn);
				//NVIC控制器配置EXTI4
		pri=NVIC_EncodePriority(7-2,1,1);
		NVIC_SetPriority(EXTI4_IRQn,pri);
		NVIC_EnableIRQ(EXTI4_IRQn);
		
}


/*******************************
函数名:EXTI0_IRQHandler
函数功能:EXTI0的中断服务函数函数
函数形参:无
函数返回值:void
备注:
********************************/
void EXTI0_IRQHandler(void)
{
	if(EXTI->PR & (1<<0))//EXTI0产生了上升沿中断
	{
		EXTI->PR |= (1<<0);
		K_UP_cnt++;
	}
}


/*******************************
函数名:EXTI3_IRQHandler
函数功能:EXTI3的中断服务函数函数
函数形参:无
函数返回值:void
备注:
********************************/
void EXTI3_IRQHandler(void)
{
	if(EXTI->PR & (1<<3))//EXTI3产生了下升沿中断
	{
		EXTI->PR |= (1<<3);
		K0_cnt++;
	}
}

/*******************************
函数名:EXTI4_IRQHandler
函数功能:EXTI4的中断服务函数函数
函数形参:无
函数返回值:void
备注:
********************************/
void EXTI4_IRQHandler(void)
{
	if(EXTI->PR & (1<<4))//EXTI3产生了下升沿中断
	{
		EXTI->PR |= (1<<4);
		K1_cnt++;
	}
}


Exti.h

#ifndef _EXTI_H__
#define _EXTI_H__
#include "stm32f4xx.h"
void Exti0_Init(void);
#endif

效果

按下对应按键,右下角的WATCH得数值会对应自增。
在这里插入图片描述

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

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

相关文章

SDIO读写SD卡速度有多快?

前两天测试了SPI方式读写SD卡的速度《SPI方式读写SD卡速度测试》&#xff0c;今天来测试一下SDIO方式的读写速度。测试条件&#xff1a;单片机&#xff1a;STM32F407VET6编译环境&#xff1a;MDK 5.30HAL库SD卡&#xff1a;闪迪32GB/64GB TF卡文件系统&#xff1a;FatFS R0.12c…

SpringCloud详解01-SpringCloudAlibaba、Nacos

文章目录前言一、架构演进1、web1.0阶段2、web2.0阶段3、垂直架构4、分布式架构二、SpringCloud基本概念1.特点2.SpringCloud和SpringCloudAlibaba3.SpringCloudAlibaba体系核心组件三、SpringCloudAlibaba1、注册中心Nacos2、Nacos安装和启动总结前言 本篇记录一下SpringClou…

ChatGPT研究分享:机器第一次开始理解人类世界

0、为什么会对ChatGPT感兴趣一开始&#xff0c;我对ChatGPT是没什么关注的&#xff0c;无非就是有更大的数据集&#xff0c;完成了更大规模的计算&#xff0c;所以能够回答更多的问题。但后来了解到几个案例&#xff0c;开始觉得这个事情并不简单。我先分别列举出来&#xff0c…

每日学术速递3.17

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Breaking Common Sense: WHOOPS! A Vision-and-Language Benchmark of Synthetic and Compositional Images 标题&#xff1a;打破常识&#xff1a;哎呀&#xff01;合成和合成图像…

【Redis】搭建哨兵集群

目录 集群结构 准备实例和配置 启动 测试 集群结构 这里我们搭建一个三节点形成的Sentinel集群&#xff0c;来监管之前的Redis主从集群。如图&#xff1a; 三个sentinel实例信息如下&#xff1a; 节点IPPORTs1192.168.150.10127001s2192.168.150.10127002s3192.168.150.…

python并发编程多线程

在传统操作系统中&#xff0c;每个进程有一个地址空间&#xff0c;而且默认就有一个控制线程 线程顾名思义&#xff0c;就是一条流水线工作的过程&#xff0c;一条流水线必须属于一个车间&#xff0c;一个车间的工作过程是一个进程 车间负责把资源整合到一起&#xff0c;是一个…

C语言指针操作(十)动态内存分配与指向它的指针变量

目录 一、什么是内存的动态分配 二、怎样建立内存的动态分配 2.1用malloc函数开辟动态存储区 2.2用calloc函数开辟动态存储区 2.3用realloc函数重新分配动态存储区 2.4用free函数释放动态存储区 三、void指针类型 四、举例说明 一、什么是内存的动态分配 全局变量是分…

redis持久化的几种方式

一、简介 Redis是一种高级key-value数据库。它跟memcached类似&#xff0c;不过数据可以持久化&#xff0c;而且支持的数据类型很丰富。有字符串&#xff0c;链表&#xff0c;集 合和有序集合。支持在服务器端计算集合的并&#xff0c;交和补集(difference)等&#xff0c;还支持…

【蓝桥杯专题】 贪心(C++ | 洛谷 | acwing | 蓝桥)

菜狗现在才开始备战蓝桥杯QAQ 文章目录【蓝桥杯专题】 &#xff08;C | 洛谷 | acwing | 蓝桥&#xff09;1055. 股票买卖 IIAcWing 104. 货仓选址传递糖果AcWing 112. 雷达设备付账问题乘积最大AcWing 1247. 后缀表达式P【蓝桥杯专题】 &#xff08;C | 洛谷 | acwing | 蓝桥&…

Flink 应用案例——求网页访问量Top N 实时计算(附可执行代码)

在学习了Flink之后&#xff0c;笔者通过以下案例对Flink API 进行简单复习 目录 案例要求 前置准备 编写主程序&#xff08;点此跳转至代码&#xff09; 运行截图 案例要求 以下数据 为某网站的访问日志 现要求通过以下数据 统计出最近10s内最热门的N个页面&#xff08;即…

【3.17】MySQL索引整理、回溯(分割、子集问题)

3.1 索引常见面试题 索引的分类 什么是索引&#xff1f; 索引是一种数据结构&#xff0c;可以帮助MySQL快速定位到表中的数据。使用索引&#xff0c;可以大大提高查询的性能。 按「数据结构」分类&#xff1a;Btree索引、Hash索引、Full-text索引。 InnoDB 存储引擎创建的聚簇…

漫画:什么是快速排序算法?

这篇文章&#xff0c;以对话的方式&#xff0c;详细着讲解了快速排序以及排序排序的一些优化。 一禅&#xff1a;归并排序是一种基于分治思想的排序&#xff0c;处理的时候可以采取递归的方式来处理子问题。我弄个例子吧&#xff0c;好理解点。例如对于这个数组arr[] { 4&…

优思学院|六西格玛DMAIC,傻傻搞不清?

DMAIC还是搞不清&#xff1f; DMAIC是一个用于过程改进和六西格玛的问题解决方法论。它是以下五个步骤的缩写&#xff1a; 定义&#xff08;Define&#xff09;&#xff1a;明确问题&#xff0c;设定项目的目标和目的。绘制流程图&#xff0c;并收集数据&#xff0c;以建立未来…

基于bearpi的智能小车--Qt上位机设计

基于bearpi的智能小车--Qt上位机设计 前言一、界面原型1.主界面2.网络配置子窗口模块二、设计步骤1.界面原型设计2.控件添加信号槽3.源码解析3.1.网络链接核心代码3.2.网络设置子界面3.3.小车控制核心代码总结前言 最近入手了两块小熊派开发板,借智能小车案例,进行鸿蒙设备学…

01背包问题c++

问题 问题介绍 有 N 种物品和一个容量是 V 的背包&#xff0c;每种物品都有无限件可用。 第 i 种物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第…

基于Transformer的交通预测模型部分汇总【附源代码】

交通预测一直是一个重要的问题&#xff0c;它涉及到交通运输系统的可靠性和效率。随着人工智能的发展&#xff0c;越来越多的研究者开始使用深度学习模型来解决这个问题。其中&#xff0c;基于Transformer的交通预测模型在近年来备受关注&#xff0c;因为它们具有优秀的建模能力…

设计模式之桥接模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、桥接模式是什么&#xff1f; 桥接模式是一种结构型的软件设计模式&#xff0c;将抽象部分与实现部分分离&#xff0c;使他们可…

像ChatGPT玩转Excel数据

1.引言 最近ChatGPT的出现&#xff0c;把人工智能又带起了一波浪潮。机器人能否替代人类又成了最近热门的话题。 今天我们推荐的一个玩法和ChatGPT有点不一样。我们的课题是“让用户可以使用自然语言从Excel查询到自己想要的数据”。 要让自然语言可以从Excel中查数据&#…

通过百度文心一言大模型作画尝鲜,感受国产ChatGPT的“狂飙”

3月16日下午&#xff0c;百度于北京总部召开新闻发布会&#xff0c;主题围绕新一代大语言模型、生成式AI产品文心一言。百度创始人、董事长兼首席执行官李彦宏&#xff0c;百度首席技术官王海峰出席&#xff0c;并展示了文心一言在文学创作、商业文案创作、数理推算、中文理解、…

用Qt画一个温度计

示例1 以下是用Qt绘制一个简单的温度计的示例代码&#xff1a; #include <QPainter> #include <QWidget> #include <QApplication> class Thermometer : public QWidget { public:Thermometer(QWidget *parent 0); protected:void paintEvent(QPaintEvent …