有些东西看过了之后不及时巩固的话,过一段时间就忘得差不多了,前段时间看了实时中断RTI,趁着还有一些余热,赶紧记下来。
之前一些以为实时中断只有在运用嵌入式实时操作系统时才会用到的,觉得是很高级的东西,所以一直没信心,不敢去看。
实时中断其实并不复杂,简单地说,就是一个定时模块,定时溢出,产生中断。功能跟PIT差不多,都能用定时。 不过既然有了PIT可以定时了,为什么还要多此一举弄多一个实时中断RTI 呢?因为,PIT 时钟电路每固定一段时间都必须更新一次时间信息,这个更新的责任就落在MCU身上了。对于那种比较繁重的系统而言,“进行一次更新”会耗费许多的资源。RTI 专注于记时工作,使MCU可以空出来处理其它的工作。外部晶振时钟可以直接“驱动”RTI。
RTI定时不会很准,因为它没有经过复杂的时钟处理,然后经过性价比极高的配置之后,可以变为a*2^b倍数。因为a*2^b不能是任意数整数,不能配成你想要的任何频率,所以说RTI定时不会很准,不过它用起来还是很灵活的。 现在说一下RTI 是如何配置的:
第一步,实时中断RTI 在默认情况下是关闭的,怎样才能让 RTI 工作呢? 这就用到实时中断控制寄存器 RTICTL 了。 RTICTL是一个八位寄存器,第七位没定义,只用到低七位[RTR6~RTR0]。 当RTR[6:4]=000时,实时中断被禁止,只要当RTR[6:4] 不全为0时,实时中断就开启了。同时实时中断的溢出周期也是由该寄存器配置的。 RTI 的参考时间是外部晶振的时钟OSCCLK。 故,
实时中断的溢出时钟周期=(RTR[3:0]+1) x (2的(RTR[6:4] + 9)次
方)/OSCCLK。
第二步,要想在实时中断溢出时产生一个中断,则用到寄存器 CRGINT 了。 当CRGINT_RTIE=1时,每个周期结束时,就会产生一个中断。
只要配置好上面说的两个寄存器,再写上相应的中断函数,实时中断就可以用了。顺便提一下,实时中断 RTI 的中断号是 7 。
CRGFLG_RTIF 是实时中断的标志位,当 RTI 溢出时,CRGFLG_RTIF 就会由硬件置1,向CRGFLG_RTIF 写1,可以清零标志位。这和51单片机不一样,51单片机的标志位清零是向相应的寄存器写0。
与 RTI 相关的寄存器还有 CLKSEL_RTIWAI,不过一般都不会用到。当CLKSEL_RTIWAI=1时,只要系统进入等待模式,RTI 就停止工作。当CLKSEL_RTIWAI=0时,在等待模式下,RTI 仍然工作。
实时中断写到这里接进尾声了,下面附些与实时中断相关的程序:
#include /* common defines and macros */#include /* derivative information */#pragma LINK_INFO DERIVATIVE \"mc9s12xs128\"
void RTI_INIT() //实时中断 RTI 初始化函数
{
CRGINT_RTIE=1; // 允许在每个周期结束产生中断
RTICTL=59; // 设置RTICTL为 0101 1001 溢出周期为 (9+1)*2^(5+9)/(16M)= 10*2^14/(16M)
} //实际上是10.24ms 16M是外部晶振的频率,实时中断以外部晶振时钟为参考时钟
void main()
{
DisableInterrupts;
RTI_INIT();
EnableInterrupts;
for(;;)
{
}
}
#pragma CODE_SEG __NEAR_SEG NON_BANKED //实时中断RTI 中断函数
void interrupt 7 RTI(void)
{
CRGFLG_RTIF=1; //向CRGFLG_RTIF 写1 清除标志位
}