-
2022-06-02 20:07:05
文章目录
- 一、思路步骤(看懂这张图)
- 1. 打开RCC时钟树
- 2.配置GPIO(三种模式)
- 3.配置AFIO中断引脚选择
- 4.打开EXTI
- 5.配置NVIC(先选择组在初始化NVIC)
- 6.自己书写中断函数
提示:以下内容仅供参考
一、使用步骤
1. 打开RCC时钟树
代码如下(示例):
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);
2.配置GPIO(三种模式)
代码如下(示例):
//利用外部中断,按键来控制LED GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct);
3.配置AFIO中断引脚选择
代码如下(示例)
//打开AFIO,选择路线配置为中断模式 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15); //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
4.打开EXTI
代码如下(示例)
//初始化EXTI EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line=EXTI_Line15|EXTI_Line5;//15ÊÇϽµÑØ EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line=EXTI_Line0;//0ÊÇÉÏÉýÑØ EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_Init(&EXTI_InitStructure);
5.配置NVIC
代码如下(示例)
//配置NVIC NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=3; NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn ; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=3; NVIC_Init(&NVIC_InitStruct);
6.自己书写中断函数
//自己书写函数 void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0)==SET)//WKUP { LED2_GPIOD_Turn(); LED8_GPIOA_Turn(); EXTI_ClearITPendingBit(EXTI_Line0); } } void EXTI9_5_IRQHandler(void)//KEY0 { if(EXTI_GetITStatus(EXTI_Line5)==SET) { LED8_GPIOA_Turn(); EXTI_ClearITPendingBit(EXTI_Line5); } } void EXTI15_10_IRQHandler(void)//KEY1 { if(EXTI_GetITStatus(EXTI_Line15)==SET) { LED8_GPIOA_Turn(); EXTI_ClearITPendingBit(EXTI_Line15); } }
7.主函数
#include "stm32f10x.h" // Device header #include "Delay.h" #include "LED.h" #include "Key.h" #include "EXTI.h" int main() { LED_Init(); Key_Init(); My_EXTI_Init(); while(1) { } }
8.总结
#include "stm32f10x.h" // Device header #include "LED.h" void My_EXTI_Init(void) { //打开RCC时钟树 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //配置AFIO RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15); //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5); //配置EXTI EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line=EXTI_Line15|EXTI_Line5;//15ÊÇϽµÑØ EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line=EXTI_Line0;//0ÊÇÉÏÉýÑØ EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_Init(&EXTI_InitStructure); //配置NVIC NVIC_InitTypeDef NVIC_InitStruct; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=3; NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn ; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=3; NVIC_Init(&NVIC_InitStruct); } //自己书写中断函数 void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0)==SET)//WKUP { LED2_GPIOD_Turn(); LED8_GPIOA_Turn(); EXTI_ClearITPendingBit(EXTI_Line0); } } void EXTI9_5_IRQHandler(void)//KEY0 { if(EXTI_GetITStatus(EXTI_Line5)==SET) { LED8_GPIOA_Turn(); EXTI_ClearITPendingBit(EXTI_Line5); } } void EXTI15_10_IRQHandler(void)//KEY1 { if(EXTI_GetITStatus(EXTI_Line15)==SET) { LED8_GPIOA_Turn(); EXTI_ClearITPendingBit(EXTI_Line15); } }
主函数
#include "stm32f10x.h" // Device header #include "Delay.h" #include "LED.h" #include "Key.h" #include "EXTI.h" int main() { LED_Init(); Key_Init(); My_EXTI_Init(); while(1) { } }
总结
最主要的是要看懂最前面的那张图,理解
更多相关内容 -
EXTI重复配置两次导致误触发中断的问题
2020-07-18 13:53:21有些工程师非常的小心,小心到甚至在程序中对一个外设配置完一次还不放心,还要再配置一次。这本身看起来没有什么问题,但是在特定的外设中,反而会不小心造成一些小问题,比如这里所要说的EXTI。 -
STM32外部中断EXTI实现按键控制LED灯
2020-12-20 10:11:22使用外部中断的方式实现按键控制LED灯,不使用按键扫。适合刚入门的新手 -
18-EXTI—外部中断_exti相关配置_
2021-10-03 12:29:30配置exti校验程序,适合stm32f10x系列的单片机驱动代码exti中断等操作 -
EXTI_Config_stm32f103zet6_EXTI_源码
2021-10-01 05:09:33EXTI_Config EXTI configuration example -
1.stm32f103学习笔记,EXTI按键中断点亮小灯应用
2020-10-08 13:58:11中断在嵌入式应用中占有非常重要的地位,几乎每个控制器都有中断功能。中断对保证紧急事件得到第一时间处理是非常重要的。我们设计使用外接的按键来作为触发源,使得控制器产生中断,并在中断服务函数中实现控制 RGB... -
STM32L051C8T6_EXTI.zip
2020-04-16 13:03:06采用HAL库生成的工程文件实现STM32L051C8T6的外部中断控制,实现简单按键通过中断方式控制LED的状态翻转代码。 -
STM32之EXTI——外部中断
2020-07-14 04:59:08互联网的广大网友,大家早上中午晚上好、EXTI、、、故名思义、、EX表外,出、、I表示Intrrupt、、所以合起来就是外部中断、、、说到这、、我觉得我最近的六级水平(背单词)又进了一步,稍微自夸了下下、、英语重要... -
EXTI仿真.rar
2020-04-15 17:30:10实现按键控制LED亮灭,包含原理图及代码。采用单片机:STM32,仿真软件:Proteus,编程软件:MDK-ARM -
电子-exti.h
2019-09-05 21:22:40电子-exti.h,单片机/嵌入式STM32-F0/F1/F2 -
第十一届蓝桥杯物联网设计与开发实验——ex9 EXTI外部中断实验
2021-01-20 11:04:20ex9 EXTI外部中断实验 实验目的:掌握EXTI的使用方法。 实验内容:按下USER按键触发外部中断EXTI14。 实验现象:每按下一次USER按键,LD5灯显示反转一次。 中断概念 中断全过程 中断发生——当CPU在处理某一事件A时... -
stm32exti.rar
2020-04-19 21:28:31关于实现STM32F10x的中断程序控制LED灯亮灭,其中选择使用GPIOA管脚Pin_0端口进行...初始状态灯熄灭,当按下按键,检测跳转到EXTI0_IRQHandler函数中执行中断控制,GPIOA取反并延时,清除标志位,等待下一次按键按下。 -
STM32F10X系列 EXTI及寄存器记录.docx
2020-12-03 17:57:06重新加深STM32F103系列EXTI外部中断,结合“正点原子”相关教材和《STM32中文参考手册》,写了这篇关于EXTI的总结文档,防止自己忘记后有迹可查。 -
3 HAL_EXTI_KEY_LED.zip
2021-04-10 16:40:35蓝桥杯嵌入式比赛开发板:STM32G431RBT6 实验:外部中断+按键控制LED亮灭 -
STM32实例程序 4.EXTI_test外部中断事件
2022-06-28 06:51:10STM32实例程序 4.EXTI_test外部中断事件STM32实例程序 4.EXTI_test外部中断事件STM32实例程序 4.EXTI_test外部中断事件STM32实例程序 4.EXTI_test外部中断事件STM32实例程序 4.EXTI_test外部中断事件STM32实例程序 4... -
stm32-407控制外部中断exti
2021-04-20 19:46:28stm32-407控制外部中断exti -
电子-exti.c
2019-09-05 21:22:41电子-exti.c,单片机/嵌入式STM32-F0/F1/F2 -
_08_exti_key.zip
2021-03-04 09:31:39stm32f103的按键外部中断make形式工程 -
EXTI中断使用例子
2018-04-28 22:16:52一个STM32开发中EXTI中断使用的简单例子,实现了一个简单的经典的按键触发中断 -
STM32的EXTI外部中断(直接操作寄存器)
2017-11-28 17:54:11STM32的EXTI外部中断(直接操作寄存器),亲测可用,内有详细代码注释和说明讲解,很好的学习资料。 -
中断-NVIC与EXTI外设详解(超全面)
2022-04-14 20:53:30选择中断线与EXTI 初始化结构体详解 选择中断线 在配置中断线时一定要先使能AFIO外设的时钟,因为配置中断线是用到ADIO外设的寄存器,我们知道配置寄存器必须要有时钟 使能时钟 配置中断线 配置EXTI初始化结构体 1) ...目录
一.NVIC-嵌套向量中断控制器
NVIC :嵌套向量中断控制器,属于内核外设,管理着包括内核和片上所有外设的中断相关的功能。
这里解释一下片上外设与内核外设他们都在芯片里面,但内核外设是在内核CPU里面,片上外设就是内核之外咯。
NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对 Cortex-M3 内核里面的 NVIC 进行裁剪,把不需要的部分去掉,所以STM32 的 NVIC 是 Cortex-M3 的 NVIC 的一个子集。
几个关于内核外设重要的库文件:
Cortex-M3 内核的外设也比较多,但STM32并没有用到这么多内核外设对其进行了裁剪,STM32重要的内核外设用到的库函数放在了misc.c文件之中所以core_cm3.c文件用的较少。core_cm3.c:内核外设的驱动固件库
core_cm3.h:实现了内核(CPU)里面的外设的寄存器映射,还有很多关于内核外设的库函数。
misc.h:NVIC_InitTypeDef结构体,以及库函数的参数和声明
misc.c:NVIC(嵌套向量中断控制器)、SysTick(系统滴答定时器)相关函数1.中断向量表
CM3 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256级的可编程中断设置。但 STM32 并没有使用 CM3 内核的全部东西,而是只用了它的一部分。STM32 有 84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级。而我们常用的就是这 68 个可屏蔽中断,但是 STM32 的 68 个可屏蔽中断,在 STM32F103 系列上面,又只有 60 个(在 107 系列才有 68 个)。
而我要讲的是103系列其中系统异常有 8 个(如果把 Reset 和 HardFault 也算上的话就是 10 个),外部中断有 60个。除了个别中断的优先级被定死外,其它中断的优先级都是可编程的。
下面灰色的就是系统异常(中断),中断就是异常,异常就是中断这里就不区分了,表中的优先级是硬件编号,数字越小优先级越高这里复位中断的编号最小,所以一按板子上的复位键会立马执行复位程序。
2.NVIC内核外设寄存器
NVIC管理着中断向量表中的60个中断
在固件库中,NVIC 的结构体定义给每个寄存器都预留了很多位,恐怕为的是日后扩展功能。不过 STM32F103 可用不了这么多,只是用了部分而已
具体使用了各个寄存器使用了多少个请看图
- ISER[8]:ISER 全称是:Interrupt Set-Enable Registers:这是一个中断使能寄存器组(有8个这样的寄存器)。
上面STM32F103 的可屏蔽中断只有 60 个,一个寄存器有32位一位可以表示一个中断两个寄存器总共可以表示 64 个中断。而 STM32F103 只用了其中的前 60 位。所以对我们来说,有用的就是两个(ISER[0]和 ISER[1])
,ISER[0]的 bit0-bit31 分别对应中断 0-31。ISER[1]的 bit0-27 对应中中断32~59;这样总共 60 个中断就分别对应上了。你要使能某个中断,必须设置相应的 ISER 位为 1,使该中断被使能(这里仅仅是使能,还要配合中断分组、屏蔽、IO 口映射等设置才算是一个完整的中断设置)。
-
ICER[8]:全称是:Interrupt Clear-Enable Registers:是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。向寄存器写1清除写0无效。
-
ISPR[8]:全称是:Interrupt Set-Pending Registers:是一个中断挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。通过置 1
当置位中断挂起寄存器的时候,相应的中断将会被挂起,此时这个中断将不会立即执行,而是等待可执行的时候再执行;比如高低级别的中断同时产生,就先挂起低级别的中断,等高级别的中断执行完毕,解除并执行低级中断这个过程一般是自发进行
。 -
ICPR[8]:全称是:Interrupt Clear-Pending Registers:是一个中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。通过设置 1,可以将挂起的中断解除挂起。写 0 无效。
-
IABR[8]:全称是:Interrupt Active Bit Registers:是一个中断激活标志位寄存器组。对应位所代表的中断和 ISER 一样,
如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个
。在中断执行完了由硬件自动清零。 -
IP[240]:全称是:Interrupt Priority Registers:是一个中断优先级控制的寄存器组。这个寄存器组相当重要!STM32 的中断分组与这个寄存器组密切相关。240 个 8bit 的寄存器组成,每个可屏蔽中断占用 8bit,这样总共可以表示 240 个可屏蔽中断。
而 STM32 只用到了其中的前 60 个。IP[59]-IP[0]分别对应中断 59~0也就是说:一个中断需要一个IP寄存器来配置优先级。 比如说中断硬件编号为20的中断配置的寄存器就为IP[20]
看图所知这里只分配了80个IP寄存器但对我们配置60中断绰绰有余,这里建议一下一定要去看看Cortex-M3编程手册有关NIVC的寄存器,这样心底有个底。IP寄存器 宽度为 8bit,原则上每个外部中断可配置的优先级为 0~255(十进制),数值越小,优先级越高。但是绝大多数 CM3 芯片都会精简设计,以致实际上支持的优先级数减少,在F103 中,只使用了高 4bit,如下所示:
用于表达优先级的这 4bit,又被分组成抢占优先级和响应优先级STM32 将中断分为 5 个组,组 0-4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。
比如组2来说:2位配置抢占式优先级(00 01 10 11)换成十进制不就是0~3嘛,2位配置响应式优先级0 ~3,数字越小优先级越高其他分组以此类推。
注意:组1抢占式优先级0位,那就没有抢占式优先级,- 配置分组
在系统代码执行的过程只进行一次中断优先级分组,设置分组之后一般不会进行变动,不然中断执行会混乱,如:假设你分成组2,抢占式优先级有2位,后面改成组3的话,就会变成3位抢占式优先级,则之前的一位响应优先级变成了抢占式优先级,则之前配置的抢占式和响应优先级的值就不确定了乱套了。
- 抢占式优先级与响应式优先级的区别
加深理解:
1.抢占式优先级高的可以打断正在执行的(抢占式优先级低)中断(挂起),转而执行抢占式优先级高的中断执行完毕后在返回原来(抢占式优先级低)中断继续执行,这就是所谓的中断嵌套。而响应优先级并不能嵌套
2.若抢占式优先级与响应式优先级都相同则硬件编号(在中断向量表的排序顺序)小的先执行
3.中断编程
一般中断使能一般有两个门,外设使能相应的中断然后送入NVIC再使能,外设使能中断是小门,NVIC使能中断是大门,只有都使能才能响应中断。
1.使能外设某个中断,这个具体由每个外设的相关中断使能位控制。
2.配置中断优先级分组,然后初始化 NVIC_InitTypeDef 结构体,设置抢占优先级和子优先级,使能中断请求。NVIC_InitTypeDef 结构体在固件库头文件 misc.h 中定义。
配置中断优先级分组
初始化 NVIC_InitTypeDef 结构体- NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序也不会报错,只会导致不响应中断。具体的成员配置可参考stm32f10x.h 头文件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。
-
NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定。
-
NVIC_IRQChannelSubPriority:子优先级(响应优先级),具体的值要根据优先级分组来确定 。
-
NVIC_IRQChannelCmd:中断使能(ENABLE)或者(DISABLE)。操作的是 NVIC_ISER 和 NVIC_ICER 这两个寄存器。
配置好 NVIC_InitTypeDef 结构体然后就调用NVIC_Init()函数,由函数将参数写入寄存器
现在来具体来分析一下这个函数加深我们对NVIC寄存器的理解
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct) { uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F; /* Check the parameters */ assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd)); assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority)); assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority)); if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE) { /* Compute the Corresponding IRQ Priority --------------------------------*/ tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08; tmppre = (0x4 - tmppriority); tmpsub = tmpsub >> tmppriority; tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre; tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub; tmppriority = tmppriority << 0x04; NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority; /* Enable the Selected IRQ Channels --------------------------------------*/ NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); } else { /* Disable the Selected IRQ Channels -------------------------------------*/ NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); } }
3、编写中断服务函数
在启动文件 startup_stm32f10x_hd.s 中我们预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,为了方便管理我们把中断服务函数统一写在 stm32f10x_it.c 这个库文件中。
如果一切配置完毕,当中断来临时,CPU会根据相应的中断去中断向量表找到对应的中断函数的地址,然后调用执行中断服务函数。
二.EXTI—外部中断/事件控制器
这里的外部中断是指由外部条件触发例如按键触发(GPIO),对于互联型产品(F107),外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它产品(我们这里是F103),则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求
1.外部中断/事件线路映像
而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。
EXTI16~19也作为EXTI外设的输入线
16个中断线的不是每个中断都有独立的中断服务函数,IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数
从表中可以看出,外部中断线5~9分配一个中断向量,共用一个服务函数。
外部中断线10~15分配一个中断向量,共用一个中断服务函数。对应的中断服务函数,直接去启动文件里面找以防写错。
2.EXTI功能框图
信号线上打一个斜杠并标注“20”字样,这个表示在控制器内部类似的信号线路有 20 个,这与 EXTI 总共有 20 个中断/事件线是吻合的。所以我们只要明白其中一个的原理,那其他 19 个线路原理也就知道了
通过在软件中断/事件寄存器写’1’,也可以通过软件产生中断/事件请求
脉冲发生器:
输入一个有效信号 1 时就会产生一个脉冲,如果输入端是无效信号就不会输出脉冲。这个脉冲信号可以给其他外设电路使用,比如定时器 TIM、模拟数字转换器 ADC 等等,这样的脉冲信号一般用来触发 TIM 或者 ADC 开始转换中断与事件的区别:
- 中断:需要CPU参与,需要调用软件的中断服务函数才能完成中断后产生的结果
- 事件:靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,触发TIM计时,AD转换等,事件不要软件的参与,降低了CPU的负荷,而且硬件速度快于软件速度
详情推荐一篇文章:《中断与事件的区别》
接下来逐一介绍用到的寄存器,进一步理解框图原理:
- 外部中断配置寄存器
- 上升&下降沿触发选择寄存器
在同一中断线上,可以同时设置上升沿和下降沿触发。即任一边沿都可触发中断
- 软件中断事件寄存器(EXTI_SWIER)
- 挂起寄存器
中断或事件屏蔽寄存器
3.选择中断线与EXTI 初始化结构体详解
- 选择中断线
在配置中断线时一定要先使能AFIO外设的时钟,因为配置中断线是用到ADIO外设的寄存器,我们知道配置寄存器必须要有时钟
使能时钟
配置中断线
- 配置EXTI初始化结构体
1) EXTI_Line:EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19。
2) EXTI_Mode:EXTI 模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)。
3) EXTI_Trigger:EXTI 边沿触发事件可选上升沿触发(EXTI_Trigger_Rising)、下降沿触发 ( EXTI_Trigger_Falling) 或者上升沿和下降沿都触发( EXTI_Trigger_Rising_Falling)。
4) EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线(ENABLE)或禁用(DISABLE)。
最后调用EXTI_Init函数,将结构体配置好的参数写入对应的寄存器,这个比较简单我就不讲了,这里提一下这个结构体中断/事件线的选择并不是配置中断线/事件线,配置线的函数上面已经提及,这里选择线是为了知道中断线在寄存器哪个位置(019)对应中断线(EXTI019),好配置相应的寄存器。
三.外部中断控制实验
实验目的:利用按键产生一个下降沿,让系统产生一个中断,执行中断服务函数,函数将GPIO电平翻转使得灯,按一下亮按一下灭。
实验原理
EXTI程序框图分析:
编程要点
1) 初始化用来产生中断的 GPIO;
2) 初始化 EXTI;
3) 配置 NVIC;
4) 编写中断服务函数;直接上代码咯:
exti.c
#include "exti.h" static void NVIC_EXTI_Config(void) { NVIC_InitTypeDef NVIC_InitStruct; //中断优先级分组这里是组1 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //选择中断源 NVIC_InitStruct.NVIC_IRQChannel= EXTI15_10_IRQn; //设置抢占式优先级 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =1; //设置响应式优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority =1; //使能中断源 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //调用NVIC初始化函数 NVIC_Init(&NVIC_InitStruct); } void EXTI_Key_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; EXTI_InitTypeDef EXTI_InitStruct; RCC_APB2PeriphClockCmd(EXTI_Key1_GPIO_CLK,ENABLE); //上拉输入 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin= EXTI_Key1_GPIO_PIN ; GPIO_Init(EXTI_Key1_GPIO_POTR,&GPIO_InitStruct); //配置NVIC中断 NVIC_EXTI_Config(); //一定要使能外设AFIO外设的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //选择信号源 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15); //选择中断线 EXTI_InitStruct.EXTI_Line = EXTI_Line15; //选择模式这里选择中断模式 EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //下降沿模式 EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //使能中断 EXTI_InitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStruct); }
exti.h
#ifndef __EXTI_H #define __EXTI_H #include "stm32f10x.h" #define EXTI_Key1_GPIO_PIN GPIO_Pin_15 #define EXTI_Key1_GPIO_POTR GPIOA #define EXTI_Key1_GPIO_CLK RCC_APB2Periph_GPIOA void EXTI_Key_Config(void); #endif /*__EXTI_H */
main.c
#include "stm32f10x.h" #include "led.h" #include "exti.h" #define SOFT_DELAY Delay(0x0FFFFF); void Delay(__IO u32 nCount); int main(void) { /* LED 端口初始化 */ LED_GPIO_Config(); EXTI_Key_Config(); LED_G(OFF); LED_R(OFF); while(1) { } } void Delay(__IO uint32_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); }
中断服务函数
void EXTI15_10_IRQHandler(void) { //防抖 Delay(0x0FFFF); //判断按键是否按下 if( GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)== 0) { if( EXTI_GetITStatus(EXTI_Line15) != RESET ) { //电平翻转 GPIOA->ODR ^= GPIO_Pin_8; } //清除中断挂起位 EXTI_ClearITPendingBit(EXTI_Line15); } }
注意:执行完函数时一定要清除中断挂起为,不然系统会一直进入中断函数
实验效果
四.总结
由于本文涉及的知识点太多,参考了很多资料然后结合自己的理解写出这篇文章快接近万字了,到这终于写完啦,如果有错误还请指正,如果涉及到初始化函数那些寄存器具体怎么运算写入的不懂的可以评论区问我,建议虽然是库函数数编程,但尽量去看看函数是如何将参数写入寄存器的以及各个寄存器的作用,这样可以极大加深我们对原理的理解。觉得文章对你有所帮助就快快点赞收藏叭!!!
- ISER[8]:ISER 全称是:Interrupt Set-Enable Registers:这是一个中断使能寄存器组(有8个这样的寄存器)。
-
STM32中断—EXTI外部中断
2022-06-18 23:48:01EXTI_InitStructure.EXTI_Line=EXTI_Line0 | EXTI_Line1;//0行 EXTI_InitStructure.EXTI_LineCmd=ENABLE;//开启 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式 EXTI_InitStructure.EXTI_...5. 中断
中断系统
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
中断执行流程
STM32中断
- 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设
- 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级
本节学习
- EXRI1——EXRI2——EXRI3——EXRI4——EXRI9_5——EXRI15_10
后面的地址是干什么的?
这是因为中断函数,它的地址是由编译器来分配,是不固定的,但是我们的中断跳转,由于硬件的限制,只能跳到固定的地址执行程序,所以为了能让硬件跳转到一个不固定的中断函数里
NVIC基本结构
NVIC优先级分组
- NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级
- 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
分组方式 抢占优先级 响应优先级 分组0 0位,取值为0 4位,取值为0~15 分组1 1位,取值为0~1 3位,取值为0~7 分组2 2位,取值为0~3 2位,取值为0~3 分组3 3位,取值为0~7 1位,取值为0~1 分组4 4位,取值为0~15 0位,取值为0 5.1 EXTI外部中断
5.1.1 EXTI简介
- EXTI(Extern Interrupt)外部中断
- EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
- 支持的触发方式:上升沿/下降沿/双边沿/软件触发
- 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
- 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
- 触发响应方式:中断响应/事件响应
5.1.2 EXTI基本结构
5.1.2 AFIO复用IO口
- AFIO主要用于引脚复用功能的选择和重定义
- 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
5.1.3 EXTI框图
总结:
- 对应想要获取的信号是外部驱动的很快的突发信号,对应这种情况,可以考虑使用STM32的外部中断
5.1.4 旋转编码器介绍
- 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
- 类型:机械触点式/霍尔传感器式/光栅式
机械触点一般不用于电机测速
硬件电路
我们只需要把这个外部中断的路线打通即可
5.1.5 对射式红外线传感器计次数
AFIO的库函数和GPIO在一个文件里
void GPIO_AFIODeInit(void);
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);CountSensor.c
PB14号引脚的电平信号,就顺利通过了AFIO,进入到后级的EXTI电路了
#include "stm32f10x.h" // Device header //定义一个全局变量计数 //默认0 uint16_t CountSensor_Count; void CountSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启时钟 //EXTI和NVIC两个外设的时钟一直都是打开的 //NVIC是内核的外设,是不需要开启时钟的 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); //PB14号引脚的电平信号,就顺利通过了AFIO,进入到后级的EXTI电路了 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14); //初始化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); //配置NOIC //分组方式整个芯片就只能用一组 //可以放到主函数的最开始 //放到模块里需要保证每个模块一致 //取值范围抢占优先级(0-3),响应优先级(0-3) NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStruct; //需要在当前工程搜索IRQn_Type //选择对应的中断通道 NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //设置抢占优先级(0-3) NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //设置响应优先级(0-3) NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; NVIC_Init(&NVIC_InitStruct); } uint16_t CountSensor_Get(void) { return CountSensor_Count; } //参考启动文件文件中的中断向量表 //中断函数的名字都是固定的(无参,无返回值) void EXTI15_10_IRQHandler(void) { //先进行,中断标准位的判断(确保是我们想要的中断源触发的这个函数) if(EXTI_GetITStatus(EXTI_Line14)==SET) { CountSensor_Count++; //注意需要清除中断标志位,否则程序会不断的响应中断 //程序就卡死在了中断函数 EXTI_ClearITPendingBit(EXTI_Line14); } }
CountSensor.h
#ifndef __COUNTSENOR_H #define __COUNTSENOR_H #include "stm32f10x.h" // Device header uint16_t CountSensor_Get(void); void CountSensor_Init(void); #endif
main.c
OLED代码 -->见STM32——OLED显示屏#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "CountSensor.h" int main() { OLED_Init(); CountSensor_Init(); OLED_ShowString(1,1,"Count:");//显示字符串 while(1) { OLED_ShowNum(1,7,CountSensor_Get(),5); } }
5.1.6 旋转编码器计次
连线图
中断代码思路
Encoder.c
#include "stm32f10x.h" // Device header //定义一个全局变量计数 //默认0 int16_t Encoder_Count; void Encoder_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启时钟 //EXTI和NVIC两个外设的时钟一直都是打开的 //NVIC是内核的外设,是不需要开启时钟的 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); //PB14号引脚的电平信号,就顺利通过了AFIO,进入到后级的EXTI电路了 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1); //初始化EXTI EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line=EXTI_Line0 | EXTI_Line1;//0行 EXTI_InitStructure.EXTI_LineCmd=ENABLE;//开启 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式 EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发 EXTI_Init(&EXTI_InitStructure); //配置NOIC //分组方式整个芯片就只能用一组 //可以放到主函数的最开始 //放到模块里需要保证每个模块一致 //取值范围抢占优先级(0-3),响应优先级(0-3) NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStruct; //需要在当前工程搜索IRQn_Type //选择对应的中断通道(0) NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //设置抢占优先级(0-3) NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //设置响应优先级(0-3) NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; NVIC_Init(&NVIC_InitStruct); //需要在当前工程搜索IRQn_Type //选择对应的中断通道(1) NVIC_InitStruct.NVIC_IRQChannel=EXTI1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //设置抢占优先级(0-3) NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //设置响应优先级(0-3) NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; NVIC_Init(&NVIC_InitStruct); } //返回变化值 uint16_t Encoder_Get(void) { int16_t Temp; Temp=Encoder_Count; return Temp; } //参考启动文件文件中的中断向量表 //中断函数的名字都是固定的(无参,无返回值) void EXTI0_IRQHandler(void) { //先进行,中断标准位的判断(确保是我们想要的中断源触发的这个函数) if(EXTI_GetITStatus(EXTI_Line0)==SET) { //读取PB1的电平,是不是低电平 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0) { Encoder_Count--; } //注意需要清除中断标志位,否则程序会不断的响应中断 //程序就卡死在了中断函数 EXTI_ClearITPendingBit(EXTI_Line0); } } void EXTI1_IRQHandler(void) { //先进行,中断标准位的判断(确保是我们想要的中断源触发的这个函数) if(EXTI_GetITStatus(EXTI_Line1)==SET) { //读取PB1的电平,是不是低电平 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0) { Encoder_Count++; } //注意需要清除中断标志位,否则程序会不断的响应中断 //程序就卡死在了中断函数 EXTI_ClearITPendingBit(EXTI_Line1); } }
Encoder.h
#ifndef __ENCODER_H #define __ENCODER_H #include "stm32f10x.h" // Device header void Encoder_Init(void); uint16_t Encoder_Get(void); #endif
main.c
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Encoder.h" int16_t Num; int main() { OLED_Init(); Encoder_Init(); OLED_ShowString(1,1,"Num:");//显示字符串 while(1) { Num+=Encoder_Get(); OLED_ShowSignedNum(1,5,Num,5); } }
建议:在中断函数里不要执行耗时过长的代码
既然都看到最后了,可否给个
呢,
关注收藏不迷路
给那些看完的朋友,奖励一个 赤赤博客-后端+前端,觉得不错的话可以推荐给身边的朋友哟!
-
STM32 EXTI外部中断/事件
2022-06-19 17:17:58一、EXTI外部中断/事件功能框图 1、中断线路:①-②-③-④-⑤ ①输入线:有19个中断/事件输入线(联网型有20个),通过寄存器将这些输入线设置为任意一个GPIO。 ②边沿检测电路:选择上升沿触发、下降沿触发或者...一、EXTI外部中断/事件功能框图
1、中断线路:①-②-③-④-⑤
①输入线:有19个中断/事件输入线(联网型有20个),通过寄存器将这些输入线设置为任意一个GPIO。
②边沿检测电路:选择上升沿触发、下降沿触发或者上升和下降沿都触发。
③或门:选择软件触发或者GPIO输入触发中断。
④与门:从或门③输出的信号分为两路,上路经过请求挂起寄存器输出与中断屏蔽寄存器一起控制与门的输出,并将与门④的输出保存至挂起寄存器EXTI_PR。
⑤、将EXTI_PR寄存器内容输出至NVIC。2、事件线路:①-②-③-⑥-⑦-⑧
⑥与门:从或门③输出的信号分为两路,下路经过与门⑥,与事件屏蔽寄存器一起控制是否选择事件。
⑦脉冲发生器电路:与门⑥输出为1时,产生一个脉冲信号。
⑧脉冲信号:控制外设事件。二、EXTI外部中断通路
打通这条通路即可实现EXTI中断/事件。
GPIOA~GPIOI的所有引脚全部连接至AFIO上,作为输入线,但数字编号相同的引脚只能算作一条输入线。如下图:
从PA0~PH0中,通过AFIO的EXTICR1寄存器选择一天作为EXTI0的输入源。三、EXTI配置
1、配置时钟:开启GPIOB和AFIO的时钟,EXTI和NVIC(内核外设)的时钟不需要开启
2、设置GPIO输入模式:
①EXTI推荐的模式见下表:可选择浮空、上拉或下拉。
②输入引脚:选择GPIO_Pin_14。
③速度:用于是输入模式,GPIO_Speed任选。
3、配置AFIO:使用GPIO_EXTILineConfig函数,该函数位于GPIO外设源码中。
4、配置EXTI:
①EXTI_Line选择14号。
②EXTI_LineCmd选择ENABLE。
③EXTI_Mode:有EXTI_Mode_Event和EXTI_Mode_Interrupt两种,这里选择EXTI_Mode_Interrupt。typedef enum { EXTI_Mode_Interrupt = 0x00, EXTI_Mode_Event = 0x04 }EXTIMode_TypeDef;
④EXTI_Trigger:这里有EXTI_Trigger_Rising、EXTI_Trigger_Falling和EXTI_Trigger_Rising_Falling,选择一种即可。
typedef enum { EXTI_Trigger_Rising = 0x08, EXTI_Trigger_Falling = 0x0C, EXTI_Trigger_Rising_Falling = 0x10 }EXTITrigger_TypeDef;
5、配置NVIC,该外设在misc.c文件中。
①配置优先级分组:抢占优先级(主优先级)和子优先级,这里选择第二组,分组方式整个芯片只能使用一种。在这里插入代码片/** @code The table below gives the allowed values of the pre-emption priority and subpriority according to the Priority Grouping configuration performed by NVIC_PriorityGroupConfig function ============================================================================================================================ NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority | Description ============================================================================================================================ NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority | | | 4 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority | | | 3 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority | | | 2 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority | | | 1 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority | | | 0 bits for subpriority ============================================================================================================================ @endcode */
②配置NVIC_InitStructure结构体用于初始化:
NVIC_IRQChannel选择EXTI15_10_IRQn,STM32的EXTI15~EXTI10放置在一个中断里;
NVIC_IRQChannelCmd=ENABLE;NVIC_IRQChannelPreemptionPriority=1;NVIC_IRQChannelSubPriority=1;
③调用NVIC_Init()初始化。四、加入中断事件处理函数
在stratup_stm32f10x_md.s中查看中断向量表,中断向量表中定义的就是中断函数的名字。__Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper DCD RTC_IRQHandler ; RTC DCD FLASH_IRQHandler ; Flash DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line 0 DCD EXTI1_IRQHandler ; EXTI Line 1 DCD EXTI2_IRQHandler ; EXTI Line 2 DCD EXTI3_IRQHandler ; EXTI Line 3 DCD EXTI4_IRQHandler ; EXTI Line 4 DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD ADC1_2_IRQHandler ; ADC1_2 DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1 DCD CAN1_SCE_IRQHandler ; CAN1 SCE DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD TIM1_BRK_IRQHandler ; TIM1 Break DCD TIM1_UP_IRQHandler ; TIM1 Update DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend __Vectors_End
五、函数代码
#include "stm32f10x.h" // Device header uint16_t CountSensor_Count=0; void CountSensor_Init(void){ //第一步:配置时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //第二步:配置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 EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line=EXTI_Line14; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising; 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(){ if(EXTI_GetITStatus(EXTI_Line14)==SET){ CountSensor_Count++; EXTI_ClearITPendingBit(EXTI_Line14); } }
-
STM32中EXTI,EXTI和NVIC的关系
2021-01-29 18:11:52关于EXTI 1.什么是EXTI? EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的 20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的... -
28.EXTI外部中断原理与配置
2022-03-10 10:12:07EXTI外部中断原理与配置 -
GD32F103学习笔记(5)——EXTI(外部中断)接口使用
2022-04-13 15:26:53一、简介 Cortex-M3集成了嵌套式...EXTI(中断/事件控制器)包括20个相互独立的边沿检测电路并且能够向处理器内核产生中断 请求或唤醒事件。EXTI有三种触发类型:上升沿触发、下降沿触发和任意沿触发。 EXTI中的每一个 -
第6课【EXTI中断】中断 事件 NVIC EXTI寄存器
2021-10-28 02:25:15目录基本知识框架课堂笔记EXTI中断事件控制器功能框图中断 / 事件线EXTI寄存器及相关库函数EXTI寄存器EXTI相关库函数外部中断实战基本知识框架Xmind文件下载 基本知识框架 课堂笔记 EXTI中断事件控制器 EXTI 中断 /... -
STM32中断:NVIC与EXTI
2022-03-18 10:34:34STM32中断,NVIC和EXTI的含义,及NVIC和EXTI对应的结构体与初始化函数,最后再用一个实验来体会中断在软件编程中的用法 -
STM32 F3产品技术培训-14.GPIO-EXTI模块.pdf
2019-09-14 02:51:15STM32 F3产品技术培训-14.GPIO-EXTI模块