STM32的中断分两个类型:内核异常外部中断

内核异常不能够被打断,不能被设置优先级(它的优先级是凌驾于外部中断之上的)。常见的内核异常有以下几种:复位(reset),不可屏蔽中断(NMI),硬错误(Hardfault)。

外部中断是我们必须学习掌握的知识,包含线中断,定时器中断,IIC,SPI等所有的外设中断,它可配置优先级。外部中断的优先级分为两种:抢占优先级响应优先级

  • 抢占优先级:抢占优先级高的,能够打断优先级低的任务,等优先级较高的任务执行完毕后,再回来继续执行之前的任务。所以当存在多个抢占优先级不同的任务时,很有可能会产生任务的嵌套。
  • 响应优先级:响应优先级又被称为次优先级,若两个任务的抢占式优先级一样,那么响应优先级较高的任务则先执行,且在执行的同时不能被下一个响应优先级更高的任务打断。

配置 NVIC_Config() 函数

NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是M3内核里面的一个外设。NVIC负责除了SYSTICK之外的所有中断的控制。

NVIC_Config() 函数如下:

// 主要是配置中断源的优先级与打开使能中断通道
static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct ; // 配置中断优先级分组(设置抢占优先级和子优先级的分配),在函数在misc.c
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ; // 配置初始化结构体 在misc.h中
// 配置中断源在stm32f10x.h中
NVIC_InitStruct.NVIC_IRQChannel = KEY1_EXTI_IRQN ;
// 配置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;
// 配置子优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0 ;
// 使能中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
// 调用初始化函数
NVIC_Init(&NVIC_InitStruct) ; // 对key2执行相同操作
NVIC_InitStruct.NVIC_IRQChannel = KEY2_EXTI_IRQN ;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
NVIC_Init(&NVIC_InitStruct) ;
}

配置 NVIC_Config() 的目的是选择中断源的优先级以及打开中断通道,主要功能通过配置 NVIC 初始化结构体 NVIC_InitStruct 来完成。通俗的讲,STM32中有很多中断,而当有多个中断同时发生时就涉及到中断执行的先后问题了,所以引入了中断优先级的概念,中断优先级越高中断就越先执行。在这里我们只讨论外部中断的优先级,在 NVIC 中有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx ,它用来配置外部中断的优先级。优先级高低的比较包括抢占优先级和子优先级,先比较抢占优先级,如果抢占优先级相同就比较子优先级,从而得出中断之间的优先级高低。NVIC的主要任务就是给对应的中断源分配中断优先级。

NVIC_Config() 函数的内容:

1、设置中断优先级分组

中断优先级分组其实是确立一个大纲,中断优先级寄存器 NVIC_IPRx 中有4个位用来确定优先级,中断优先级的分组就是把这4个位分配在抢占优先级和子优先级中。比如设定一个位配置抢占优先级,其余三个位配置子优先级。通过函数 NVIC_PriorityGroupConfig() 来实现分组。

  • NVIC_PriorityGroup_0:0 bit for 抢占优先级;4 bits for 子优先级;
  • NVIC_PriorityGroup_1:1 bit for 抢占优先级;3 bits for 子优先级;
  • NVIC_PriorityGroup_2:2 bits for 抢占优先级;2 bits for 子优先级;
  • NVIC_PriorityGroup_3:3 bits for 抢占优先级;1 bit for 子优先级;
  • NVIC_PriorityGroup_4:4 bits for 抢占优先级;0 bit for 子优先级;
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
// 设置优先级分组
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}

2、配置 NVIC 初始化结构体

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

初始化结构体的作用是,收集中断源的信息(包括配置哪一个中断源、中断源的抢占优先级是多少、中断源的子优先级是多少、中断源的使能是否开启)。

  • NVIC_IROChannel:用于设置中断源,不同的中断中断源不一样。在 stm32f10x.h 头文件里面的 IRQn_Type 结构体中定义包含了所有的中断源。
  • NVIC_IRQChannelPreemptionPriority 和 NVIC_IRQChannelSubPriority 分别设置抢占优先级和子优先级,具体的值要根据中断优先级分组来确定。
  • NVIC_IRQChannelCmd:设置中断使能(ENABLE)或失能(DISABLE),相当于一个总开关。

3、通过 NVIC 初始化函数将 NVIC 初始化结构体中的信息写入相应的寄存器中。

体现了固件库编程的优点,化繁为简,不需要深入到寄存器层次上,只需要掌握相应函数的配置即可。

配置 EXTI_Config() 函数

