欢迎光临
我们一直在努力

外部中断EXTI、复用功能、重映射、嵌套向量中断控制器NVIC、外部中断按键控制LED灯

文章目录

  • 外部中断EXTI
  • 1. 外部中断基础知识
    • 1.1 STM32外部中断框架
    • 1.2 STM32外部中断机制框架
  • 2. 复用功能
  • 3. 重映射
  • 4. 嵌套向量中断控制器NVIC
    • 4.1 中断向量表
    • 4.2 中断优先级分组
    • 4.3 中断优先级控制函数结构体
    • 4.4 中断优先级设置步骤
  • 5. 外部中断按键控制LED灯

外部中断EXTI

1. 外部中断基础知识

1.1 STM32外部中断框架

中断的概念:在主程序运行过程中,出现了特定的中断触发条件,使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完后又返回原来被暂停的位置继续运行。 在这里插入图片描述

  • 有20条外部中断线
  • 有十六条是GPIO的中断线(0~15),同一个引脚号参与同一个line
  • GPIO的中断线要启用必须先要配置AFIO的寄存器EXTICRx 在这里插入图片描述

1.2 STM32外部中断机制框架

在这里插入图片描述

  • 边沿检测(中断发生条件):上升沿 (低电平往高电平的变化),下降沿 或者 双边沿 (只要电平发生变化就触发)
  • 软件配置中断或者事件寄存器
  • 屏蔽中断寄存器或事件寄存器
  • 请求挂起寄存器 (不工作)
  • 中断发送给NVIC中断控制器 (管理先做哪一个中断)
  • 事件则产生一个脉冲响应
  • 2. 复用功能

    处理器的引脚本身默认就是一个普通的GPIO,但是它还可以被复用成其他功能,我们称之为一个引脚的复用功能 在这里插入图片描述 在这里插入图片描述

    3. 重映射

    重映射属于复用功能的另外一个功能,可以把具有特殊功能的引脚,分配到其他引脚上去 如果某个功能被重映射了,那么这个功能将不再遵循其默认的默认分配。 在这里插入图片描述

    比如STM32F1xx手册中第120页中: 串口1 发送和接收默认引脚 PA9 和 PA10,当 USART1_REMAP = 1 时,发送和接收引脚为 PB6 和 PB7。 (比如 PA9 和 PA10 已经当做普通引脚使用了,这个时候需要USART1的功能,可以配置PB6和PB7成为USART1 的功能来使用) 在这里插入图片描述

    4. 嵌套向量中断控制器NVIC

    4.1 中断向量表

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

    优先级号越小,优先级越高。(优先级负数为内核中断) STM32F1xx手册中第130页中: 在这里插入图片描述

    4.2 中断优先级分组

    这60个中断,怎么管理呢?这就涉及到STM32的中断分组。STM32可以将中断分成5个组,分别称为组0~4,同时,对每个中断设置一个抢占优先级和响应优先级。分组设置是由SCB->AIRCR寄存器的bit10~8来定义的。SCB->AIRCR是在哪里的呢?由于这是CM3内核定义的。 在这里插入图片描述 在这里插入图片描述

    CM3中定义了8个Bit用于设置中断源的优先级,而STM32只选用其中的4个Bit 抢占优先级的级别高于响应优先级,而数值越小所代表的的优先级越高,介绍一下抢占优先级、响应优先级的区别:

    • 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的;
    • 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断;
    • 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行;
    • 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

    除此之外还有两点需要注意:

    • 打断的情况只会与抢占优先级有关,和响应优先级无关!(中断嵌套)
    • 一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断优先级配置混乱,影响系统稳定性。

    4.3 中断优先级控制函数结构体

    • 中断优先级控制函数
      • NVIC_SetPriorityGrouping()。
    • 中断优先级控制结构体参数
      • NVIC_IRQChannel:定义初始化的是哪一个中断,这个可以在stm32f10x.h文件中查到每个中断对应的名字,例如UART1_IRQn
      • NVIC_IRQChannelPreemptionPriority:定义此中断的 抢占优先级级别。
      • NVIC_IRQChannelSubPriority:定义此中断的 响应优先级级别。
      • NVIC_IRQChannelCmd:该中断是否使能。
    • NVIN_Init()函数初始化NVIC寄存器

    4.4 中断优先级设置步骤

    1、系统运行后先设置中断优先级分组,调用函数。 2、针对每个中断,设置对应的抢占优先级和响应优先级。 3、如果需要挂起或恢复某个中断,应首先查询该中断当前的激活状态,然后根据状态分别调用对应的挂起(suspend) 或 恢复(resume)函数。

    5. 外部中断按键控制LED灯

    按键控制LED的开发流程: 第一步:使能功能复用时钟 在这里插入图片描述 第二步,配置复用寄存器 第三步,配置中断屏蔽寄存器

    固件库按键控制LED灯

    外部中断EXTI结构体:
    typedef struct
    {
    uint32_t EXTI_Line;// 外部中断线(比如 GPIOA 0~15)

    EXTIMode_TypeDef EXTI_Mode;// 外部中断模式(中断, 事件)

    EXTITrigger_TypeDef EXTI_Trigger;// 边沿检测(触发条件:上升沿,下降沿,双边沿)

    FunctionalState EXTI_LineCmd;// 表示外部中断线的使能或禁用状态
    }EXTI_InitTypeDef;

    外部中断EXTI相关库函数:
    void EXTI_DeInit(void);
    void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
    void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
    void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
    FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
    void EXTI_ClearFlag(uint32_t EXTI_Line);
    ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
    void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

    软件流程设计

    • 初始化系统
      • 初始化GPIO、EXTI外设时钟
      • 初始化按键和LED引脚
      • 初始化EXTI外部中断条件
      • 初始化NVIC嵌套中断控制器
    • 编写外部中断函数
      • 判断中断发生控制LED灯

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

    // exti.h 头文件
    void Exti_Init(void);

    // exti.h 源文件
    #include "stm32f10x.h"
    #include "exti.h"

    // 初始化GPIO按键 EXTI外部中断 NVIC中断控制器 函数
    void Exti_Init(void)
    {
    GPIO_InitTypeDef GPIO_initstruct;// 定义GPIO结构体变量
    EXTI_InitTypeDef EXTI_initstruct;// 定义外部中断EXTI结构体变量
    NVIC_InitTypeDef NVIC_initstruct; // 定义NVIC嵌套中断控制器结构体变量

    // 初始化时钟, GPIOA 和 AFIO外部中断时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    // 优先级分组配置 2位配置抢占优先级 2位配置响应优先级
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    GPIO_initstruct.GPIO_Pin = GPIO_Pin_0;// 初始化A0引脚
    GPIO_initstruct.GPIO_Mode = GPIO_Mode_IPU; // 初始化A0为上拉输入模式
    GPIO_Init(GPIOA, &GPIO_initstruct); // 初始化A0结构体
    // GPIOA0变成外部中断功能
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

    EXTI_initstruct.EXTI_Line = EXTI_Line0;// 初始化外部中断线0
    EXTI_initstruct.EXTI_Mode = EXTI_Mode_Interrupt; // 初始化外部中断模式
    EXTI_initstruct.EXTI_Trigger = EXTI_Trigger_Falling; // 初始化下降沿触发条件
    EXTI_initstruct.EXTI_LineCmd = ENABLE;// 外部中断线使能
    EXTI_Init(&EXTI_initstruct);// 初始化EXTI结构体

    NVIC_initstruct.NVIC_IRQChannel = EXTI0_IRQn;// 初始化中断线0
    NVIC_initstruct.NVIC_IRQChannelPreemptionPriority = 0; // 初始化抢占优先级
    NVIC_initstruct.NVIC_IRQChannelSubPriority = 0;// 初始化响应优先级
    NVIC_initstruct.NVIC_IRQChannelCmd = ENABLE;// 该中断使能
    NVIC_Init(&NVIC_initstruct);// 初始化 NVIC寄存器
    }

    // main.c
    #include "stm32f10x.h"
    #include "main.h"
    #include "LED.h"
    #include "exti.h"

    void delay(uint16_t time)
    {
    uint16_t i=0;
    while(time)
    {
    i = 12000;
    while(i);
    }
    }

    int main()
    {
    LED_Init();
    Exti_Init();
    GPIO_SetBits(GPIOA, GPIO_Pin_1);

    while(1)
    {

    }
    }

    // 外部中断函数, 主要满足完整的中断触发条件, 函数就会由硬件自动执行
    // "中断配置条件" 必须同时包含 EXTI配置 + NVIC使能
    void EXTI0_IRQHandler()
    {
    // 如果检查到外部中断线(EXTI0)发生了中断请求
    if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    {
    GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    delay(1000);
    GPIO_SetBits(GPIOA, GPIO_Pin_1);
    delay(1000);

    // 清除外部中断线(EXTI0)的中断挂起标志位, 方便下次还能运行函数
    EXTI_ClearITPendingBit(EXTI_Line0);
    }
    }

    赞(0)
    未经允许不得转载:171主机测评 » 外部中断EXTI、复用功能、重映射、嵌套向量中断控制器NVIC、外部中断按键控制LED灯
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址