当前位置: 首页 > news >正文

STM32 外部中断EXTI

目录

外部中断基础知识

STM32外部中断框架

STM32外部中断机制框架

复用功能

重映射

中断嵌套控制器NVIC 

外部中断按键控制LED灯


外部中断基础知识

STM32外部中断框架

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

            

1.有20条外部中断线

2.有十六条是GPIO的中断线(0~15),同一个引脚号参与同一个line

3.第十九条line只在有ETH互联设备上才存在

4.GPIO的中断线要启用必须先要配置AFIO的寄存器EXTICRx  

STM32外部中断机制框架

1. 边沿检测:上升沿,下降沿或者双边沿(上下都中断)

输入线就是20条外部中断线,可能是GPIO0~15的十六根线,也有可能是其他的线,比如说GPIO进来之后产生了一个信号,进入边沿检测电路,我们通过这个要选择是上升沿还是下降沿(上升和下降是针对电平来说的,下降沿是从高电平到低电平,上升沿是从低电平到高电平),根据是上升沿发生中断还是下降沿发生中断,是配置我们中断发生的条件,

2. 软件配置中断或者事件寄存器

一般情况下是中断

3. 屏蔽中断寄存器或事件寄存器

还是以中断寄存器为主

4. 请求挂起寄存器

挂起就好比晾衣杆,把一个东西挂起来说明这个事件不工作了,比如我cpu正常运行我们的主程序,突然来挂起之后,就直接不工作了

5. 中断发送给NVIC中断控制器

NVIC就是个中断的控制器(当主程序运行时会出现很多钟中断的条件,可能是敲门了,可能是你爸打电话了,可能是你妈打电话给你了,假如说同一个时间节点三四个人打电话给你,你应该决定做哪些事情,NVIC就是帮你管理你先处理哪个事件,同时你有外部中断,串口中断,定时器中断,然后再恢复主程序)

6. 事件则产生一个脉冲响应  

复用功能

什么是复用功能?

处理器的引脚本身默认就是一个普通的GPIO,但是它还可以被复用成其他功能,我们称之为一个引脚的复用功能(GPIO如果是IO口作为输入线,第一要先配置GPIO,如果这个IO口当中我们外部中断的中断线引脚它也得配置复用功能,因为此时不在是一个普通的引脚,是我们外部中断外设的引脚)

                                       

 比如PA0可以当作WKUP引脚、串口引脚、AD引脚....,所以单片机里面每个引脚都有多个功能,

如果我们只是简单的拿来用作输入输出引脚,就正常配置就行,如果拿来作为特殊的功能用,就得配置复用功能

重映射

什么是重映射?

重映射属于复用功能的另外一个功能,可以把具有特殊功能的引脚,分配到其他引脚上去

如果某个功能被重映射了,那么这个功能将不再遵循其默认的默认分配。(相当说串口1是PA9和PA10,但如果把它配置成PB6和PB7原来的就作废了)

 PA7引脚能被当作定时器CH1N的功能,PB13也能当作定时器CH1N的引脚说明同样的外设功能可以用在多个引脚

串口1的发送,串口1的接收,正常情况下PA9是发送PA10是接收,但是当串口USART1_REMAP = 1 时 ,PB6也能用来当串口1的发送,PB7能用来当作串口1的接收 

中断嵌套控制器NVIC 

中断向量表

Cortex-M3内核支持256个中断,其中包含了16个内核中断(异常)和240个外部中断,并目具有256级的可编程中断设置。但是,STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。STM32有84个中断,包括16个内核中断(异常)和68个可屏蔽中断,具有16级可编程的中断优先级。而STM32F103系列上面,16个内核中断(异常)不变,而可屏蔽中断只有60个(在107系列才有68个)**优先级号越小,优先级越高*。

中断优先级分组
这60个中断,怎么管理呢?这就涉及到STM32的中断分组。STM32可以将中断分成5个组,分别为组0-4;同时,对每个中断设置一个抢占优先级和响应优先级。分组配置是由SCB->AIRCR寄存器的bit10-8来定义的。SCB->AIRCR是在哪里的呢?由于这是CM3内核定义的具体的分配关系如下所示:

 Group0-4是中断优先级的五种模式(五位)

如果是Group0是四位可编程的,说明抢占优先级没有位,四位都给了响应优先级 

如果是Group1是四位可编程的,说明抢占优先级一位,三位都给了响应优先级 

一般情况下看中断类型选择合适的分组

             

 

 CM3中定义了8个Bit(若处理器使用高 3 位(bit7~bit5),则实际可配置的优先级等级为2^3=8级(0~7),数值越小优先级越高(如 0 为最高,7 为最低)。若使用全部 8 位,则可配置2^8=256级优先级。,完全够用)用于设置中断源的优先级,而STM32只选用其中的4个Bit(但是又把这4位分为抢占优先级和响应优先级,抢占优先级和响应优先级就好比父优先级和子优先级,如果两个中断发生的情况下先比较抢占优先级谁数值更低谁就优先,如果抢占优先级一样那比较响应优先级,响应优先级谁更小谁先运行,那如果还是一样就打开stm32f10x.h表再进行比较)抢占优先级的级别高于响,应优先级,而数值越小所代表的的优先级越高,介绍一下抢占优先级、响应优先级的区别:

