STC89C52单片机外部中断与定时器中断寄存器配置分析
参考:STC89C52手册
摘自手册:
中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。当中央处理器CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级。CPU总是先响应优先级最高的中断请求。
当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。
STC89C52系列单片机提供了8个中断请求源,它们分别是:
外部中断0(INT0)
定时器0中断
外部中断1(INT1)
定时器1中断
串口(UART)中断
定时器2中断
外部中断2(INT2)
外部中断3(INT3)
所有的中断都具有4个中断优先级。用户可以用关总中断允许位(EA/IE.7)或
相应中断的允许位来屏蔽所有的中断请求,也可以用打开相应的中断允许位来使CPU响应相应的中断申请;每一个中断源可以用软件独立地控制为开中断或关中断状态:每一个中断的优先级别均可用软件设置。高优先级的中断请求可以打断低优先级的中断,反之,低优先级的中断请求不可以打断高优先级及同优先级的中断。当两个相同优先级的中断同时产生时,将由查询次序来决定系统先响应哪个中断。各个中断查询次序如下所示:
可以看到当两个相同优先级的中断同时发生时,由查询次序决定先响应谁,最高的是外部中断0,最低的是外部中断3。
通过设置新增加的特殊功能寄存器IPH中的相应位,可将中断优先级设为四级,如果只设置IP或XICON,那么中断优先级就只有两级,与传统8051单片机两级中断优先级完全兼容。
手册定时器0和定时器1的中断函数名打错了,应该是Routine,多了个n。
中断结构图如下
下面对外部中断进行简单分析:
外部中断0,1,2,3上面都有一条横线,这表示的是外部中断0,1,2,3即可以低电平触发也可以下降沿触发,外部中断请求标志IEx是在寄存器TCON和XICON寄存器中,其中外部中断0,1的中断请求标志和中断类型由TCON决定,外部中断2,3的中断请求标志和中断类型由XICON决定。
IEx(x=0,1,2,3)是各个外部中断的请求标志,置1了表示外部中断向CPU请求中断。ITx(x=0,1,2,3)是各个外部中断的中断源类型选择位,置0则表示低电平触发,置1则表示下降沿触发。
而外部中断2,3的中断请求标志位于辅助中断控制寄存器XICON中:
比如外部中断0的外部中断请求标志和中断源类型描述如下:
当然,只有这两个是还不够,因为还没允许外部中断啊!要想使用外部中断,那么就得允许外部中断吧。所以这就用到了另一个寄存器中断允许寄存器IE(该寄存器用来使能定时器、外部中断、串口的中断,留意一下)。
STC89C52系列单片机CPU对中断源的开放或屏蔽,每一个中断源是否被允许中断,是由内部的中断允许寄存器IE(地址为A8H)和XICON(地址为C0H)控制的。寄存器IE的格式如下:
红色框的就是外部中断0,1的中断允许位,黄色框的是定时器的溢出中断允许位,EA是中断的总开关这是必须打开的。这里先暂时分析的外部中断,所以先关注红色框的。
可以看到下面的描述,置1就是允许中断,置0就是禁止中断。这个寄存器只是用来配置外部中断0,1的,而外部中断2,3的配置是由辅助中断寄存器XICON来决定的。
PX是配置中断优先级的。
所以我们就知道了,使能外部中断只需要以下几个步骤:
1.配置外部中断触发类型ITx(0为低电平触发,1为下降沿触发);
2.IEx是中断请求标志,可以不用管它,为了不影响后续操作,将其置0即可;
3.将EXx置1允许外部中断;
4.将EA置1打开中断总开关;
5.需要配置优先级可以配置PXx;
如外部中断0的配置用代码表示就是:
void Int0_Init(void)
{
IT0=1; //外部中断0触发方式为下降沿触发
IE0=0; //外部中断0中断请求标志
EX0=1; //允许外部中断0
EA=1; //中断总开关
PX0=1; //外部中断0优先级
}
以下以定时器0的配置作为例子分析
定时器/计数器0和1的相关寄存器如下:
有了外部中断的认识那么配置定时器也就容易了,定时器分为了4种模式(各个模式的作用可参看手册更详细),所以使用定时器我们需要配置定时器模式。定时器用于定时那么就需要有一个定时初值,所以要使用定时器还需要配置定时器的计数初值并开启定时器。最后使用定时中断功能还需要开启定时器中断,并且还需要明白一点,各中断源首先受IE中断允许寄存器中的EA位控制,其次还受各中断源自己的中断允许控制位控制,所以还需要打开总中断和打开自身的中断允许位。
所以我们明白了配置定时器四部曲:配置定时器模式,配置定时初值,开启定时器,允许定时器中断并使能总中断。
定时器模式是由TMOD定时器/计数器工作模式寄存器来配置的,高4位配置定时器1,低4位配置定时器0。
定时器0的初值是由TL0和TH0决定的,这两个是8位的寄存器,假设使用模式1,即16位定时器/计数器,设置定时初值为64536,16进制表示就是0xFC18,所以TL0=18,TH0=FC,两个共同组成定时器初值。
定时器的开启是由TCON寄存器配置的,主要关注两个位:定时器开始计数标志TR0和溢出标志TF0。
TR0是运行控制位,置1就允许定时器0计数。TF0是溢出中断标志位,当计数溢出时会向CPU请求中断。
至此定时器的初始化就已经完成,只是还没允许定时器中断,所以需要配置IE中断允许寄存器中的ET0和EA位。
所以配置定时器四部曲:配置定时器模式,配置定时初值,开启定时器,允许定时器中断并使能总中断。变现成代码实现就是:
void Timer0Init(void) // 1毫秒@12.000MHz
{
TMOD &= 0xF0; // 设置定时器模式
TMOD |= 0x01; // 设置定时器模式
TL0 = 0x18; // 设置定时初值
TH0 = 0xFC; // 设置定时初值
TF0 = 0; // 清除定时器0溢出标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 定时器0溢出中断允许位
EA = 1; // 总中断允许位
PT0 = 1; // 定时器0中断优先级
}