STM32 中断总结(1)
发布日期:2021-05-14 16:24:59 浏览次数:25 分类:精选文章

本文共 4633 字,大约阅读时间需要 15 分钟。

前言

由于个人博客被攻击,现逐渐将博客内容搬运至CSDN。本文原写于2020年4月。

中断是单片机的核心之一,stm32具有强大的中断,几乎每个外设都可设中断。

补充知识

中断和异常向量表(见st官方stmF10x英文数据手册),共60个可设置中断。

NVIC:嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对 Cortex-M3 内核里面的 NVIC 进行裁剪,把不需要的部分去掉,所以说 STM32 的 NVIC 是 Cortex-M3 的 NVIC 的一个子集。

《STM32F10xxx Cortex-M3编程手册》

NVIC

结构体定义

NVIC 初始化结构体:

typedef struct{
uint8_t NVIC_IRQChannel; // 中断源
uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
uint8_t NVIC_IRQChannelSubPriority; // 子优先级
FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
} NVIC_InitTypeDef;

优先级

在NVIC中 中断优先级寄存器 NVIC_IPRx 用来配置优先级,该寄存器宽度为8bit,但是在F103中只使用了高4bit,这4bit又分组为抢占优先级和子优先级。如果多个终端同时响应,依次比较抢占优先级、子优先级和硬件中断编号(越小越先)。

优先级的分组由内核外设 SCB 的应用程序中断及复位控制寄存器 AIRCR 的PRIGROUP[10:8]位决定, F103 分为了 5 组,具体如下图:

主优先级=抢占优先级

对应位于misc.h和misc.c中函数 NVIC_PriorityGroupConfig() 实现

优先级分组

对应位于misc.h和misc.c中函数 NVIC_PriorityGroupConfig() 实现

配置步骤

  • 使能外设某个中断,具体由每个外设的相关中断使能位控制;

  • 初始化NVIC_InitTypeDef结构体,设置抢占优先级和子优先级,使能中断请求。

  • 编写中断服务函数

  • 解释

    对于步骤二:代码如下

    typedef struct{
    uint8_t NVIC_IRQChannel; // 中断源
    uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
    uint8_t NVIC_IRQChannelSubPriority; // 子优先级
    FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
    } NVIC_InitTypeDef;

    对于中断源的配置特此说明:不同的中断中断源不一样,写错不报错。成员过多,此处不再展示,具体参考stm32f103.h里的IRQn_Type结构体定义。

    对于步骤三:在启动文件

    startup_stm32f10x_hd.s 中预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要重新编写, 为了方便管理中断服务函数统一写在 stm32f10x_it.c 这个库文件中。

    EXTI

    EXTI全称外部中断/事件控制器。管理了20个中断线,具有边沿检测器,可实现输入信号上升沿or下降沿的检测。可实现对每个中断线进行单独配置。

    硬件流程图

    硬件流程图如下:

    每个GPIO都可以被设置为输入线,见表:

    中断线/实践线

    每个GPIO都可以被设置为输入线,见表:

    EXTI结构体

    EXTI 初始化结构体(stm32f10x_exti.c,stm32f10x_exti.h)

    typedef struct{
    uint32_t EXTI_Line; // 中断/事件线
    uint8_t EXTI_Mode; // 模式
    uint8_t EXTI_Trigger; // 触发类型
    FunctionalState EXTI_LineCmd; // 使能
    } EXTI_InitTypeDef;

    说明:

    • EXTI_Line:见上表
    • EXTI_Mode:可选择产生中断还是事件
    • EXTI_Trigger:选择上升沿或下降沿
    • EXTI_LineCmd:使能

    编程

    步骤

  • 初始化GPIO

  • 初始化EXTI

  • 初始化NVIC

  • 编写中断服务函数

  • NVIC配置

    static void NVIC_Configuration(void){
    NVIC_InitTypeDef NVIC_InitStructure;
    /* 配置NVIC为优先级组1 */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    /* 配置中断源:按键1 */
    NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
    /* 配置抢占优先级 */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    /* 配置子优先级 */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    /* 使能中断通道 */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    /* 配置中断源:按键2,其他使用上面相关配置 */
    NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
    NVIC_Init(&NVIC_InitStructure);
    }

    GPIO设置和EXTI终端配置

    void EXTI_Key_Config(void){
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    /* 开启按键GPIO口的时钟 */
    RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK, ENABLE);
    /* 配置 NVIC 中断 */
    NVIC_Configuration();
    /*--------------------------KEY1配置-----------------------------*/
    /* 选择按键用到的GPIO */
    GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
    /* 配置为浮空输入 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
    /* 选择EXTI的信号源 */
    GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);
    EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
    /* EXTI为中断模式 */
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /* 上升沿中断 */
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    /* 使能中断 */
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    /*--------------------------KEY2配置-----------------------------*/
    /* 选择按键用到的GPIO */
    GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
    /* 配置为浮空输入 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);
    /* 选择EXTI的信号源 */
    GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE);
    EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
    /* EXTI为中断模式 */
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /* 下降沿中断 */
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    /* 使能中断 */
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    }

    中断服务函数

    void KEY1_IRQHandler(void){
    // 确保是否产生了EXTI Line中断
    if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET){
    // LED1 取反
    LED1_TOGGLE;
    // 清除中断标志位
    EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
    }
    }
    void KEY2_IRQHandler(void){
    // 确保是否产生了EXTI Line中断
    if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET){
    // LED2 取反
    LED2_TOGGLE;
    // 清除中断标志位
    EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
    }
    }
    上一篇:【linux自学笔记】初识ubuntu
    下一篇:STM32系统时钟配置笔记

    发表评论

    最新留言

    逛到本站,mark一下
    [***.202.152.39]2025年04月29日 11时52分00秒