STM32 EXTI外部中断小结

发布者:sigma28最新更新时间:2022-04-25 来源: eefocus关键字:STM32  EXTI  外部中断 手机看文章 扫描二维码
随时随地手机看文章

本文为野火教程学习笔记。

EXTI原理解释

EXTI 简介

  EXTI (External interrupt/event controller) ——外部中断/事件控制器,其用于管理外设中GPIO和一些其他外设的中断。可以实现单独对某一线配置中断触发方式等操作。


EXTI原理框图解释

EXTI

  边沿检测器检测外部的信号,上升沿和下降沿触发选择寄存器具体的配置会决定边沿检测电路检测何种边沿。


  检测到对应边沿后,检测电路输出1,软件中断事件寄存器的配置决定是否产生中断或事件,相当于小开关。


  若配置响应这个边沿,则小开关输出1。下面由请求挂起寄存器和事件屏蔽寄存器确定产生中断还是事件。这两个相当于选择开关。


  如果为中断,最后来到中断屏蔽寄存器,这相当于大开关。


  从原理图中我们可以看出,从输入线输入开始到NVIC向内核发出中断,中间要经过边沿检测电路,小开关,请求寄存器,大开关等寄存器。各个寄存器的对应名称已经标注在图片上。


输入线

  得知 EXTI 中断的过程后,探讨输入线部分内容。

  EXTI可以管理20根外部输入源,EXTI和对应外部输入源匹配后的整体叫做输入线。


外部的输入源与中断线EXTI的对应关系如下图

   EXTI的前16根线的输入源只能是GPIO端口,单独一根线允许连接GPIO的固定一种端口;如:EXTI0 只能连接 0 端口,如:PA0,PB0… 不能连接别的端口,如不可连接PA1,PB1…

在这里插入图片描述

输入源+中断线=输入线

小结:外部中断理论部分

要使用 EXTI 外部中断。对于中断过程中,要配置框图中的各种寄存器以达到目的。对于输入线,要配置输入源和中断线以组成输入线。


编程实例

实例简介

上面介绍了EXTI的原理,我们现在编写一个按键控制LED灯的程序,其中让EXTI来检测按键按下的动作,然后产生中断,在中断函数中反转LED灯。


实验的电路图

  

从图中我们可以看出,按键默认是低电平。按下后为高电平。我们希望按键按下时有动作,所以我们要设置PA0上升沿触发,然后在中断函数中控制PB5反转。


开始编程(一)

  首先我们在User文件夹下新建文件夹以存放C和H文件,并添加到USER下Group中,把H文件填入IncludePath.


初始化EXTI和GPIO

初始化EXTI

  根据经验,固件库中一定有初始化的函数。打开stm32f10x_exti.h翻到最下面我们就可以看见这个头文件所有函数,果然有


void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);


一看就知道这是初始化函数。打开后发现只需要一个结构体的传入,F12这个结构体我们看到:

在这里插入图片描述

我们可以看见这个结构体提供了 :


EXTI_Line : 用来选定PXm 中的m

EXTI_Mode : 用来选定工作方式->中断/事件

EXTI_Tigger : 触发方式

EXTI_LineCmd : 开启开关。

这些成员变量的取值一定被枚举或宏定义好了。向上向下翻找就可以找到。


  在这里你一定发现,通过初始化 EXTI ,可以确定中断线,但无法确定输入源。即只能指定 PXm 中的 m,无法确定其中的X。想要配置输入源 需要从GPIO库中的函数进行配置。


初始化GPIO

  老习惯,去找找固件库有没有这样的函数。打开stm32f10x_gpio.h翻到对最下面,我们可以看到这条函数


void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);


十分的神似,F12进去看看函数说明;

在这里插入图片描述

  通过函数的描述我们可以看见这就是用来配置EXTI中断的,并且同时指定了输入源和中断线。

  GPIO_PortSource指定输入源,GPIO_PinSource指定中断线。

  值得注意的是,这个函数已经在操作AFIO这个外设了,因此,开时钟时必须开启AFIO的时钟。


  对于这个例子,我们无需初始化GPIO,因为 PA0 的输入信号会直接通过 EXTI0 内部电路完成中断。但对于一种情况,GPIO的初始化是必要的,在思考中会 体现这一点。

  最后提醒一下,不要忘记打开时钟。


void EXTI_KEY_Config(void)

{

EXTI_InitTypeDef EXTI_InitStruct;

//这里还缺少一个配置中断优先级的函数,下面再说

//EXTI_NVIC_Config();

//初始化EXTI

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);         //千万别忘了打开时钟

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);  //选择输入线


//配置EXTI初始化函数的结构体

EXTI_InitStruct.EXTI_Line    = EXTI_Line0;

EXTI_InitStruct.EXTI_LineCmd = ENABLE;