高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的;

(你正在打游戏突然你妈喊你回家吃饭)
抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断;
抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行;
如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行:

除此之外有两点需要注意:
打断的情况只会与抢占优先级有关,和响应优先级无关!(中断嵌套:单片机正在执行工作,突然中断来了,然后有来了个高优先级中断能够打断低优先级的中断)
一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2(Group2),设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果

中断优先级控制函数结构体
中断优先级控制函数(在misc.h中的找到NVIC_InitTypeDef结构体)
        NVlc setPriorityGrouping().
中断优先级控制结构体参数
        NVIC IRQChannel(通道):定义初始化的是哪一个中断,这个可以在stm32f10x.h文件中查到每个中断对应的名字,如USART1_IRQn(串口1);

在mian.c中的misc.h,如果是EXTI0表示A0 B0 C0,我们是什么中断源就配置什么中断就行,只有0 1 2 3 4有单独的

 如果用的是5 6 7 8 9的IO口的引脚统一用EXTI9_5_IRQN,如果IO口用的是11 12 13 14 15的引脚统一用EXTI9_10_IRQN


 因为每一个外设你要中断,你都要统一配置中断的优先级

        NVICIRQChannelPreemptionPriority:定义此中断的抢占优先级别;
        NVIC IRQChannelsubPriority:定义此中断的响应优先级别;
        NVIC IRQChannelcmd:该中断是否使能。
NVIC Init()函数初始化NVIC寄存器 

中断优先级设置步骤

1、系统运行后先设置中断优先级分组,调用函数(0-5,五选一)

2、针对每个中断,设置对应的抢占优先级和响应优先级

3、如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可

外部中断按键控制LED灯

按键控制LED的开发流程:

(按键和单片机连接PC13或者PA0,但是现在如果把PC13或者PA0配置成外部中断,会发现不在是一个普通的引脚了,要配置复用功能,所以我们要用到EXTI和复用AFIO)

                     

第一步:使能功能复用时钟

第二步:配置复用寄存器

第三步:配置中断屏蔽寄存器

 软件流程设计

初始化系统

        初始化GPIO、EXTI外设时钟

        初始化按键和LED引脚

        初始化EXTI外部中断条件

        初始化NVIC嵌套中断控制器

编写外部中断函数

        判断中断发生控制LED灯 

初始化GPIO、EXTI外设时钟和初始化按键和LED引脚

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//同时初始化GPIOA和AFIO(包括了复位和中断时钟)GPIO_InitTypeDef GPIOInitstruct;GPIOInitstruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_0;GPIOInitstruct.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOA, &GPIOInitstruct);

初始化EXTI外部中断条件 

在stm32f10x_exti.c(外部中断库)中的stm32f10x_exti.h找到EXTI_InitTypeDef结构体

