1、Freescale HCS12 微控制器 MC9S12DG128,HCS12中断,默认状态: 在进入中断服务程序时,I位自动置1,禁止其他可屏蔽中断 即使有优先级更高的中断请求,也必须等当前中断服务程序执行完以后才能响应 优先级的作用只有在多个中断源同时请求中断时在能体现 无法实现中断嵌套如果在进入中断服务程序时,手动对I位清零: 任何其他可屏蔽中断都可以被响应,无论其优先级有多高 中断响应由时间控制,可以实现中断嵌套 对中断执行无法预测HPRIO寄存器 写入HPRIO中的中断向量的后八位,可以改变该中断的优先级 同样,优先级的作用只有在多个中断源同时请求中断时在能体现,在CW4.6环境下,中
2、断编程主要有两种方式: 第一种是使用“interrupt”关键字,“interrupt”关键字是一个非标准ANSI-C的关键字,因此,它不能被所有ANSI-C编译器厂商所支持。同样,对不同的编译器,interrupt”关键字的用法可能会改变。“interrupt”关键字同样会提示编译器下面的函数是一个中断服务例程。 例: void interrupt 20 SCI0_ISR(void); 其中,interrupt表示该函数为终端服务程序,后面的20表示中断号20,在这里SCI0的中断向量号就是20. 这种方法写起来非常简单,但是,在S12单片机实际使用中,中断号并没有在手册中给出,通常需要自己
3、在中断向量表中从上往下数出来,或者根据中断向量计算得到,很容易出错。于是有了第二种方法: 在ISR程序之前,使用符号“#pragma TRAP_PROC”,TRAP_PROC 提示编译器下面的函数是中断服务例程。编译器会用一个特殊的中断返回指令来结束这个函数。 此时,中断函数的书写如下所示: #pragma TRAP_PROC void SCI0_ISR(void) . 这时候编译器不知道这个ISR指向那个中断向量,我们需要在链接文件即:prm文件中指定之。 使用 VECTOR命令来实现中断向量与ISR程序的连接。 例:VECTOR 0 _Startup /这是系统默认prm文件中自带的,即复
4、位后0号中断即复位中断的ISR为_Startup() 我们可以这样写: VECTOR 20 SCI0_ISR /指定中断号 或者 VECTOR ADDRESS 0xFFD6 SCI0_ISR /直接指定中断向量地址注:使用#pragma TRAP_PROC与修改prm文件的方法,在中断服务子程序的结尾处必须要手动加入返回主程序的指令,包括取出堆栈、中断返回两个步骤。 在S12单片机中,可以写作 asm pula; rti;尾注: 两种方法所写的中断服务子程序必须被放在非分页存储区内,即non_blanked code seg. 其中一种常用的方法是在服务子程序前声明:/下面代码放在NON_BA
5、NKED区 #pragma CODE_SEG NON_BANKED 在中断程序后声明:/下面内容按默认放置 #pragma CODE_SEG DEFAULT,HCS12默认中断处理机制,运 行,中断 A,中断 B,程序,低优先级,高优先级,中断A请求,中断B请求,人 人 平 等,在可屏蔽中断服务程序中EnableInterrupts,运 行,中断 A,中断 B,程序,低优先级,高优先级,中断B请求,中断B被挂起,中断A请求,长 幼 不 分,采用中断优先处理机制,运 行,中断 A,中断 B,程序,低优先级,高优先级,中断A请求,中断B请求,中断B返回,等 级 森 严,中断优先处理机制,在中断服务
6、程序中,首先对I为清零,即EnableInterrupts选择优先级更高的中断源可以进入响应中断设置优先等级 两级 一个中断源为低优先级,其他为高优先级 在低优先级中断服务程序中,对I位清零 在高优先级中断服务程序中,不清零 多级 利用局部的中断屏蔽位 比如Timer Channel0 的中断屏蔽位 TIE_C0I,优先机制 - 两级,例如: 中断向量地址 $FFF0 FFF1 为低优先级 其他的中断为高优先级 在$FFF0 FFF1 中断服务程序中,EnableInterrupts(I位清零) 其他的中断包括自己都可以在中断服务程序执行时,被响应 在其他的中断服务程序中,I位不清零(默认)
7、只有当前中断服务程序执行完后,才能响应其他的中断请求,当同时有多个中断源请求中断时,中断向量地址最靠近$FFFF的,将会首先被响应,优先机制 多级,要求: 在低优先级的中断服务程序中,高优先级的中断请求可以被响应,HPRIO = 0xEA: ECT0,1,2同时请求中断时,CPU将会首先响应通道2 默认时, CPU将会首先响应通道0,优先机制 多级,情况 1: 每个中断都单独发生,在一个中断程序执行时,没有其他中断情况 2: 在执行ECT1的中断服务程序时,ECT0请求中断 ECT0中断服务程序将被执行 情况 3: 在执行ECT2的中断服务程序时,ECT0请求中断 ECT2的中断服务程序执行结
8、束后,执行ECT0的中断服务程序 情况 4: ECT1,ECT2同时请求中断 ECT1的中断服务程序先执行,当EnableInterrupts后 执行ECT2的中断服务程序 ECT2的中断服务程序执行结束后,返回执行ECT1的中断服务程序,方案:优先机制 多级,在ECT0中断服务程序中:在ECT1中断服务程序中(自定义优先级最低):在ECT2中断服务程序中(自定义优先级最高): 用户程序,TIE_C1I = 0; /关闭ECT1局部中断 TIE_C2I = 1; /开放ECT2局部中断 EnableInterrupts; /开放全局中断 TIE_C1I = 1; /开放ECT1局部中断 TIE
9、_C2I = 1; /开放ECT2局部中断,TIE_C0I = 1; /开放ECT0局部中断 TIE_C2I = 1; /开放ECT2局部中断 EnableInterrupts; /开放全局中断 TIE_C0I = 1; /开放ECT0局部中断 TIE_C2I = 1; /开放ECT2局部中断,ECT模块的组成,8 个独立的定时器通道,每个通道具备输入捕捉和输出比较功能4 个带有8 位缓存的脉冲累加器,也可以作为2个16 位的累加器使用 带有4 位预分频因子的16 位模数递减计数器 用户可选可抵御噪音的延迟计数器,ECT系统控制寄存器1: TSCR1,TEN=1:定时器使能; TEN=0:定时
10、器禁止,进入低功耗状态。 TSWAI=0:等待模式时定时器继续工作,方便调试; 1:禁止定时器。 TSFRZ=0:冻结模式时定时器继续工作,方便仿真; 1:禁止定时器。 TFFCA=0:自动清除标志位; 1:手动清除。,注:在ECT模块初始化时必须设置TSCR1才可以使定时器工作。,一般设置TSCR1=0x80,TSCR1,ECT系统控制寄存器2: TSCR2,TOI=0:禁止定时器溢出中断; TOI=1:允许。 TCRE=0:定时器自由运行;1=输出比较7引起复位。 PR2、PR1、PR0:定时器预分频因子,TSCR2,ECT系统计数寄存器:TCNT,TCNT: 16位的加1自由计数器,最大
11、值为65535。 一般直接(非中断)使用的方法:while(TCNT!=0x0000); /计算未满足时,就一直等待while(TCNT=0x0000);/计数瞬时满足,TCNT,实验3:内容(1) ECT控制流水灯显示,int counter; void TimerOverflow(void) while (TCNT != 0x0000); /等待TCNT溢出时(恢复0x0000),就结束空循环,执行下面语句counter+; if (counter = 8) PORTB = 0x7e; / 0x7e=0111 1110if (counter = 7) PORTB = 0xbd; / 0xb
12、d=1011 1101if (counter = 6) PORTB = 0xdb; / 0xdb=1101 1011if (counter = 5) PORTB = 0xe7; if (counter = 4) PORTB = 0xe7; if (counter = 3) PORTB = 0xdb; if (counter = 2) PORTB = 0xbd; if (counter = 1) PORTB = 0x7e; void main(void) TSCR1 = 0x80; / TSCR1.7=TEN位(Timer Enable位,0=Disables,1=enable)TSCR2 =
13、0x03; / 预分频器设置 TSCR2.2-0:0=1,1=2,2=4,3=8,4=16,5=32,6=64,7=128/预置分频系数控制着每个自由运行计数时间,它需要216个定时器时钟时间才溢出一次.counter = 0;DDRB=0xff; / 设置端口B为输出方式PORTB=0xff; / LEDs off for (;) TimerOverflow(); if (counter = 8) counter = 0;TSCR2 = 0x05; /调整定时器的预分频器值 ,本例是否使用中断,主要用途: 测量事件发生的间隔时间输入捕捉能感应到引脚上的电平的变化 如果发现电平变化,则: 1、
14、计数器的值被保存到到输入捕捉寄存器中,状态标志位被置1 2、如果中断允许,则向CPU发出中断请求,定时器模块输入捕捉功能,定时器模块IC0-IC7: 既可以用于输入捕捉、也可以用于输出比较功能,定时器模块输入捕捉,IOSx: 0=通道x为输入捕捉获; 1=通道x为输出比较。,输入捕捉/输出比较选择寄存器TIOS,8个16位的定时器通道寄存器TC0,TC1,TC7,当检测到IOSx选择位对应的输入捕捉沿跳变、或触发输出比较的输出动作时,锁存自由运行计数器的计数值。,B2,B1,B0,C7F C6F C5F C4F C3F C2F C1F C0F,RST: 0 0 0 0 0 0 0 0,捕捉/比
15、较通道x的中断标志位,写 1清除中断状态标志位。,定时器中断标志寄存器1: TFLG1,CxI:1=第x个通道中断允许; 0=第x个通道中断禁止。,定时器中断使能寄存器: TIE,定时器模块输入捕捉,EDGnA/B:输入捕捉边沿控制,n代表通道序号。,。,控制寄存器3/4: TCTL3、TCTL4,定时器模块输入捕捉,SHxy=0:正常操作。1=通道x在通道y上产生同样的动作。 TFMOD=0:只要产生正确的输入捕获事件,TFLG1中的CxF位就置一。1=队列模式时才使用。 PACMX=0:8位脉冲累加器溢出后自动回0。1=不自动回0,停留在0XFF。脉冲累加器对IC通道捕获的有效边沿数量进行
16、计数。 BUFEN=1:使用输入捕获缓冲区。0=不使用。 LATQ=0:输入捕获队列模式使能。产生一次成功的输入捕获时,IC通道寄存器中保留的计数值会被送到保持器中,然后IC寄存器会接收新的计数值。1=锁存模式使能。,输入控制系统控制寄存器:ICSYS,实验3:内容(2) ECT输入捕捉控制LED灯显示,要求:利用输入捕捉0通道,对外来的信号进行下降沿捕捉,并触发中断。中断发生后用LED灯指示中断成功。,void main(void) EnableInterrupts; sysInit(); /包含ECTInit(void)DDRB = 0xFF; / PTB as output 设置端口B为
17、输出方式PORTB = 0x00;/ LEDs onfor(;) ,void ECTInit(void) TIOS_IOS0 = 0; / Put the PT0 as the Input Capture Pin /设置PT0为输入捕捉(IC)TSCR1 = 0x90; /0x90=1001 0000 Enable the Clock定时器使能, 自动清除相应寄存器 TCTL4_EDG0B = 1, TCTL4_EDG0A = 0; /下降沿捕捉 TSCR2_PR0 = 1; /预分频系数Prescale = 32TSCR2_PR1 = 0;TSCR2_PR2 = 1;TIE_C0I = 1;
18、 /定时器中断使能寄存器TIE,COI=1中断使能,=0中断屏蔽 ,interrupt void Enhanced_Capture_Timer_channel_0(void) PORTB = PORTB; / PORTB灯取反 ,实验3:内容(2) ECT输入捕捉控制LED灯显示,/以下是在main函数中,如何使用PORTA_BIT6来产生一个方波信号。 DDRA=0xff; /设置PORTA的方向寄存器,为输出 PORTA=0x00; /PORTA的输出初始化为低电平 DDRB=0xff; /PORTB设置为LED灯的控制信号 PORTB=0xff; /LED全灭 for(;) for(i=
19、0;i6000;i+)PORTA_BIT6=1;/循环中设置信号为高电平for(i=0;i6000;i+)PORTA_BIT6=0; /循环中设置信号为低电平,产生方波,void ic_init(void) /IC0的初始化: TSCR1= 0x90; /主定时器使能TSCR2=0x07; /分频因子=128ICSYS=0x02; /IC缓冲使能TIOS=0; /通道设置为输入捕获TCTL4=0xff; /采用上升、下降沿触发TIE=0x01; /通道0开中断,/方波信号已经成功得产生了,中断服务程序: void interrupt 8 ic0_int(void) TFLG1_C0F=1;/中
20、断标志清除ic4=TC0;/通过读TC0寄存器来响应中断,ic4为用户设置的变量 PORTB=0x55; /用LED灯来指示已经进入了中断,实验要求:利用输入捕捉0通道,对外来的信号进行双沿捕捉,并触发中断,中断发生后,读取捕捉后的计数值。方波信号由PORTA_BIT6产生,PORTA_BIT6和IOC0硬件连接。,最简单最常用的功能就是:产生一定间隔的脉冲, 其非常精确的时间间隔的电平输出,比使用延时要准确的多。通过定时器通道寄存器TC0TC7的预设值与自由计数器TCNT比较,当两者相等时触发中断,并按照预设的输出方式输出电平。,定时器模块输出比较,定时器模块输出比较,OMn:输出模式选择位
21、; OLn:输出电平选择位 这8对控制位是用来指定输出比较的输出动作的,当OMn 和OLn 二者任意一个为1时,OCn对应的端口会有相应的输出。 如果需要用OMn 和OLn 来控制相应定时器端口的输出,则OC7M 中的对应位必须清零。,定时器控制寄存器1/2: TCTL1、TCTL2,void ECTInit(void) TIOS_IOS0 = 1; /设置PT0为输出比较(OC)TSCR1 = 0x90; /定时器使能, 自动清除相应寄存器 TCTL4_EDG0B = 1, TSCR2_PR0 = 0; /预分频系数Prescale = 32TSCR2_PR1 = 0;TSCR2_PR2 =
22、 0;TCTL2_OM0 = 1; TCTL2_OL0 = 0; / OC0输出0 TIE_C0I = 1; /定时器中断使能寄存器TIE,COI=1中断使能,=0中断屏蔽 ,实验3:内容(3) ECT输出比较控制,要求:利用输出比较0通道,输出方波信号。,void main(void) EnableInterrupts;sysInit(); /包含ECTInit(void)for(;) ,interrupt void Enhanced_Capture_Timer_channel_0(void) /当自由运行计数器(TCNT)的值与TC0的值相等时,触发中断if ( !TCTL2_OL0) /判断TCTL2_OL0的值是否为0 TCTL2_OM0 = 1; TCTL2_OL0 = 1; / OC0输出置1 TC0 = TCNT + 1500;/设置下次输出定时时间,else if ( TCTL2_OL0) TCTL2_OM0 = 1; TCTL2_OL0 = 0; / OC0输出置0TC0 = TCNT + 500; /设置下次输出定时时间 ,定时器模块输出比较,FOCxx通道强制输出比较 在相应的寄存器位写入强制输出比较命令,会立即使相应的通道处于输出比较状态。,强制输出比较寄存器:CFORC,