博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
STM32的中断系统
阅读量:4992 次
发布时间:2019-06-12

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

STM32的中断系统

STM32具有十分强大的中断系统,将中断分为了两个类型:内核异常和外部中断。并将所有中断通过一个表编排起来,下面是stm32中断向量表的部分内容:

1097927-20180814123940440-1953049551.png

1097927-20180814123948507-6094837.png

上图-3到6这个区域被标黑了,这个区域就是内核异常。内核异常不能够被打断,不能被设置优先级(也就是说优先级是凌驾于外部中断之上的)。常见的内核异常有以下几种:复位(reset),不可屏蔽中断(NMI),硬错误(Hardfault),其他的也可以在表上找到。

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

什么是抢占优先级?

抢占优先级比较霸道,一言不和就插队。抢占优先级高的,能够打断优先级低的任务,等优先级较高的任务执行完毕后,再回来继续执行之前的任务。所以当存在多个抢占优先级不同的任务时,很有可能会产生任务的嵌套。

什么是响应优先级?

响应优先级则稍微谦逊些,比较有礼貌。响应优先级又被称为次优先级,若两个任务的抢占式优先级一样,那么响应优先级较高的任务则先执行,且在执行的同时不能被下一个响应优先级更高的任务打断,所以我说它比较有有礼貌。。

中断控制器(NVIC)

因为stm32的中断系统比较复杂,所以在内核中有一个专门管理中断的控制器:NVIC.

NVIC负责除了SYSTICK之外的所有中断的控制,十分重要!

在标准库中,提供了一套通过NVIC来控制中断的API,我们首先来看NVIC_Init()函数,这套函数首先要定义并填充一个结构体:NVIC_InitTypeDef 该结构体的定义如下:

NVIC_IRQChannel 需要配置的中断向量

NVIC_IRQChannelCmd 使能或者关闭相应中断向量的中断响应

NVIC_IRQChannelPreemptionPriority 配置相应中断向量的抢占优先级

NVIC_IRQChannelSubPriority 配置相应中断的响应优先级

结构体的四个成员都比较好理解,这里就不再累述了。

不过要注意一点的是,NVIC只可以配置16种中断向量的优先级,其抢占优先级和响应优先级都用一个4位的数字来决定。在库函数中,将其分为了5中不同的分配方式:

第0组:所有的4位都有来表示响应优先级,能够配置16种不同的响应优先级。中断优先级则都相同。

第1组:最高一位用来配置抢占优先级,剩余三位用来表示响应优先级。那么就有两种不同的抢占优先级(0和1)和8种不同的响应优先级(0~7)。

第2组:高两位用来配置抢占优先级,低位用来配置响应优先级。那么两种优先级就各有4种。

第3组:高三位用来配置抢占优先级,低位用来配置响应优先级。有8种抢占优先级和2种相应优先级。

第4组:所有位都用来配置抢占优先级,即有16种抢占优先级,没有响应属性。

这5种不同的分配方式,根据项目的实际需求来配置。

配置的API如下:

NVIC_PriorityGroupConfig();

其中括号内可以输入以下一个参数,代表不同的分配方式:

NVIC_PriorityGroup_0

NVIC_PriorityGroup_1

NVIC_PriorityGroup_2

NVIC_PriorityGroup_3

NVIC_PriorityGroup_4

EXTI外部中断

STM32的所有GPIO都引入到了EXTI外部中断线上,也就是说,所有的IO口经过配置后都能够触发中断。下图就是GPIO和EXTI的连接方式:

1097927-20180814124003510-425482330.png

从上图我们可以看出,一共有16个中断线: EXTI0到EXTI15.

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

在EXTI中,有三种触发中断的方式:上升沿触发,下降沿触发,双边沿触发。根据不同的电路,我们选择不同的触发方式,以确保中断能够被正常触发。

实例

为了便于理解,这里我们将中断配置代码贴上来。

