STM32F103系列单片机中断总结:概念和使用方法

您所在的位置:网站首页 nbp中断 STM32F103系列单片机中断总结:概念和使用方法

STM32F103系列单片机中断总结:概念和使用方法

2024-01-17 01:34| 来源: 网络整理| 查看: 265

文章目录 前言一、中断の概念1.术语解释2.F103系列单片机的中断及其管理器 二、中断相关的寄存器及其设置方法三、配置中断的步骤及其库函数四、中断配置的模板总结

前言 随富随贫且欢乐,不开口笑是痴人。-----白居易

中断是学习单片机必须掌握的内容!正因为有了中断,单片机即使不搭载操作系统运行大型程序也一样的纵享丝滑。正因为有了中断,我们才能快速便捷的编写出有多线程那味儿的程序。STM32F103系列单片机中断非常强大,每个外设都可以产生中断,F103 在内核水平上搭载了一个中断响应系统, 支持为数众多的系统中断和外部中断。本文对其稍微总结一下下,包括其相关寄存器及其相应的库函数设置方法(了解即可),中断的设置步骤(掌握),最后给出一个模板给套。希望大家争取看一遍便会完全了解并使用。

一、中断の概念 1.术语解释

单片机中断:指单片机处理程序运行中出现的“紧急事件”的整个过程,程序运行过程中,系统外部、系统内部或者现行程序本身若出现紧急事件,单片机立即中止现行程序的运行,自动转入相应的处理程序(中断服务程序),待处理完后,再返回原来的程序运行,这整个过程称为程序中断。 中断可分为可屏蔽中断和不可屏蔽中断两类:可由程序控制其屏蔽的中断称为可屏蔽中断,屏蔽时,单片机将不接受中断(即不进入中断服务程序),反之,不能由程序控制其屏蔽,单片机一定要立即处理的中断称为不可屏蔽中断。

个人理解: 众所周知,学习过程中使用类比学习法,通过对比新知识和旧知识的区别和联系,可以加深印象。 在这里插入图片描述 委托式事件模型见下图: 在这里插入图片描述 委托式事件处理:我们通过为组件注册特定的事件监听器,当发生事件后,组件就可以由自己动态解决发生的事件,然后把大量的组件有机的组合起来,从而提高响应速度,同时解放生产力。 中断可以类比委托式事件处理:为单片机的特定组件指定中断的触发条件,编写中断服务函数处理发生的中断,这样编写单片机程序时即可站得高,望得远,把握主流程,从细枝末节中抽身。

2.F103系列单片机的中断及其管理器

其支持的系统中断有 8 个 ,外部中断有 60个,除了个别中断的优先级被定死外,其它中断的优先级都是可编程的。想知道所有的的系统中断和外部中断吗?那么请在标准库文件 stm32f10x.h 这个头文件查询IRQn_Type 这个枚举定义,里面包含了 F103 系列全部的中断声明。可以清楚地看到内核使用的,F103系列通用的中断号,再往下面便是不同容量的子产品特有的中断。

NVIC:嵌套向量中断控制器,控制着整个芯片中断相关的功能,是Cortex-M3内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对 Cortex-M3内核里面的 NVIC进行裁剪,把不需要的部分去掉,即 STM32F103系列的 NVIC 是阉割过得。

二、中断相关的寄存器及其设置方法

参看库文件 core_cm3.h ,找到NVIC_Type结构体,查看其封装的寄存器:

