• STM32 中断NVIC详解,配置及示例


            NVIC全称 Nested Vectored Controller 嵌套向量中断控制器

            它是一种硬件设备,用于管理和协调处理器的中断请求。NVIC可以管理多个中断请求,并按优先级处理它们。当一个中断请求到达时,NVIC会确定其优先级并决定是否应该中断当前执行的程序,以便及时响应和处理该中断请求。

            它可以提高系统的响应速度和可靠性,尤其是在需要及时处理大量中断请求的实时应用程序中。NVIC通常集成在处理器中,可以使用特定的控制寄存器进行编程配置。在嵌入式系统中,程序员需要理解和使用NVIC以确保系统能够正确处理中断请求,同时提高系统的性能和可靠性。

           举个例子:当你在炒菜的时候,来了个电话,你停下炒菜,去接了个电话,然后再回来炒菜。停下炒菜,去接电话。这个过程就叫做中断。

            在STM32中有两个优先级的概念,每个中断源都需要指定这两种优先级。

    • 抢占优先级 Preemption Priority
    • 从优先级(响应优先级) Sub Priority

            其中高抢占优先级的中断可以嵌套低抢占优先级的中断。

            假设 X抢占优先级为X_{P},Y抢占优先级为Y_{P},X响应优先级为X_{S},Y响应优先级位Y_{S}

    X_{P}>Y_{P}时,中断Y_{P}和代码,先执行X_{P}

    X_{P}=Y_{P}时,若X_{P}先到达,则先执行X_{P}后执行Y_{P}。反之,先执行Y_{P}后执行X_{P}

    X_{P}=Y_{P}X_{S}=Y_{S}时,根据它们在中断表中的排位顺序执行。

            可以使用STM32库函数中的NVIC_PriorityGroupConfig()选择优先级,函数的参数为NVIC_PriorityGroup_X

            EXTI(External Interrupt/event Controller)是外部中断/事件控制器。它提供了一种单向的、由外部事件触发的中断机制,可以用于响应外部信号的变化,例如按键、传感器、通信接口等外设的状态变化。EXTI模块可以配置为两种工作模式:事件中断和触发中断

            事件中断手头有上的事情做完了,再去执行中断。

            触发中断直接执行中断。

            所以中断请求的及时性比时间请求的及时性快。

            触发方式上升沿触发下降沿触发双边沿触发、以及低电平触发

            EXTI模块可以实现多种中断触发方式的支持,中断延时时间短,具有高精度的中断响应能力,并可以与其他外设操作结合使用,是STM32微控制器中实现外部中断的常用模块。

            我们看一下外部中断/时间线路映像图

            从中我们可以看到PA0/PB0/.../PG0——>EXTI0 ,PA1/PB1/.../PG1——>EXTI1,...,PA15/PB15/.../PG15——>EXTI15       

            在本示例用PA0按钮控制LED亮灭,所以等等配置EXTI_Line的时候就要用到EXTI_Line0

    //1.配置NVIC

    1. NVIC_InitTypeDef NVIC_InitStructure;
    2. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    3. NVIC_InitStructure.NVIC_IRQChannel =EXTI0_IRQn;
    4. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    5. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    6. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    7. NVIC_Init(&NVIC_InitStructure);

    //2.配置PA0+PA0外部中断使能

    1. GPIO_InitTypeDef GPIO_InitStructure;
    2. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    3. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    5. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
    6. GPIO_Init(GPIOA,&GPIO_InitStructure);

    //3.配置EXTI

    1. EXTI_InitTypeDef EXTI_InitSturcture;
    2. EXTI_InitSturcture.EXTI_Line = EXTI_Line0;
    3. EXTI_InitSturcture.EXTI_Trigger = EXTI_Trigger_Falling;
    4. EXTI_InitSturcture.EXTI_Mode = EXTI_Mode_Interrupt;
    5. EXTI_InitSturcture.EXTI_LineCmd = ENABLE;
    6. EXTI_Init(&EXTI_InitSturcture);

    //4.开启PA0和PA0的复用功能的时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);

    到这里PA0的配置就搞定了

    1. void PA0_EXTI0_Configuration(void)
    2. {
    3. NVIC_InitTypeDef NVIC_InitStructure;
    4. GPIO_InitTypeDef GPIO_InitStructure;
    5. EXTI_InitTypeDef EXTI_InitSturcture;
    6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
    7. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    8. NVIC_InitStructure.NVIC_IRQChannel =EXTI0_IRQn;
    9. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    10. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    11. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    12. NVIC_Init(&NVIC_InitStructure);
    13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    15. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    16. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
    17. GPIO_Init(GPIOA,&GPIO_InitStructure);
    18. EXTI_InitSturcture.EXTI_Line = EXTI_Line0;
    19. EXTI_InitSturcture.EXTI_Trigger = EXTI_Trigger_Falling;
    20. EXTI_InitSturcture.EXTI_Mode = EXTI_Mode_Interrupt;
    21. EXTI_InitSturcture.EXTI_LineCmd = ENABLE;
    22. EXTI_Init(&EXTI_InitSturcture);
    23. }

    //5.配置LED

    1. void Led_Configuration(void)
    2. {
    3. GPIO_InitTypeDef GPIO_InitStructure;
    4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    6. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    7. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    8. GPIO_Init(GPIOA, &GPIO_InitStructure);
    9. }

            根据中断表,当PA0配置成外部中断,只要PA0出现异常就会跳转到EXTI0_IRQHandler

            在STM32中,厂家已经把中断的主要部分都编写完了,我们只需要在stm32f103x_it.c中编写自己需要的中断即可。也可以放在自己想要的位置

    1. void EXTI0_IRQHandler(void)
    2. {
    3. if(EXTI_GetITStatus(EXTI_Line0)==SET)
    4. {
    5. GPIOA->ODR ^= GPIO_Pin_1;
    6. ClearITPendingBit(EXTI_Line0);
    7. }
    8. }

            EXTI_GetITStatus判断中断是否触发,触发的话返回SET,没出发返回RESET       

            触发后翻转一次PA1的电平

            然后清除EXTI_GetITStatus,要不然你第一次按下PA0的按钮后,EXTI_GetITStatus返回SET,然后会一直触发中断

  • 相关阅读:
    【Java】Servlet API
    金融行业数智化供应链管理系统:多维度评估分析供应商,赋能智能金融变革
    导致Spring事务失效的原因有哪些?
    这么漂亮的图画,竟然是用NumPy画出来的?请跟我来,10行代码玩转NumPy!
    字符串的使用方法之startwith()-以XX开头、endsWith()-以XX结尾、trim()-删除两端空格
    2022.11.7-11.13 AI行业周刊(第123期):技术人员的职业发展在哪里?
    tftp服务的搭建
    如何考取 AWS 技术认证
    国民技术Cortex-M0系列单片机IAP升级
    【面试题 - mysql】进阶篇 - 分库分表
  • 原文地址:https://blog.csdn.net/m0_73671341/article/details/134051262