EXTI(External interrupt/event controller):外部中断/事件控制器,它管理了控制器的20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿的检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。STM32的所有GPIO都引入到了EXTI外部中断线上,也就是说,所有的IO口经过配置后都能够触发中断。

下图是GPIO和EXTI的连接方式:

从上图中我们可以看出,一共有16个中断线:EXTI0~EXTI15。每个中断线都对应了从PAx到PGx一共7个GPIO。也就是说,在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时响应所有端口的中断事件,但是可以分时复用。在程序执行过程中,这个不需要我们太多的去关心。我们关心最多的是中断触发的方式。

GPIO占用了EXTI0~EXTI15,另外四根则用于特定的外设事件。

EXTI是一个有着多达20个接口的控制器,它可以为每一个接入接口的信号源配置中断(或事件)线、设置信号的检测方式、设置触发事件的性质。传入 EXTI 中的仅仅是一个信号,而 EXTI 的功能就是根据信号传入的事件线来对信号做出相应的处理,然后将处理后的信号转向 NVIC。它就像一个分拣机器,传入的东西经过筛选处理后被送往不同的地方,只是EXTI分拣的是信号。NVIC 是配置中断源,而EXTI 就是向NVIC传送中断信号

EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,路线1-2-4-5是产生中断的流程,20/代表着有20条相同的线路。

EXTI_Config() 函数如下:

// 主要是连接EXTI与GPIO
void EXTI_Config()
{
GPIO_InitTypeDef GPIO_InitStruct ;
EXTI_InitTypeDef EXTI_InitStruct ; NVIC_Config(); // 初始化要与EXTI连接的GPIO
// 开启GPIOA与GPIOC的时钟
RCC_APB2PeriphClockCmd(KEY1_EXTI_GPIO_CLK | KEY2_EXTI_GPIO_CLK, ENABLE) ; GPIO_InitStruct.GPIO_Pin = KEY1_EXTI_GPIO_PIN ;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(KEY1_EXTI_GPIO_PORT , &GPIO_InitStruct) ; GPIO_InitStruct.GPIO_Pin = KEY2_EXTI_GPIO_PIN ;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(KEY2_EXTI_GPIO_PORT , &GPIO_InitStruct) ; // 初始化EXTI外设
// EXTI的时钟要设置AFIO寄存器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ;
// 选择作为EXTI线的GPIO引脚
GPIO_EXTILineConfig( KEY1_GPIO_PORTSOURCE , KEY1_GPIO_PINSOURCE) ;
// 配置中断or事件线
EXTI_InitStruct.EXTI_Line = KEY1_EXTI_LINE ;
// 使能EXTI线
EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
// 配置模式:中断or事件
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
// 配置边沿触发 上升or下降
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising ;
EXTI_Init(&EXTI_InitStruct) ; GPIO_EXTILineConfig( KEY2_GPIO_PORTSOURCE , KEY2_GPIO_PINSOURCE) ;
EXTI_InitStruct.EXTI_Line = KEY2_EXTI_LINE ;
EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
EXTI_Init(&EXTI_InitStruct);
}

上面部分分为三部分:

配置GPIO相应引脚、配置 EXTI 并连接GPIO引脚、传入 NVIC_Config()

1、配置GPIO相应引脚

该代码是通过按键产生一个电平信号,然后经EXTI处理传入NVIC产生中断的,所以要配置连接按键的GPIO引脚,主要是设置相应的引脚模式为浮空输入 。先开启相应GPIO的时钟,然后配置引脚初始化结构体,再利用初始化函数将初始化结构体写入寄存器中。

2、配置EXTI并连接GPIO引脚

要操作外设,首先要打开相关的时钟,EXTI挂载在APB2总线上,并且开启时钟时要操作AFIO寄存器。准备工作就绪后连接GPIO相应的引脚到EXTI中,前面说了EXTI有20个接口,所以特定的引脚有特定的接口,所以要根据 GPIO_EXTILineConfig() 函数选择用作EXTI线的GPIO引脚。

连接好GPIO引脚与EXTI后就该配置EXTI的初始化结构体,结构体如下:

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

配置此结构体主要是:选择相应的EXTI线、选择触发模式、选择产生的结果(中断/事件)、是否使能EXTI线。

  • EXTI_Line:中断线选择,可选 EXTI_0 至 EXTI_19(共20个)。既然刚才配置好了与GPIO引脚对应的EXTI线,所以初始化结构体中的EXTI线就是与GPIO连接的那个线。
  • EXTI_Mode:EXTI 模式选择,可选为产生中断或者产生事件。就是决定信号的发展方向。
  • EXTI_Trigger:EXTI 边沿触发模式,可选上升沿触发、下降沿触发或者上升沿和下降沿都触发。
  • EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线或禁用。