void NVIC_Configuration(void){  NVIC_InitTypeDef NVIC_InitStructure;    /* 配置NVIC为优先级组1 */  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);    /* 配置中断源:按键1 */  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //配置为EXTI0通道  /* 配置抢占优先级 */  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  /* 配置子优先级 */  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  /* 使能中断通道 */  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure); //将上述配置参数传入中断初始化函数}

除了中断线的配置,我们还要配置对应引脚

void EXTI_Key_Config(void){    GPIO_InitTypeDef GPIO_InitStructure;     EXTI_InitTypeDef EXTI_InitStructure;    /*开启按键GPIO口的时钟*/    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);                                                    /* 配置 NVIC 中断*/    NVIC_Configuration();/*--------------------------KEY1配置-----------------------------*/    /* 选择按键用到的GPIO */     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;  /* 配置为浮空输入 */   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);    /* 选择EXTI的信号源 */  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   EXTI_InitStructure.EXTI_Line = EXTI_Line0;        /* EXTI为中断模式 */  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;    /* 上升沿中断 */  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  /* 使能中断 */      EXTI_InitStructure.EXTI_LineCmd = ENABLE;  EXTI_Init(&EXTI_InitStructure);}

至此,中断的配置完毕。相信你已经看出来,上述代码是将PA0配置为上升沿中断。不过,现在只能够说该中断已经配置完毕,但我们还不能使用它。我们还缺少一个中断的执行函数。

当中断被触发后,程序要马上跳转到中断函数去执行中断操作,这个函数在工程创建时默认时没有的。需要你自己去添加。而且需要注意的是,中断函数的名称必须是由标准库提供的,否则无法识别。

我们打开startup_stm32f10x_hd.s这个文件,在里面能找到这么一段代码:

; External Interrupts                DCD     WWDG_IRQHandler            ; Window Watchdog                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect                DCD     TAMPER_IRQHandler          ; Tamper                DCD     RTC_IRQHandler             ; RTC                DCD     FLASH_IRQHandler           ; Flash                DCD     RCC_IRQHandler             ; RCC                DCD     EXTI0_IRQHandler           ; EXTI Line 0                DCD     EXTI1_IRQHandler           ; EXTI Line 1                DCD     EXTI2_IRQHandler           ; EXTI Line 2                DCD     EXTI3_IRQHandler           ; EXTI Line 3                ...                ...                ...

不难看出,EXTI0_IRQHandler 就是中断线0的中断函数,所以,我们把这个函数添加到工程中即可。最好添加到stm32f10x_it.c 这个文件中,方便管理。

可以在这个函数中添加你想要的功能,代码如下:

void EXTI0_IRQHandler(void){  //确保是否产生了EXTI Line中断    if(EXTI_GetITStatus(EXTI_Line0) != RESET)     {        /******/         //LED闪烁相关代码        /******/    //清除中断标志位        EXTI_ClearITPendingBit(EXTI_Line0);         }  }

至此,整个中断的流程梳理完毕,如果有什么纰漏的话,欢迎探讨!

转载于:https://www.cnblogs.com/hanhuo/p/9473906.html

你可能感兴趣的文章
吴裕雄 实战PYTHON编程(8)
查看>>
xhtml
查看>>
poj 1113 Wall (凸包模板题)
查看>>
cf 535B Tavas and SaDDas
查看>>
OO-面对对象的特征--多态、抽象
查看>>
看准网免登陆查看
查看>>
用pygame实现打飞机游戏-1-搭建框架
查看>>
io编程,bio,nio,aio
查看>>
windows 关于时间的计算
查看>>
面向对象编程思想-代理模式
查看>>
HttpClient获取Cookie的两种方式
查看>>
Windows 7中的电源计划及维护
查看>>
Spring MVC 配置类 WebMvcConfigurerAdapter
查看>>
js获取url参数
查看>>
程序员如何优雅的挣零花钱?
查看>>
推荐 2 个简历模板及 2 大加分技巧
查看>>
关于伪类选择器中一个冒号和两个冒号的区别
查看>>
理解敏捷开发准则
查看>>
[beta cycle]daily scrum10_2.25
查看>>
【转载】和 Thrift 的一场美丽邂逅
查看>>