typedef struct { __IO uint32_t ISER[8]; // 中断使能寄存器 uint32_t RESERVED0[24]; __IO uint32_t ICER[8]; // 中断清除寄存器 uint32_t RSERVED1[24]; __IO uint32_t ISPR[8]; // 中断使能悬起寄存器 uint32_t RESERVED2[24]; __IO uint32_t ICPR[8]; // 中断清除悬起寄存器 uint32_t RESERVED3[24]; __IO uint32_t IABR[8]; // 中断有效位寄存器 uint32_t RESERVED4[56]; __IO uint8_t IP[240]; // 中断优先级寄存器(8Bit wide) uint32_t RESERVED5[644]; __O uint32_t STIR; // 软件触发中断寄存器 } NVIC_Type;

在配置中断的时候我们一般只用 ISER,ICER 和 IP 这三个寄存器, ISER 用来使能中断,ICER 用来失能中断,IP 用来设置中断优先级。

翻到固件库文件 core_cm3.h 的最后,看到了寄存器的设置方法,如下: void NVIC_EnableIRQ(IRQn_Type IRQn) 使能中断 void NVIC_DisableIRQ(IRQn_Type IRQn) 失能中断 void NVIC_SetPendingIRQ(IRQn_Type IRQn) 设置中断悬起位 void NVIC_ClearPendingIRQ(IRQn_Type IRQn) 清除中断悬起位 uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) 获取悬起中断编号 void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) 设置中断优先级 uint32_t NVIC_GetPriority(IRQn_Type IRQn) 获取中断优先级 void NVIC_SystemReset(void) 系统复位

中断优先级: 当同时有两个及以上的中断时,就必须设置中断优先级了,在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx, 用来配置外部中断的优先级,其宽度为 8bit,每个外部中断可配置的优先级为 0~255,数值越小,优先级越高。但是绝大多数CM3芯片都会精简设计,以致实际上支持的优先级数减少,在F103中,只使用了高 4bit。 分成抢占优先级(主优先级)和子优先级。而且为了管理这用于表达优先级的这高4bit,于是又封装了一个优先级组,通过选择不同的组可以得到不同的优先级数目的比例,参看库文件misc.h:

============================================================================================================================ NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority | Description ============================================================================================================================ NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority | | | 4 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority | | | 3 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority | | | 2 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority | | | 1 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority | | | 0 bits for subpriority ============================================================================================================================

显然,大多数时候, 人们都喜欢选择折中的,即 NVIC_PriorityGroup_2。 当有多个中断同时请求(注意是还没执行中断服务函数)时,抢占优先级(主优先级)高的就会先得到执行,如果抢占优先级(主优先级)相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,就越先响应。

中断嵌套: 假定在选定了优先级组后,在组里添加了两个中断,当单片机正在执行中断1的服务函数过程中,突然,又来一个中断2的请求,那么: 若中断2的主优先级比中断1的主优先级小,那么单片机暂停中断1的服务函数,进入中断2的服务函数,执行完之后,才返回中断1的服务函数。形成了所谓的嵌套。 若中断2的主优先级比中断1的主优先级大,那么就必须等待中断1的服务函数执行完毕才能响应中断2。不能形成嵌套。

三、配置中断的步骤及其库函数

好了,如果前面不太彻底明白的话也没关系,搬砖的只需要记住在哪里搬,搬去哪里,怎么搬就行了,至于这块砖是怎么生产的就不需要了解了。进入正题 在这里插入图片描述 在配置每个中断的时候一般有4个步骤: 1、结合当前使用的外设,确定自己需要的中断源(单片机外设)。比如单片机用于通信的固件外设(I2C,SPI,USART等)有发送完成,接收完成中断。GPIO引脚也可设置上升沿,下降沿中断。定时器的计时中断。。。所有的中断类型参看stm32f10x.h 这个头文件IRQn_Type 这个枚举定义。

2、 初始化 NVIC_InitTypeDef 结构体,配置中断优先级分组,设置抢占优先级和子优先级,使能中断请求。参看固件库文件 misc.h:

typedef struct { uint8_t NVIC_IRQChannel; //用来设置中断源 uint8_t NVIC_IRQChannelPreemptionPriority; //抢占优先级(主优先级) uint8_t NVIC_IRQChannelSubPriority; //子优先级 FunctionalState NVIC_IRQChannelCmd; //中断使能( ENABLE)或者失能( DISABLE) } NVIC_InitTypeDef;

此结构体配置完后,使用库函数 void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);配置NVIC。