初始化结构体配置完毕后交由初始化函数写入相应的寄存器中。

3、传入 NVIC_Config()

编写中断服务函数

中断的触发与处理及优先级定义都已经安排上了,最后就是编写中断函数的内容了,只要进入中断就会执行中断函数中的代码。STM32的中断服务函数不同于51单片机中的中断服务函数,STM32的所有中断函数都被安排了,每个中断都有其固定的名字,只有找到这个名字,在这个固定的函数名下编写中断服务函数才是有效的,所有中断函数的编写都要在 stm32f10x_it.c 中。

外设的中断服务函数的名字都存放在 startup_stm32f10x_xx.s 中。EXTI线0到EXTI线4线都是单独的中断函数名、EXTI线5到EXTI线9共用一个中断函数名、EXTI线10线到EXTI线15线共用一个中断函数名。

我们要做的就是以相应的EXTI线的中断函数名字来编写中断函数,如下:

void EXTI0_IRQHandler(void)
{
if( EXTI_GetITStatus(KEY1_EXTI_LINE)!=RESET)
{
LED1_TOGGLE; //LED1的亮灭状态反转
} EXTI_ClearITPendingBit(KEY1_EXTI_LINE);
} void EXTI15_10_IRQHandler(void)
{
if( EXTI_GetITStatus(KEY2_EXTI_LINE)!=RESET)
{
LED2_TOGGLE; //LED2的亮灭状态反转
} EXTI_ClearITPendingBit(KEY2_EXTI_LINE);
}

每次进入中断函数后,靠 ITStatus EXTI_GetITStatus(uint32_t EXTI_Line) 读取中断是否执行,执行完之后要利用 void EXTI_ClearITPendingBit(uint32_t EXTI_Line) 清除中断标志位,以免不断进入中断。

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h" int main(void)
{
LED_GPIO_Config();
EXTI_Config(); while(1)
{
}
}

  

#ifndef __BSP_KEY_H
#define __BSP_KEY_H #include "stm32f10x.h" #define KEY1_EXTI_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY1_EXTI_GPIO_PORT GPIOA
#define KEY1_EXTI_GPIO_PIN GPIO_Pin_0
#define KEY1_EXTI_IRQN EXTI0_IRQn /* 对应着引脚号 */
#define KEY1_EXTI_LINE EXTI_Line0 /* 中断、事件线对应引脚号 */
#define KEY1_GPIO_PORTSOURCE GPIO_PortSourceGPIOA
#define KEY1_GPIO_PINSOURCE GPIO_PinSource0
#define KEY1_EXTI_IRQHANDLER EXTI0_IRQHandler #define KEY2_EXTI_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_EXTI_GPIO_PORT GPIOC
#define KEY2_EXTI_GPIO_PIN GPIO_Pin_13
#define KEY2_EXTI_IRQN EXTI15_10_IRQn
#define KEY2_EXTI_LINE EXTI_Line13
#define KEY2_GPIO_PORTSOURCE GPIO_PortSourceGPIOC
#define KEY2_GPIO_PINSOURCE GPIO_PinSource13
#define KEY2_EXTI_IRQHANDLER EXTI15_10_IRQHandler void EXTI_Config(void); #endif

  

#ifndef __BSP_LED_H
#define __BSP_LED_H #include "stm32f10x.h" #define LED1_GPIO_CLK RCC_APB2Periph_GPIOC /*时钟*/
#define LED1_GPIO_PORT GPIOC /*端口*/
#define LED1_GPIO_PIN GPIO_Pin_2 /*引脚*/ #define LED2_GPIO_PIN GPIO_Pin_3
#define LED2_GPIO_CLK RCC_APB2Periph_GPIOC
#define LED2_GPIO_PORT GPIOC #define digitalTOGGLE(p,i) {p->ODR ^=i;}
#define LED1_TOGGLE digitalTOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED2_TOGGLE digitalTOGGLE(LED2_GPIO_PORT,LED2_GPIO_PIN) /* LED状态反转 */
void LED_GPIO_Config(void); #endif

  

