首页/文章/ 详情

单片机中断程序,如何被中断?

28分钟前浏览4

来源 | 技术社区

很多同学都存在这样的疑惑:如果外部中断来的频率足够快,上一个中断没有处理完成,新来的中断该如何处理?

中断一般是由硬件(例如外设、外部引脚)产生,当某种内部或外部事件发生时,MCU的中断系统将迫使 CPU 暂停正在执行的程序,转而去进行中断事件的处理,中断处理完毕后,又返回被中断的程序处,继续执行下去,所有的Cortex-M 内核系统都有一个用于中断处理的组件NVIC,主要负责处理中断,还处理其他需要服务的事件。嵌套向量式中断控制器(NVIC: Nested Vectored Interrupt Controller)集成在Cortex-M0处理器里,它与处理器内核紧密相连,并且提供了中断控制功能以及对系统异常的支持。

处理器中的NVIC能够处理多个可屏蔽中断通道和可编程优先级,中断输入请求可以是电平触发,也可以是最小的一个时钟周期的脉冲信号。每一个外部中断线都可以独立的使能、清除或挂起,并且挂起状态也可以手动地设置和清除。

主程序正在执行,当遇到中断请求(Interrupt Request)时,暂停主程序的执行转而去执行中断服务例程(Interrupt Service Routine,ISR),称为响应,中断服务例程执行完毕后返回到主程序断点处并继续执行主程序。多个中断是可以进行嵌套的。正在执行的较低优先级中断可以被较高优先级的中断所打断,在执行完高级中断后返回到低级中断里继续执行,采用“咬尾中断”机制。


内核中断(异常管理和休眠模式等),其中断优先级则由SCB寄存器来管理,IRQ的中断优先级是由NVIC来管理。

NVIC的寄存器经过了存储器映射,其寄存器的起始地址为0xE000E100,对其访问必须是每次32bit。

SCB寄存器的起始地址:0xE000ED00,也是每次32bit访问,SCB寄存器主要包含SysTick操作、异常管理和休眠模式控制。

NVIC具有以下特性:


  • 灵活的中断管理:使能\清除、优先级配置
  • 硬件嵌套中断支持
  • 向量化的异常入口
  • 中断屏蔽
1. 中断使能和清除使能

arm将处理器的中断使能设置和清除设置寄存器分在两个不同的地址,这种设计主要有如下优势:一方面这种方式减少了使能中断所需要的步骤,使能一个中断NVIC只需要访问一次,同时也减少了程序代码并且降低了执行时间,另一方面当多个应用程序进程同时访问寄存器或者在读写操作寄存器时有操作其他的中断使能位,这样就有可能导致寄存器丢失,设置和清除分成两个寄存器能够有效防止控制信号丢失。
因此我可以独立的操作每一个中断的使能和清除设置。


1.1 C代码
 
*(volatile unsigned long) (0xE000E100) = 0x4 ; //使能#2中断
*(volatile unsigned long) (0xE000E180) = 0x4 ; //清除#2中断
1.2 汇编代码
 
__as m void Interrupt_Enable()
{
LDR R0, =0xE000E100  ;  //ISER寄存器的地址
MOVS R1, #04         ;  //设置#2中断
STR R1, [R0]         ;  //使能中断#2
}

__as m void Interrupt_Disable()
{
LDR R0, =0xE000E180  ;  //ICER寄存器的地址
MOVS R1, #04         ;  //设置#2中断
STR R1, [R0]         ;  //使能中断#2
}
1.3 CMSIS标准设备驱动函数
 
//使能中断#IRQn
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) 
{
    if ((int32_t)(IRQn) >= 0) {
        NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
    }
}
//清除中断#IRQn
__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) 
{
    if ((int32_t)(IRQn) >= 0) {
        NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
        __DSB();
        __ISB();
    }
}
//读取使能中断#IRQn
__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn)
{
    if ((int32_t)(IRQn) >= 0) {
        return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
    }
    else {
        return(0U);
    }
}
2. 中断挂起和清除挂起