typedef struct
{uint32_t EXTI_Line;      //外部中断线                                                                                                                                                   EXTIMode_TypeDef EXTI_Mode; //外部中断模式EXTITrigger_TypeDef EXTI_Trigger; //外部中断是上升沿还是下降沿还是双边沿FunctionalState EXTI_LineCmd;   //使能}EXTI_InitTypeDef; EXTI_InitTypeDef EXTIInitstruct;EXTIInitstruct.EXTI_Line = EXTI_Line0;
//因为是按键引脚是PA0所以配置中断线是EXTI_Line0EXTIInitstruct.EXTI_Mode = EXTI_Mode_Interrupt;
//选择模式是中断EXTIInitstruct.EXTI_Trigger = EXTI_Trigger_Falling;
//选择的是下降沿EXTIInitstruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTIInitstruct);

 初始化NVIC嵌套中断控制器在mian.c中的misc.h找到NVIC_InitTypeDef结构体和优先级分组函数

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//配置优先级前先分组
NVIC_InitTypeDef NVICInitstruct;NVICInitstruct.NVIC_IRQChannel = EXTI0_IRQn;NVICInitstruct.NVIC_IRQChannelPreemptionPriority = 0;NVICInitstruct.NVIC_IRQChannelSubPriority = 0;
//因为只有一个中断配置最高优先级NVICInitstruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVICInitstruct);

 在stm32f10x_dam.c中的stm32f10x_gpio.h外部中端线GPIO配置函数

GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

 编写外部中断函数

中断函数配置好之后如果中断条件发生会先去中断向量表里去先找到EXTI0_IRQHandler这个函数用户有没有定义,如果有定义就执行定义的,如果没定义也跑但内容是空的

函数名在启动文件中,因为我们单片机上电先要执行前面所有内容

weak:弱定义;如果用户没有自己定义的中断函数,则系统默认执行系统自定义的中断函数,如果用户有定义中断函数则优先执行用户的中断函数

所有复制EXTI0_IRQHandler,复制到main函数以外,因为我们的中断函数不需要调用,因为只要我们配置了就会自动跳转过来,如何判断:stm32f10x_exti.c(外部中断库)中的stm32f10x_exti.h找到外部中断获取中断标志位函数EXTI_GetITStatus(uint32_t EXTI_Line)和外部中断清除中断标志位EXTI_ClearITPendingBit(uint32_t EXTI_Line);两个函数配套使用

typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;

int  main()
{Shake_Init();Led_Init();while(1){}}
void EXTI0_IRQHandler()
{
//如果外部中断获取中断标志位说明发生中断(就是按键按下的时候)if(EXTI_GetITStatus(EXTI_Line0) != RESET ){GPIO_ResetBits(GPIOA,GPIO_Pin_0);GPIO_SetBits(GPIOA,GPIO_Pin_0);//因为我们的中断可能会发生很多次,所有每进行一次中断需要清除一次,方便下一次进入//如果没有调用清除中断函数只能进行一次,因为它已经置位了,清除之后它又能进入ëEXTI0_IRQHandler函数中EXTI_ClearITPendingBit(EXTI_Line0);}}

 总体代码:

#include "stm32f10x.h"
#include "shake.h"void Shake_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);GPIO_InitTypeDef GPIOInitstruct;EXTI_InitTypeDef EXTIInitstruct;NVIC_InitTypeDef NVICInitstruct;GPIOInitstruct.GPIO_Pin = GPIO_Pin_0;GPIOInitstruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOA, &GPIOInitstruct);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);EXTIInitstruct.EXTI_Line = EXTI_Line0;EXTIInitstruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTIInitstruct.EXTI_Trigger = EXTI_Trigger_Falling;EXTIInitstruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTIInitstruct);NVICInitstruct.NVIC_IRQChannel = EXTI0_IRQn;NVICInitstruct.NVIC_IRQChannelPreemptionPriority = 0;NVICInitstruct.NVIC_IRQChannelSubPriority = 0;NVICInitstruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVICInitstruct);}
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "bear.h"
#include "key.h"
#include "relay.h"
#include "shake.h"void delay(uint16_t time){uint16_t i = 0;while(time --){i = 12000;while(i--);}}int  main()
{Shake_Init();Led_Init();GPIO_ResetBits(GPIOA,GPIO_Pin_1);while(1){}}void EXTI0_IRQHandler()
{if(EXTI_GetITStatus(EXTI_Line0) != RESET ){GPIO_ResetBits(GPIOA,GPIO_Pin_1);delay(1000);GPIO_SetBits(GPIOA,GPIO_Pin_1);delay(1000);EXTI_ClearITPendingBit(EXTI_Line0);}}

相关文章:

  • 原生localStorage到zustand + persist改造
  • [密码学基础]密码学发展简史:从古典艺术到量子安全的演进
  • 碰一碰发视频系统源码搭建全解析:定制化开发
  • 芝法酱躺平攻略(21)——kafka安装和使用
  • LabVIEW 程序维护:为何选靠谱团队?
  • 纯FPGA控制AD9361的思路和实现之一 概述
  • JVM 系列:JVM 内存结构深度解析
  • Day10【基于encoder- decoder架构实现新闻文本摘要的提取】
  • 面向对象设计中的类的分类:实体类、控制类和边界类
  • 暨南大学 2024年ACM程序设计校赛 题解与知识点分析
  • SOA 核心三要素:服务、构件与对象的深度解析
  • 毕业答辩的PPT应该包括哪些内容?
  • Grallvm技术介绍
  • 从 LabelImg 到 Label Studio!AI 数据标注神器升级,Web 版真香
  • 【网络初识】从零开始彻底了解网络编程(一)
  • 企业网站安装 SSL安装的必要性
  • C++学习之路,从0到精通的征途:vector类的模拟实现
  • 【网络原理】UDP协议
  • 动手实现文本生成模型:基于 Decoder-only Transformer (PyTorch)
  • 深入实战:使用C++开发高性能RESTful API
  • “30小时不够”,泽连斯基建议延长停火至30天
  • 中华人民共和国和柬埔寨王国关于构建新时代全天候中柬命运共同体、落实三大全球倡议的联合声明
  • 上海地铁18号线二期长轨贯通,预计今年年底开通初期运营
  • 世卫成员国就《大流行病协议》达成一致,首次演练应对气候诱发的病毒危机
  • 美肯塔基州长警告:关税或致美家庭年增数千美元支出
  • 当瓷器传入欧洲,看女性视角下的中国风