STM32中断的更多相关文章

  1. STM32中断管理函数

    CM3 内核支持256 个中断,其中包含了16 个内核中断和240 个外部中断,并且具有256 级的可编程中断设置.但STM32 并没有使用CM3 内核的全部东西,而是只用了它的一部分. STM32 ...

  2. 第16章 STM32中断应用概览

    第16章     STM32中断应用概览 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

  3. STM32 中断应用概览

    本章参考资料< STM32F4xx 中文参考手册>第十章-中断和事件.<ARM Cortex™-M4F 技术参考手册> -4.3 章节: NVIC 和 4.4 章节: SCB— ...

  4. 第16章 STM32中断应用概览—零死角玩转STM32-F429系列

    第16章     STM32中断应用概览 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

  5. STM32中断应用总结

    STM32中断很强大,STM32中断可以嵌套,任何外设都可以产生中断,其中中断和异常是等价的. 中断执行流程: 主程序执行过程可以产生中断去执行中断的内容(保护现场),然后在返回继续执行中断. 中断分 ...

  6. 【转载-Andrew_qian】stm32中断学习

    [转载]stm32中断学习 中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大 ...

  7. STM32中断编程三步曲教你弄会中断设置以及中断优先级设置

    中断作为stm32中必不可少的一个功能,其重要性是不言而喻的因此把中断学习好是根本. 所以今天就来好好啃一下中断配置的知识,俗话说:磨刀不误砍柴工.问题是什么呢?项目中我用到了一个触摸键盘TTP229 ...

  8. stm32 中断几个库函数实现过程分析

    感谢原文作者:鱼竿的传说,这篇文章写得不错,转载自 http://www.cnblogs.com/chineseboy/archive/2013/03/14/2956782.html 前题: 闭门造车 ...

  9. stm32中断无电平触发的解决办法

    这几天在用stm32读取FPGA中FIFO里的数据,遇到了不少的问题.其中有个自己觉得比较好玩的问题,就拿出来写写.其实这个问题也比较简单,开始我觉得没必要拿出来写,不过,想想后觉得还是写写吧,就当做 ...

  10. STM32学习笔记(六) SysTick系统时钟滴答实验(stm32中断入门)

    系统时钟滴答实验很不难,我就在面简单说下,但其中涉及到了STM32最复杂也是以后用途最广的外设-NVIC,如果说RCC是实时性所必须考虑的部分,那么NVIC就是stm32功能性实现的基础,NVIC的难 ...

随机推荐

  1. NOIP2017 Day1 T1 小凯的疑惑

    题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小凯想知道在无法准确支付的物品中,最贵的价 ...

  2. Dubbo必须会的知识点

    前言 应用架构演变: 单一架构ORM:单机构建网站,是一个高内聚版本,所有功能部署在一起.通过一个容器和JSP/Servlet技术或通过一些开源的框架如SSM以及SSH,通过数据库管理系统来存储数据. ...

  3. 前端直传文件到aliyun OSS

    <template> <div id="container"> <div class="img-item m-1 upload-file&q ...

  4. java的注解学习

    转载自https://www.cnblogs.com/xdp-gacl/p/3622275.html 孤傲苍狼 只为成功找方法,不为失败找借口! Java基础加强总结(一)——注解(Annotatio ...

  5. 2.BlockingQueue-阻塞式队列

  6. 一文带你熟悉JAVA IO这个看似很高冷的菇凉

    Java IO 是一个庞大的知识体系,很多人学着学着就会学懵了,包括我在内也是如此,所以本文将会从 Java 的 BIO 开始,一步一步深入学习,引出 JDK1.4 之后出现的 NIO 技术,对比 N ...

  7. noSql 的应用场景简述

    选型一定要结合实际情况而不是照本宣科,比如: 企业发展之初,明明一个关系型数据库就能搞定且支撑一年的架构,搞一套大而全的技术方案出来 有一些数据条件查询多,更适合使用ElasticSearch做存储降 ...

  8. 安装Ubuntu虚拟机

    centos已经满足不了我了,这里就装了个虚拟机,等有钱了再单配台单系统的Linux主机. 一.下载Ubuntu的ISO文件 用国内的网易镜像站点 进去点个16.04.6,然后下个64位的.iso就好 ...

  9. 简单渗透测试流程演示(445端口、IPC$、灰鸽子)

    目录 一.实验流程 二.实验过程 2.1 信息收集 2.2 利用过程 2.3 暴力破解系统密码之445 2.4 通过木马留后门 一.实验流程 0.授权(对方同意被渗透测试才是合法的.)1.信息收集  ...

  10. CUP的MESI协议

    MESI协议中的状态 CPU中每个缓存行(caceh line)使用4种状态进行标记(使用额外的两位(bit)表示): M: 被修改(Modified) 该缓存行只被缓存在该CPU的缓存中,并且是被修 ...