如果一个中断发生了,却无法立即处理,这个中断请求将会被挂起。挂起状态保存在一个寄存器中,如果处理器的当前优先级还没有降低到可以处理挂起的请求,并且没有手动清除挂起状态,该状态将会一直保持。
可以通过操作中断设置挂起和中断清除挂起两个独立的寄存器来访问或者修改中断挂起状态,中断挂起寄存器也是通过两个地址来实现设置和清除相关位。这使得每一个位都可以独立修改,并且无需担心在两个应用程序进程竞争访问时出现的数据丢失。
中断挂起状态寄存器允许使用软件来触发中断。如果中断已经使能并且没有被屏蔽掉,当前还没有更高优先级的中断在运行,这时中断的服务程序就会立即得以执行。
2.1 C代码
 
*(volatile unsigned long)(0xE000E100) = 0x4 ; //使能中断#2
*(volatile unsigned long)(0xE000E200) = 0x4 ; //挂起中断#2
*(volatile unsigned long)(0xE000E280) = 0x4 ; //清除中断#2的挂起状态
2.2 汇编代码
 
__as m void Interrupt_Set_Pending()
{
LDR R0, =0xE000E100   ;  //设置使能中断寄存器地址
MOVS R1, #0x4         ;  //中断#2
STR R1, [R0]          ;  //使能#2中断
LDR R0, =0xE000E200   ; //设置挂起中断寄存器地址
MOVS R1, #0x4         ;  //中断#2
STR R1, [R0]          ;  //挂起#2中断
}

__as m void Interrupt_Clear_Pending()
{
LDR R0, =0xE000E100   ;  //设置使能中断寄存器地址
MOVS R1, #0x4         ;  //中断#2
STR R1, [R0]          ;  //使能#2中断
LDR R0, =0xE000E280   ; //设置清除中断挂起寄存器地址
MOVS R1, #0x4         ;  //中断#2
STR R1, [R0]          ;  //清除#2的挂起状态
}
2.3 CMSIS标准设备驱动函数
 
//设置一个中断挂起
__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) 
{
    if ((int32_t)(IRQn) >= 0) {
        NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
    }
}

//清除中断挂起
__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) 
{
    if ((int32_t)(IRQn) >= 0) {
        NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
    }
}

//读取中断挂起状态
__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) 
{
    if ((int32_t)(IRQn) >= 0) {
        return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
    }
    else {
        return(0U);
    }
}
NVIC属于处理器内核部分,因此在MM32 MCU芯片的用户手册中只有简单的提及,没有重点讲述,需要深入了解相关寄存器和功能需要参考《Cortex-M0技术参考手册》。

声明:


 
声明:本号对所有原创、转载文章的陈述与观点均保持中立,推送文章仅供读者学习和交流。文章、图片等版权归原作者享有,如有侵权,联系删除。  

来源:硬件笔记本
电路电子芯片控制
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2025-11-21
最近编辑:28分钟前
硬件笔记本
本科 一点一滴,厚积薄发。
获赞 157粉丝 46文章 698课程 0
点赞
收藏
作者推荐

RTC电源上的串联电阻多少合适?串联10K电阻为何电流变大?

