当LK320T发生中断时,LK320T会自动到一个特定区域读取中断服务程序(ISR)的地址(这个特定区域也叫中断向量表),然后自动执行ISR。这与传统的中断处理方式不同,传统的方式一般是CPU从中断向量处开始执行代码,而执行的代码往往是一条跳转指令,这条指令跳转到真正的ISR处,现在来看,这种方式效率是较低的。
对于每个特定的芯片来说,其能够管理的中断及中断对应的设备设是固定的,为了灵活性一般设备通过向量中断控制器(VIC)与CPU联系,因为VIC非常重要,cortex-Mx已经将VIC集成到系统中了,LK320T只要将设备连到VIC就可以使用中断了。所以中断可以分为3个层次:设备级、中断向量控制器级、CPU级,在每一级都可以阻止中断信号向下一级的传递。cortex M0中的VIC也称NVIC,即被嵌套(nested)的VIC。
1.CPU级中断
置位后,CPU的PRIMASK寄存器除了不可屏蔽中断(NMI)和硬件错误异常外的中断都可以屏蔽掉。
__disable_irq()
__enable_irq()
2.NVIC的寄存器
中断使能和清除使能 |
SETENA |
NVIC_EnableIRQ(IRQn) |
IRQn=0~31 如果一个中断发生了,却无法立即处理(比如CPU正在处理更高优先级的中断),这个中断请求将会被挂起,挂起状态被保存在一个寄存器中,如果CPU的当前优先级还没有降低到可以处理挂起的请求,并且没有手动清除挂起的状态,该状态将会一直保存合法。 中断挂起状态寄存器允许使用软件来触发中断。
|
CLRENA |
NVIC_DisableIRQ(IRQn) |
|
|
中断挂起和清除挂起 |
SETPEND |
NVIC_SetPendingIRQ(IRQn) |
|
CLRPEND |
NVIC_ClearPendingIRQ(IRQn) |
|
|
中断优先级 |
IPR0~IPR31 |
NVIC_SetPriority(IRQn,priority) |
|
IRQn的值在sc32F5832.h中定义。
3.设备级中断:
因为资料不足,下面的很多内容是根据模板及用户手册推测的,很多要进行试验验证。
3.1GPIO中断
也可以说是外部中断,根据用户手册:
- 每个单独端口引脚均可用作外部中断输入。
- 边沿(上升/下降/双边)和电平可配置
- 单独的中断使能位
- 中断标志可查询
涉及中断的有:
INTMASK相当于中断开关;INTTYPE、INTBV、INTPOL设置中断信号的类型:高电平、低电平、上升沿、下降沿、单边沿、双边沿等;RIS和MIS是用于查询管脚上是否有中断信号,并可以清除中断。
系统并没有给每一个管脚都留了一个中断号,而是留了3个。也就是说约48个管脚共用,所以可能还要进行查询的。模板中分了3组,当模板代码有瑕疵:PA_IRQn 、PB_IRQn 、PC_IRQn 三个中断的中断号在sc32F5832.h中定义为16,17,18,而在startup_sc32F5832.s的16、17、18处的三个中断确是GPIO0_IRQHandler、GPIO1_IRQHandler、GPIO2_IRQHandler资料的统一还是不够。从中也可以看出外部中断上按照端口分组的。
3.2ADC中断
ADC中断 可在任意转换之后配置中断
涉及的寄存器较多,不再列举,在用户手册ADC部分
因为存在 16 个独立的转换(SOC),所以有 16 个转换完成(EOC)脉冲。通过配置(ADCCTL1[INTPULSEPOS])可以 选择 EOC 脉冲出现在转换开始时,或是出现在转换结束时。
ADC 模块的中断可以被配置成以任一 EOC 信号作为中断源,可以在 ( INTSELxNy [INTx(y)SEL])中进行设置。 ( ADCINTFLG [ADCINTx])(x=1~9) 中断标志位指示 是否发生了相应 的中 断事件,该标志 位通 过向 ( ADCINTFLGCLR [ADCINTx]) 写 1 清除。在连续转换模式 (INTSELxNy[INTxCONT]=1)下,不论中断标志是否置位只要 一个 EOC 事件发生都会继续产生中断脉冲;若不在连续模式下,中断标志位被清零前不能继续产生中断脉冲,否则就 会产生中断溢出。中断溢出标志位 (ADCINTOVF[ADCINTx]) 指示是否发生了中断溢出事件,该标志位通过向 (ADCINTOVFCL[ADCINTx]) 写 1 清除。
什么信号引起中断(16个选一个)?何时发生中断(开始转换时,还是结束转换时)?
ADCINTFLG
|
中断标志寄存器
|
是否有ADC中断发生了? |
ADCINTFLGCLR
|
中断标志清零寄存器
|
|
ADCINTOVF
|
中断溢出寄存器
|
ADC转换是否发生了溢出? |
ADCINTOVFCL
|
中断溢出清零寄存器
|
|
INTSELxNy
|
中断 x 、 y 选择寄存器
|
1&2,3&4,5&6,7&8,9&10(是否中断使能?哪一个信号引起中断) |
ADCINTSOCSELx
|
中断 SOC 选择寄存器x
|
什么信号启动转换(SOC) |
ADC_CMP_INTR
|
比较器中断寄存器
|
|
ADC0_IRQn,ADC1_IRQn、ADC2_IRQn、ADC_IRQn三个中断号在sc32F5832.h中定义为19,20,21,而在其用户手册中明确说只有一个12位的ADC,是不是其他的类型芯片有4个ADC?从其示例代码中可以看出ADC实际使用的是编号为21的中断。
下面是转换ADCINB5输入的模拟量,软件启动转换的模板中的例子的有关中断的主体部分,其他类似。
void ADC_Init(){
ADC_RESET; // ADC复位
ADC_ENABLE; // ADC使能
//跟ADC转换有关的参数设置,具体情况具体对待,一般不用改(略)
....
//跟中断有关的设置,转换ADCINB5输入的模拟量,软件启动转换
ACCESS_ENABLE;
ADC -> INTSEL5N6_b.INT5E = 1;// ADCINT5使能
ADC -> INTSEL5N6_b.INT5CONT = 0; // ADCINT5 非连续模式使能
ACCESS_ENABLE;
ADC -> INTSEL5N6_b.INT5SEL = 5; // 5通道转换结束信号作为中断信号
ACCESS_ENABLE;ADC->ADCSOC5CTL_b.CHSEL = ChSel[5];//Chesl[5]=13,即ADCINB5信号作为5通道的输入
ACCESS_ENABLE;ADC->ADCSOC5CTL_b.TRIGSEL = TrigSel[5];//TrigSel[5]=0,即软件触发ADC启动转(SOC)
}
...
int main( void ){
Device_Init();
...
ADC_Init();
IRQ_Enable();//开中断--->NVIC_EnableIRQ(ADC_IRQn);
while(1){
...
ADC -> ADCSOCFRC1 |= (1 << 5);//ADC - SOC5强制转换
...
}
}
uint16_t ADC_SOC5_Result = 0;
void ADC_IRQHandler()
{
if((ADC -> ADCINTFLG_b.ADCINT5))
{
ACCESS_ENABLE;
ADC_SOC5_Result = ADC -> ADCRESULT5_b.RESULT;//读出转换结果
...
...
ACCESS_ENABLE;
ADC -> ADCINTFLGCLR_b.ADCINT5 = 1;//清除中断标志,以防再次引起中断
NVIC_ClearPendingIRQ(ADC_IRQn); //中断已处理,给低优先级的中断一个机会,防止进程竞争
}
}
4.中断与事件
事件和中断是一对令人感到非常困惑的概念,中断已经有了,为什么还提出事件这个概念?有中断请求了,为什么还有事件请求?STM32_外部中断线/事件线理解一文提出了解释:可以这样简单的认为,事件机制提供了一个完全有由硬件自动完成的触发到产生结果的通道,不要软件的参与,降低了CPU的负荷,节省了中断资源,提高了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法。
举例说明:现在要完成一项任务,当按键按下时启动ADC,并将ADC转换的结果显示出来。
4.1采用中断机制
按键按下,触发外部中断,系统自动调用外部中断服务程序,外部中断服务程序启动ADC,等待转换结果,当装换结果出来后显示结果。
4.2采用事件机制
ADC启动前将ADC启动信号与外部按键事件关联,按键按下时,系统中断启动ADC,待转换结束,触发ADC中断,系统自动调用ADC中断服务程序,读取结果并显示。
采用事件机制以后,处理的流程变复杂了,但是响应的速度提高了。