3、 编写中断服务函数,在固件库启动文件 startup_stm32f10x_md.s 中预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表:

WWDG_IRQHandler PVD_IRQHandler TAMPER_IRQHandler RTC_IRQHandler FLASH_IRQHandler RCC_IRQHandler EXTI0_IRQHandler EXTI1_IRQHandler EXTI2_IRQHandler EXTI3_IRQHandler EXTI4_IRQHandler DMA1_Channel1_IRQHandler DMA1_Channel2_IRQHandler DMA1_Channel3_IRQHandler DMA1_Channel4_IRQHandler DMA1_Channel5_IRQHandler DMA1_Channel6_IRQHandler DMA1_Channel7_IRQHandler ADC1_2_IRQHandler USB_HP_CAN1_TX_IRQHandler USB_LP_CAN1_RX0_IRQHandler CAN1_RX1_IRQHandler CAN1_SCE_IRQHandler EXTI9_5_IRQHandler TIM1_BRK_IRQHandler TIM1_UP_IRQHandler TIM1_TRG_COM_IRQHandler TIM1_CC_IRQHandler TIM2_IRQHandler TIM3_IRQHandler TIM4_IRQHandler I2C1_EV_IRQHandler I2C1_ER_IRQHandler I2C2_EV_IRQHandler I2C2_ER_IRQHandler SPI1_IRQHandler SPI2_IRQHandler USART1_IRQHandler USART2_IRQHandler USART3_IRQHandler EXTI15_10_IRQHandler RTCAlarm_IRQHandler USBWakeUp_IRQHandler TIM8_BRK_IRQHandler TIM8_UP_IRQHandler TIM8_TRG_COM_IRQHandler TIM8_CC_IRQHandler ADC3_IRQHandler FSMC_IRQHandler SDIO_IRQHandler TIM5_IRQHandler SPI3_IRQHandler UART4_IRQHandler UART5_IRQHandler TIM6_IRQHandler TIM7_IRQHandler DMA2_Channel1_IRQHandler DMA2_Channel2_IRQHandler DMA2_Channel3_IRQHandler DMA2_Channel4_5_IRQHandler

实际的中断服务函数都需要我们重新编写, 放在 stm32f10x_it.c 这个库文件中,可以看到那里面已经有了一些写好的系统中断的服务函数,我们只需跟着在文件末尾继续写就行了。中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数,实现不了中断。 注意:中断服务函数里不应该处理耗时的操作!

4.使能外设的某个中断,具体由此外设的相关中断使能函数控制,在此外设的固件库文件找到函数原型: void xxx_ITConfig(xxx_TypeDef* xxx, uint16_t xxx_IT, FunctionalState NewState);

四、中断配置的模板

这个中断配置函数放在自己的外设初始化相关的文件里,在外设引脚初始化后调用即可。

/** * @brief 配置嵌套向量中断控制器NVIC * @param 无 * @retval 无 */ static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 配置NVIC为优先级组1 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 配置中断源:按键1 */ NVIC_InitStructure.NVIC_IRQChannel =(中断源); /* 配置抢占优先级 */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 配置子优先级 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; /* 使能中断通道 */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }

接下来这个中断服务函数需要放在stm32f10x_it.c里

/** * @brief 中断服务函数 * @param 无 * @retval 无 */ void (需要的外设名)_IRQHandler(void) { //确保是否产生了中断 if((需要的外设名)_GetITStatus(中断标志位) != RESET) { //TODO: /*别放置耗时间的操作!!!!!!!!*/ //清除中断标志位 (需要的外设名)_ClearITPendingBit(中断标志位); } }

最后这条语句在外设初始完成后调用:(在外设的固件库找到具体的函数原型)

xxx_ITConfig( xxx, xxx, ENABLE); 总结

本文包括中断相关寄存器及其相应的库函数设置方法(了解即可),中断的设置步骤(掌握)。 最后问大家一个问题:什么条件下,孤立小系统里的时间可以倒流? 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3