之前分享了一位兄弟的RTC笔记,现在网上看到一个案例,有用到RTC的兄弟们可以一起看看 一、 摘要 现在几乎所有的电子产品都带RTC功能,因此RTC电池的寿命肯定是越长越好。 二、 问题描述 本案例是一个带RTC功能的工业产品,RTC部分的供电电路如下下图,产品发往市场半年以后,就提示更换RTC电池,远远低于设计寿命5年。图1-有问题的RTC电池供电电路三、 原因分析产品返回公司以后,我们更换上新的RTC电池,串联高精度万用表进去测量电流,发现RTC的工作电流高达100uA, 和我们设计的5uA有很大的差距。我们怀疑的点有:1、二极管D3漏电流太大,设备断电时,通过D3倒流到系统的电源上。2、RTC芯片影响,原来的RTC芯片为NXP-PCF8563P,手册描述备用电源时功耗为0.25uA;中途有更换国产RTC;3、RTC电源线路上有漏电路,例如电容的漏电流4、电阻R71影响。我们通过排除法,先排除D3,因为去除D3,电流只减小1uA左右;接着排除RTC电源上电容等漏电流,因为去除电容电流依然有100uA左右。将RTC芯片更换为NXP-PCF8563P。电流正常,大约只有4uA。接着我们换回国产RTC,同时将电阻更换为100R,则电流也正常,只有4uA左右。于是我们引出两个疑问:(1)RTC电源上的串联电阻多少合适?(2)为何串联10K的限流电阻会导致RTC芯片不仅没有变小,反而电流增大;1. RTC电源串联电阻阻值多少合适?RTC电源上串联的电阻阻值在网络上的争论一直在,有人说0R,有人说1K、10K等各种阻值,但是能够理论讲清楚的基本没有。首先我们 要明白这个电阻的目的:限流。参考各个厂商的一次性纽扣电池,以阳光动力的CR2025为例,其他品牌类似,厂家要求电池在任何情况下都不允许短路,否则有可能炸裂或者爆炸。因此,一旦发生后级短路时,限流电阻必须将电流限定在最大持续放电电流以内,运行产品工作不正常,但是不允许产品起火甚至爆炸。因此该型号的限流电阻最小值为 R=V/I=3V/3mA=1KΩ;对于电池来说,电阻可以比该阻值大,但是不能比该阻值小。图2-电池厂家的电池规格要求2. 串联10K电阻为何电流变大 ?回答问题前,我们先了解一下RTC芯片的特性:(1)、RTC芯片有两种工作模式,一种是正常工作模式,一种是备用电源工作模式,如下图,两者的供电电流可以相差200倍;(2)、每一种模式下,RTC芯片都可以理解为一个恒流源,比如电池模式需要1uA左右,正常模式需要200uA左右;(3)、RTC的芯片的电压范围非常广,可以在1.5V~5.5V之间都可以正常工作。RTC芯片可以理解为一个电流源,串联一个10K的电阻,当流过电流为100uA时,在电阻上的压降将会达到1V,如果此时电池电压只有2.6V,则RTC芯片的工作电压只有1.6V,如果电池电压更小,RTC芯片获得的电压更低,由于RTC芯片工作电压范围很广,但是需要的电流是基本不变的,为了获得足够的电流,RTC芯片可以理解为进一步降低阻抗,导致电流进一步加大。***可能在正常工作模式和备用电源模式之间的切换的逻辑不够清晰,导致使用电池的时候也进入正常工作模式。(此为猜测,没有从厂商的资料中找到根据)。图3-RTC芯片的直流工作参数四、 解决方案经过上述分析可知,为了延长电池的寿命,主要降低RTC回路上的电流。回路上的损耗主要有:电阻、二极管、RTC芯片、电容。1、RTC电池模式电流目前大部分的厂家的RTC芯片在电池模式下可以做到几百nA到1uA左右,因此RTC电流可以按照1uA进行估算。2、二极管的漏电流二极管的主要损耗在于漏电流,因此需要选择漏电流尽可能小的二极管,下图是BAS70系列二极管的漏电流的曲线图,为例保守起见,也可以按照1uA进行估算。图4-BAS70系列二极管漏电流 /温度/电压曲线3、电容损耗电容的损耗主要也是体现在漏电流,RTC电池对电源要求不高,因此使用100nF的电容滤波即可,漏电流可以评估约0.5uA。图5- 常见陶瓷电容漏电流4、电阻损耗经过上述分析,总的电流=二极管漏电流+RTC芯片电流+电容漏电流=1uA+1uA+0.5uA=2.5uA。电阻一般可以选择1K。RTC芯片和电阻为串联关系。1K电阻1uA的压降 :V=IR=1K*2.5uA=0.0025V功率为p1=U*U/R=0.0025V*0.0025V/1000=0.00625uWRTC芯片的功率P2=UI=(3V-0.2V-0.0025V)*1uA=2.7975uW电阻的损耗占比=P1/P2=0.089%,因此电阻的损耗基本可以忽略不计。5、电池的寿命估算以阳光动力电池CR2025为例,电池自放电损失约每年1%,标称容量为150mAH,上述案例的寿命评估T=150mAh*95%/(二极管漏电流1uA+RTC电流1uA+电容漏电流0.5uA)=57000H≈6.5年。6、最终的解决方案以阳光动力电池CR2025为例,二极管更换为更低漏电流1uA左右的BAS70系列,电阻只串联在电池上,只防电池短路,限制电流在3mA。图6- 改善后的RTC供电电路五、总结本文回复了RTC的两个问题。1、RTC电池要不要串联电阻,电阻阻值多少合适。2、RTC 寿命的评估考虑因素声明: 声明:文章来源网络。本号对所有原创、转载文章的陈述与观点均保持中立,推送文章仅供读者学习和交流。文章、图片等版权归原作者享有,如有侵权,联系删除。 来源:硬件笔记本

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