一、中断系统
中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。
当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。
当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。
二、STC89C52中断资源
STC89C52系列单片机提供了8个中断请求源,它们分别是:外部中断0(INT0)、定时器0中断、外部中断1(INT1)、定时器1中断、串口(UART)中断、定时器2中断、外部中断2(INT2)、外部中断3(INT3)。所有的中断都具有4个中断优先级。
用户可以用关总中断允许位(EA/IE.7)或相应中断的允许位来屏蔽所有的中断请求,也可以用打开相应的中断允许位来使CPU响应相应的中断申请:每一个中断源可以用软件独立地控制为开中断或关中断状态;每一个中断的优先级别均可用软件设置。高优先级的中断请求可以打断低优先级的中断,反之,低优先级的中断请求不可以打断高优先级及同优先级的中断。
当两个相同优先级的中断同时产生时,将由查询次序来决定系统先响应哪个中断。STC89C52系列单片机的各个中断查询次序如下表所示:
以上也是中断服务函数,在初始化中断时也要配置相关的寄存器
注意:中断的资源和单片机的型号是关联在一 起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等。
配置中断的触发方式
三、定时器和中断系统
四、代码
timer0.c标准模板
#include <REGX52.H>
/**
* @brief 定时器0初始化,1毫秒@12MHz
* @param 无
* @retval 无
*/
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式,这里是为了不影响定时器1的配置
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //中断请求标志位 清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //定时器中断允许控制位
EA=1; //总中断允许控制位
PT0=0; //定时器中断优先级设置
}
/*定时器中断服务函数模板,这个中断服务函数一般是放在main.c中的
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
timer0.c解释模板
void Timer0_Init() //1毫秒@12.000MHz
{
// TMOD=0x01;//0000 0001 配置定时器的工作模式寄存器TMOD
//但是用这一行代码,影响配置定时器1,如果要用定时器1的话
TMOD=TMOD&0xF0;//把TMOD的低四位清零,高四位保持不变
TMOD=TMOD|0x01;//把TMOD的最低位置1,高四位保持不变
//用这两行代码,可以配置低四位,而不影响高四位
TH0=64535/256;//给定时器赋初值
TL0=64535%256;
TF0=0; //中断请求标志位 清除TF0标志
TR0=1; //定时器0开始计时
ET0=1; //定时器中断允许控制位
EA=1; //总中断允许控制位
PT0=0; //定时器中断优先级设置
}
/*定时器中断服务函数模板,这个中断服务函数一般是放在main.c中的
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;/*放在函数外边是全局变量,放在函数里是局部变量,
因为T0Count是需要计数到1000的,而定时器1ms到后去
执行中断函数,中断函数执行结束后T0Count会被销毁,
无法记录执行次数,因此放在函数体内要加静态变量static
这样T0Count会保留上次的值
*/
// TH0=64535/256;//初始化定时器从64535开始计数,溢出后计数从0开始,因此要重新赋值
// TL0=64535%256;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
P2_0=~P2_0;
T0Count=0;
}
}
用STC-ISP软件生成定时器代码:
删除AUXR,另外会自动生成TL和TH的值。
main.c
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE;
Timer0Init();//初始化定时器
while(1)
{
KeyNum=Key();
if(KeyNum)
{
if(KeyNum==1)
{
LEDMode++;
if(LEDMode>=2)LEDMode=0;
}
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;/*放在函数外边是全局变量,放在函数里是局部变量,
因为T0Count是需要计数到1000的,而定时器1ms到后去
执行中断函数,中断函数执行结束后T0Count会被销毁,
无法记录执行次数,因此放在函数体内要加静态变量static
这样T0Count会保留上次的值
*/
// TH0=64535/256;//初始化定时器从64535开始计数,溢出后计数从0开始,因此要重新赋值
// TL0=64535%256;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
if(LEDMode==0)
{
P2=_crol_(P2,1);
}
if(LEDMode==1)
{
P2=_cror_(P2,1);
}
}
}