EXTI_InitStruct.EXTI_Mode    = EXTI_Mode_Interrupt; 

EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发

EXTI_Init(&EXTI_InitStruct);


}


小结:外部中断寄存器配置部分

  通过上一个理论小结,我们需要配置框图中的寄存器保证中断可被内核接收,配置输入线保证外部中断可以传入。

  这里程序部分,初始化 EXTI 配置了框图中的寄存器,配置了中断线。初始化 GPIO和 AFIO配置了中断线和输入源,即完成了输入线的配置。


开始编程(二)

  由上节STM32中断应用总结的 中断编程顺序 可知,我们上面的工作不过是完成了第一步,配置外设中断。


配置中断优先级分组

初始化NVIC时要配置好优先级的分组方式,这就要用到


void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);


这个函数,其中的参数也可在上下的枚举中找到。我们设置优先级分组为1。


NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);


配置 NVIC 寄存器

配置这个寄存器需要完成对NVIC_InitTypeDef 这个结构体的配置。

其中结构体的成员变量NVIC_IRQChannel 的参数可以在IRQn_Type中找到,F12进入

在这里插入图片描述

  可以看见,IRQn_Type 事实上是一个枚举,而且其中使用宏定扩展对应了不同型号的F10x系列的芯片,值得注意的,EXTIm 中 m=0,1,2,3,4是所有芯片都有定义的,而且每个都有独立定义。但5-9,10-15就不是了,在下面大容量的宏定义中我们可以看见他们是被集体定义在一起的。在使用时要注意。

在这里插入图片描述

  我们编写一个 EXTI_NVIC_Config() 用来对NVIC进行初始化。设置主优先级为1,子优先级为1。


static void EXTI_NVIC_Config(void)//static 说明此函数只可被这个.c文件的函数调用

{

NVIC_InitTypeDef NVIC_InitStruct;

//配置优先级分组方式

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

//配置初始化函数

NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;

NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;

NVIC_Init(&NVIC_InitStruct);

}


至此所有的初始化工作已经完成,当被设置的端口有变化被检测到时,就会进入中断函数。


编写中断服务函数

  所有的中断函数都必须被编写在 stm32f10x_it.c文件中以便于管理。并且中断函数的名字必须和启动文件。打开启动文件startup_stm32f10x_hd.s,我们找到名称。

找到这个函数名后,我们希望进入中断后再判断一下EXTI中断挂起寄存器PR是否真的置位了,可以用这个函数,在exti中可以找到


ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);


他会返回ITStatus类型,即Set或Reset。


在完成操作后,我们必须把挂起寄存器里的置位清零,这样程序才能去运行下面的工作,而不是重复跳入中断函数。用于操作的函数在exti中也有。这一句不可缺少。


void EXTI_ClearITPendingBit(uint32_t EXTI_Line);


这两个对EXTI_PR寄存器操作的函数,所需的参数都是EXTI_Line。用用于指定函数操作的线。可以说EXTI_Line 和GPIO_PIN十分相似。


我们在stm32f10x_it.c中添加这个函数


/*这部分宏定义实现了LED反转的功能应当被定义在bsp_led.h中合适

这里为了便于观察附于此*/

#define LED_G_GPIO_PIN   GPIO_Pin_0

#define LED_G_GPIO_RORT  GPIOB

#define LED_G_TEOOGLE   {LED_G_GPIO_RORT->ODR ^= LED_G_GPIO_PIN;}


void EXTI0_IRQHandler(void)

{

//先判断是否真的置位了

if(EXTI_GetITStatus(EXTI_Line0) !=RESET)

{

LED_G_TEOOGLE;                       //LED 反转

EXTI_ClearITPendingBit(EXTI_Line0);  //清除中断标志位

}

}


附上之前已经用很多次的LED配置代码


void LED_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStruct;

RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK, ENABLE);


GPIO_InitStruct.GPIO_Pin   = LED_G_GPIO_PIN;

GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(LED_G_GPIO_RORT,&GPIO_InitStruct);


}


至此所以的准备就已经完成了,只需要在main中简单的调用就可以了。


int main(void)

{

LED_GPIO_Config();

EXTI_KEY_Config();

while(1){}

}


思考

  本次的实例中,输入线由 EXTI0 作为中断线,PA0作为输入源;一个中断线连接了一个输入源。


  但如果一个中断线连接了多个输入源,如PA0,PB0,PC0… 和 EXTI0 连接。这时 PA0,PB0,PC0… 中任何一个产生中断信号后,都是通过 EXTI0 这条中断线进入中断的。即这些线的中断信号最后都会由同一个中断服务函数处理。如何判断是那条线产生的中断呢?


  这里需要在中断服务函数中编写程序手动判断。主要思想是利用外部电平变化时,GPIO的 IDR 寄存器会记录电平。通过判断 IDR 的变化来判断是哪一个中断源。这时,在程序中就需要初始化输入的GPIO为浮空输入模式。(虽然浮空GPIO默认下就是浮空输入模式,为了保险起见,还是要初始化)


