当前位置:   article > 正文

【stm32】EXTI外部中断

【stm32】EXTI外部中断

1、中断系统

  • 中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
  • 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
  • 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。

2、中断执行流程

在这里插入图片描述

3、STM32中断

  • 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设
  • 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级
    在这里插入图片描述
    中断地址的作用:
    \qquad 在程序中的中断函数,地址由编译器进行分配,不固定,但中断跳转由于硬件的限制,只能跳转到固定的地址执行程序 ,为了能让硬件跳转到一个不固定的中断函数里,就需要在内存中定义一个地址的列表,列表地址是固定的,中断发生后,就跳到这个固定位置,在这个固定位置,由编译器,再加上一条跳转到中断函数的代码,这样中断跳转就可以跳转到任意位置了,这个中断地址的列表,就叫中断问量表

4、NVIC基本结构

NVIC:嵌套中断向量控制器
在STM32中,NVIC用来统一分配中断优先级和管理中断,属于内核外设
在这里插入图片描述

5、NVIC优先级分组

  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级
  • 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
    在这里插入图片描述

中断优先级:值越小,优先级越高

6、EXTI简介(引脚电平变化,申请中断)

  • EXTI(Extern Interrupt)外部中断
  • EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
  • 支持的触发方式:上升沿/下降沿/双边沿/软件触发
  • 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
  • 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
  • 触发响应方式:中断响应/事件响应

中断响应是正常的流程,引脚电平变化触发中断
事件响应不会触发中断,而是触发别的外设(ADC,DMA等)操作,属于外设之间的联合工作

7、EXTI基本结构

在这里插入图片描述

EXTI9_5和EXTI15_10:通过标志位区分哪个中断触发的
其它外设:用来触发其它外设操作的,也就是事件响应

8、AFIO复用IO口

  • AFIO主要用于引脚复用功能的选择和重定义
  • 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
    在这里插入图片描述

9、EXTI框图

在这里插入图片描述

10、旋转编码器简介

  • 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
  • 类型:机械触点式/霍尔传感器式/光栅式
    在这里插入图片描述
    在这里插入图片描述
    电路描述:
    \qquad 左右两边电路分别接了上拉电阻R1,R2,在默认状态时,A,B输出为高电平,看哪边电路导通,此时与GND相连,则输出口为低电平

11、程序设计:

1.使用对射式红外传感器触发外部中断

\qquad 当挡光片在这个对射式红外传感器中间经过时,DO输出电平变化的信号,电平跳变的信号触发STM32 PB14号口的中断,在中断函数中,执行变量自加,主循环调用OLED显示该变量。
\qquad 接上模块后,使用挡光片在传感器中间槽上来回进出,进入时开关指示灯灭,出来后开关指示灯亮,说明高低电平输出没问题

步骤:
1.配置RCC,打开时钟
2.配置GPIO,选择端口为输入模式
3.配置AFIO,选择所使用的这一路GPIO,连接到EXTI
4.配置EXTI,选择边沿触发方式(上升,下降,双边),选择触发响应方式(中断响应,事件响应)
6.配置NVIC,给中断选择合适优先级

c文件:

#include "stm32f10x.h"                  // Device header

static uint32_t countSensor = 0;
static uint8_t flag_count = 0;

void countSensor_init(void)
{
    EXTI_InitTypeDef   EXTI_InitStructure;
    GPIO_InitTypeDef   GPIO_InitStructure;
    NVIC_InitTypeDef   NVIC_InitStructure;
    /* Enable GPIOB clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /* Enable AFIO clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    /* Configure PB14 pin as input floating */
    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode     = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed     = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Connect EXTI14 Line to PB14 pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);

    /* Configure EXTI14 line */
    EXTI_InitStructure.EXTI_Line = EXTI_Line14;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    /* Enable and set EXTI14 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

uint32_t getCountValue(void)
{
    if(flag_count==1){
        if(countSensor<10){
            countSensor++;
        }else{
            countSensor=0;
        }
        flag_count = 0;
    }
    return countSensor;
}

void EXTI15_10_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line14) != RESET)
    {
        flag_count = 1;
        /* Clear the  EXTI line 14 pending bit */
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

h文件:

#ifndef __COUNTSENSOR_H
#define __COUNTSENSOR_H

extern void countSensor_init(void);
extern uint32_t getCountValue(void);

#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "countsensor.h"

int main(void)
{
    OLED_Init();
    countSensor_init();
    OLED_ShowString(1, 1, "count:");

    while (1)
    {
        OLED_ShowNum(1,7,getCountValue(),2);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

2.旋转编码器触发外部中断

c文件:

#include "stm32f10x.h"                  // Device header

int32_t Encoder_Count;

void encoder_init(void)
{
    EXTI_InitTypeDef   EXTI_InitStructure;
    GPIO_InitTypeDef   GPIO_InitStructure;
    NVIC_InitTypeDef   NVIC_InitStructure;
    /* Enable GPIOB clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /* Enable AFIO clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    /* Configure PB0/PB1  pin as input floating */
    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode     = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed     = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Connect EXTI0/1 Line to PB1/0 pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);

    /* Configure EXTI1/0 line */
    EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    /* Enable and set EXTI0 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    /* Enable and set EXTI1 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

int32_t Encoder_Get(void)
{
    int32_t Temp;
    Temp = Encoder_Count;
    Encoder_Count = 0;
    return Temp;
}

void EXTI0_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    {
        /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
        {
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
            {
                Encoder_Count --;
            }
        }
        /* Clear the  EXTI line 0 pending bit */
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

void EXTI1_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line1) != RESET)
    {
        /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
        {
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
            {
                Encoder_Count ++;
            }
        }
        /* Clear the  EXTI line 1 pending bit */
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

h文件

#ifndef __ENCODER_H
#define __ENCODER_H

extern void encoder_init(void);
extern int32_t Encoder_Get(void);

#endif


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "encoder.h"

int32_t num ;

int main(void)
{
    OLED_Init();
    encoder_init();
    OLED_ShowString(1, 1, "count:");
    
    while (1)
    {
        num += Encoder_Get();
        OLED_ShowSignedNum(1,7,num,5);
    }    
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

注意:在配置外设GPIO时,如果不确定该配置为什么模式,可参阅参考手册外设的GPIO配置
,里面有每个外设的各个引脚所配置的模式 ,如下

在这里插入图片描述

使用外部中断模块的特性:

\qquad 对于stm32,想要获取的信号是外部驱动的很快的突发信号,如旋转编码器,红外遥控接收头,按键等。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/940685
推荐阅读
相关标签
  

闽ICP备14008679号