关键字:STM32  EXTI  外部中断 引用地址:STM32 EXTI外部中断小结

上一篇:STM32-不同芯片的移植
下一篇:STM32 PWM波比较输出

推荐阅读最新更新时间:2024-11-13 06:49

STM32学习012_产品研发流程(二)
3用户接口要求 需要确定产品硬件接口的种类和数量,电源接口,指示灯以及开关类型,复位按钮和显示屏幕,从而可以确定PCB的外围轮廓, 常用的用户接口主要有,JTAG接口,DB9串口(公头和母头),USB接口,Console接口,RJ45以太网接口,HDMI接口,VGA接口,SATA&IDE接口,PS2接口,CPCI接口,PCI以及PCI-E接口RJ11接口,S-Video视频接口,RCA视频接口(俗称莲花头),YPbPr/YCrCb视频色差输入接口,SD/TF卡接口,CF卡接口,SIM卡接口,RF射频端子,SCART接口,SPDIF数字音频接口,DisplayPort接口和光口, 常用的数据协议接口主要有SPI ,UART,LVDS
[单片机]
STM8L之外部中断
STM8L之外部中断 1、中断优先级 软件中断优先级设置函数 void ITC_SetSoftwarePriority(IRQn_TypeDef IRQn, ITC_PriorityLevel_TypeDef ITC_PriorityLevel) vector:中断向量号 prio:优先级(1~3),禁止设置为0 STM8的优先级分为软件优先级和硬件优先级,软件优先级高于于硬件优先级. 硬件优先级由向量号确定,向量号越小,优先级越高。 软件优先级可以通过本函数设置。 STM8软件优先级设置可以分为4个等级(0~3),实际上可设置的就三个等级:1~3 优先级顺序:0 1 2 3,3的优
[单片机]
STM8L之<font color='red'>外部中断</font>
STM32-自学笔记(4.丰富多样的外部设备中)
PWM输入模式: 定时器的捕获单元,还可以同时使用两个捕获通道测量一个外部PWM信号的周期和占空比。 在PWM的输入模式下,输入信号与两个捕获通道连接。假设使用捕获通道1,2。在PWM一个周期开始之后,捕获通道2在其上升沿将主计数器清除并开始向上计数,而随后捕获通道1捕获到PWM的下降沿,此时就得到高电平周期。而捕获通道2再次捕获到下一个周期的PWM的上升沿,就可以得到PWM的周期。并将计数器清楚,准备下一次测量。 编码器接口: 每个定时器的捕获单元都可以和外部的编码器连接。编码器接口的一个典型的应用是电机的角速度和转角位置的检测。 捕获单元在编码器接口工作模式下,由捕获引脚提供定时计数器的驱动时钟,显然该计数器可以识
[单片机]
STM32中断与嵌套NVIC快速入门
简介:STM32 中断与嵌套NVIC 快速入门 //==================================================== // STM32 中断与嵌套NVIC 快速入门 // netjob 2008-8-1 //==================================================== STM32中断与嵌套NVIC快速入门 我也是靠看这本书才弄懂的: Cortex-M3 权威指南 Joseph Yiu 著 宋岩 译 其实很简单。 //CM3 有 最多240个中断(通常外部中断写作IRQs),就是 软件上说的 IRQ CHA
[单片机]
STM32进阶-DHT11传感器的应用详细步骤
DHT11概述 接口说明 电源引脚 DHT11的供电电压为 3-5.5V。传感器上电后,要等待 1s 以越过不稳定状态在此 期间无需发送任何指令。电源引脚(VDD,GND)之间可增加一个100nF 的电容,用以去耦滤波。 DHT11数据处理 串行接口 (单线双向) DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次 通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数 部分用于以后扩展,现读出为零.操作流程如下: 一次完整的数据传输为40bit,高位先出。 数据格式:8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据 +8bit校
[单片机]
<font color='red'>STM32</font>进阶-DHT11传感器的应用详细步骤
STM32开发笔记16: 使用静态库加快Keil编译速度
单片机型号:STM32L053R8T6 使用Stm32CubeMx生成的源文件数量比较多,编译的时候会占用很长的时间,我们仔细观察这些文件除了main.c外,其它的文件我们基本上是调用其中的函数,并不需要对其进行改动。所以,可以仿照Freescale MQX的设计方法,分层进行编译,下图是在进行项目设计时候的层次结构。 第0层用于存储Stm32CubeMx生成的工成文件,第2层处理除main.c以外的所有文件,第3层加入应用层的逻辑结构。 第0层的处理方法,大家参考Stm32CubeMx的使用方法,就可以了。 第1层的处理方法,也非常简单,可通过以下步骤完成: 1、在工程目录结构
[单片机]
<font color='red'>STM32</font>开发笔记16: 使用静态库加快Keil编译速度
ARM - STM32 使用11.0592MHz晶振
这里探究了以下stm32 外部时钟的用法。 这里用的是stm32f103rbt6,usart2,外部晶振11.0592Mhz。 先看时钟树吧 这是上图的配置: void RCC_Init(void) { ErrorStatus HSEStartUpStatus; RCC_DeInit(); RCC_HSEConfig(RCC_HSE_ON); //设置外部高速晶振(HSE) HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE起振 if(HSEStartUpStatus == SUCCESS) //SUCCESS:HSE晶振稳定且就绪 { R
[单片机]
ARM - <font color='red'>STM32</font> 使用11.0592MHz晶振
STM32是怎样进入执行中断函数xxx_IRQHandler(void)的
在STM32单片机的编程当中,中断函数的名称都是xxx_IRQHandler格式的。那当编译程序的时候是怎么知道这是一个中断函数的呢? 每个中断都是有入口地址的。程序在执行过程中遇到中断的时候,会先判断这个中断的类型,根据类型再到中断向量表中查找,找到之后,根据表中指明的地址,程序就跳到该地址开始执行代码。 ST提供的固件库当中,有提供一个stm32f10x_it.c文件,打开之后会发现里面放的都是些空函数,但是名字都是“xxx_Handler()”格式,需要使用某个中断的时候,在代码中使能该中断,并到这个文件中将中断服务函数添加上,就可以了。 而这些名字就是一个个的中断函数入口地址。在启动代码中便有这些定义。如下图所示:
[单片机]
<font color='red'>STM32</font>是怎样进入执行中断函数xxx_IRQHandler(void)的

推荐帖子

8051 和 zigbee的問題
第一次接觸zigbee想利用zigbee透過8051作收發data之用但是只知道zigbee的rxtx接去8051的rxtx而且zigbee到8051的program也沒有有人能提供一下嗎寫作的方法?8051和zigbee的問題
getover RF/无线
分享一个开机运行10秒进入LPM4的代码
测试开机运行10秒后,进入LPM4深度睡眠完全掉电。由P1.3外部中断唤醒后进入正常工作,10秒后再度进入掉电,如此循环,验证正确。externunsignedcharcount;/*========main========*/intmain(void){Grace_init();//ActivateGrace-generatedconfigurationfor(;;){
Aguilera 微控制器 MCU
【micropython教程】+3 RTC的datetime数组参数读取
一,前言继续爱折腾,今天折腾RTC,焊接上电池以后,就开工作咯。。二,RTC函数在help()函数帮助下可以轻松找到RTC函数,本次实验使用到的几个函数见图所示。。今天在玩RTC的时候发现RTC.datetime()函数中有年,月,周,日,小时,分钟,秒还有毫秒等参数,如果能把这些参数拿出来用那不是很方面吗?比如定时比如在判断时间或者数字的时候进行跳转,说干就干,但是第一步就是要提取RTC.datetime
飞扬自我 MicroPython开源版块
最简单的AVR定时器的问题
由于本人是初学者,如果问题太没有含精量大家别见外啊我编译的60秒定时器不知道为什么就是不能再protues上实现。以下是源代码和protues仿真图,希望大家帮帮忙啊#includeiom16v.h#includemacros.h#defineuintunsignedint#defineucharunsignedcharuchartable={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};uin
Learner_new Microchip MCU
谁做过0-30V的直流电压表 
谁做过0-30V的直流电压表 ,有相关资料吗,希望发一下,加我QQ:175283992谁做过0-30V的直流电压表 我也在搞一个电压表好头疼啊,我发了一些资料上来你看看能有帮助吗?https://bbs.eeworld.com.cn/thread-331637-1-1.html我还没弄完,可以一起研究下。
book11 单片机
【2024 DigiKey创意大赛】esp32s3 klipper面板提交
一、作品简介米娜大家好啊,这一次eeworld的活动咱也是白嫖上了(雾),这次咱申请的是esp32s3lcdevboard和一个stm32f401rct6的开发板,stm32f401rct6各位都很熟悉了就不再多说了,esp32s3lcd这块板子倒是挺好的,这屏幕是真的大啊(舔嘴),这块屏幕尺寸正好可以当86盒子,太适合做点面板了,但是因为作者家里只能家居设备实在是太少了玩homeassitant感觉也没什么太大的意思,正好有台旧的kp3s打印机刚被作者刷了个klipp
翻车鱼日历 DigiKey得捷技术专区
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved