1、中断的概念
对于单片机中断的概念,我们可以这样理解:单片机处理某一事件A时,发生了另一事件B请求(中断请求);单片机暂时中断当前工作,转去处理事件B(中断响应和中断服务);待单片机将事件B处理完毕,再回到原来事件A被中断的地方继续处理事件A(中断返回),这一过程称为中断。 引起单片机中断的根源或原因: 中断源向单片机提出中断请求。
2、中断优先级 单片机的中断系统一般允许多个中断源,当几个中断源同时向单片机请求中断,要求为它服务的时候,这就存在单片机优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。单片机总是先响应优先级别最高的中断请求。 中断优先级的三条原则: a:单片机同时接收到几个中断时,响应优先级别最高的中断请求。 b:正在进行的中断过程不能被新同级或低优先级的中断请求所中断。 c:正在进行的低优先级中断服务,能被高优先级中断请求所中断。
3、中断嵌套
当单片机正在处理一个中断请求源的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。单片机暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。 4、单片机内部中断电路和寄存器
我们以STC单片机为例进行介绍: 上图是单片机内部和中断有关的电路,从图中我们知道单片机可以有5个中断源,分别是/INT0,T0,/INT1,T1,RX和TX。/INT0和/INT1为外部中断源;T0和T1为定时器/计数器中断;RX和TX为串口收发中断。 相关寄存器有TCON,IE,IP,这些寄存器又是起什么作用的呢: TF1是定时器1的溢出标志位,当定时器1发生溢出时,此位变成1,同时提出中断请求,一直保持到CPU响应中断时,才由硬件清0。如果程序不是采用中断的方式,而是采用查询的方式,那么这位需要软件清0。 TR1是定时器1的运行控制位,当它为1时允许定时器1开始计数,为0时禁止定时器1计数。 TF0和TR0的功能分别与TF1和TR1类似,它们对应的是定时器0。 对于IE1,IT1,IEO,IT0的功能在上图中有描述了,就不多说了。

IE寄存器是中断允许寄存器,只有相应的位置为1了,相关的中断才能被允许哦。 IP寄存器是中断优先级控制寄存器,当某位被设成1了,那么对应的中断源就是高优先级了哦,就可以中断低优先级中断源的处理函数了哦。
好了,今天给大家介绍了单片机内部中断电路和相关的寄存器,明天给结合程序给大家讲述如何实现单片机中断功能。
上一条分享我们提到单片机一般有5个中断源,在这条分享中我们看看如何通过编程实现这些中断功能。
1、外部中断
外部中断源有:INT0和INT1,可由外部信号引发单片机的中断,我们需要将信号引到单片机的INT0和INT1管脚上。外部中断INTO和INT1即可底电平触发,也可下降沿触发。相关的寄存器有TCON,IE,IP。
下面我们通过一段例程序理解下,怎样编写代码:
#include “reg51.h”
void init_int0(void) //中断功能的初始化函数,只有对相关的寄存器进行了正确的
配置,采用运用单片机的中断功能哦。
{
IT0=1; //IT0是寄存器TCON的最低位,在这里设成1,单片机管脚INT0上的信号低跳变(下降沿)引发中断。
EX0=1; //EX0是寄存器IE的最低位,在这里设成1,允许发生INT0中断。
EA=1; //EA是寄存器IE的最高位,在这里设成1,相当于开启了允许中断的总开关。只有EA和EX0都设成1了, 才开启了INTO中断功能哦。
}
void main(void)
{
init_int0(); //需要在主函数中,对INT0的相关寄存器进行初始化配置的。
while(1);
}
Void exint0() interrupt 0 //中断函数,把我们希望实现的功能加进入,这里面的代码应该尽量简洁,短 小,以免占用太多的时间哦。
{
加上你希望实现的功能。
}
在看懂上面这段代码的基础上大家在想想如果希望是低电平引发中断,程序该怎么写呢?
外部中断INT1的初始化函数和中断处理函数该怎么写呢?
2、定时中断
与定时器/计数器T0,定时器/计数器T1中断相关的寄存器主要有TMOD,THX,TLX,TCON,IE。下面我们通过一段例程看看怎样实现定时器/计数器的中断功能(以定时器/计数器0为例)。
#include “reg51.h”
void timer0_init(void)//定时器0中断初始化函数
{
TMOD=0x80; //将定时器/计数器0当成13位定时器/计数器,TL0只用低5位参与分频,TH0整个8位全用。
TH0=0xXX; //设定定时器0初始计数值的高8位
TL0=0xXX; //设定定时器0初始计数值的低8位
TR0=1; //定时器0开始计数
ET0=1; //开定时器0中断允许
EA= 1; //开总中断允许
}
void main(void)
{
timer0_init();
while(1);
}
void timer0int interrupt 1
{
TH0=0xXX; //在中断处理函数里面记得给TH0重新赋初值哦
TL0=0xXX; //在中断处理函数里面记得给TL0重新赋初值哦
加上你希望实现的功能哦。
}
这样在单片机工作频率固定的前提下,我们可以通过调节TH0和TL0的初值来改变定时0的定时时长,从而改变定时中断发生的时间间隔。这样就以我们希望的时间间隔执行中断处理函数中的指令。
定时器1的中断的初始化和定时器0的中断初始化类似。
需要指出的是定时器0和定时器1有4中不同的工作方式,不同的工作方式的选择可以通过设置寄存器TMOD来实现。
3、串口收发中断
#include
//FOSC = 11.0592MHz,12T模式,SMOD=0
#define reload_count_1200bps 0xe8
#define reload_count_2400bps 0xf4
#define reload_count_4800bps 0xfa
#define reload_count_9600bps 0xfd
void serial_port_initial(char TH,char TL)
{
SCON=SCON|0x50; //确定串口工作方式,8位可变波特率,无奇偶校验位
TMOD=TMOD|0x20; //设置定时器1为8位自动重装记数器
PCON=PCON|0x00; //这个寄存器里有一位SMOD,它和波特率的确定有关。
TH1 = TH; //设置定时器1自动重装数TH1,它和波特率的确定有关。
TL1 = TL; //设置定时器1自动重装数TL1,它和波特率的确定有关。
ES=1; //允许串口中断
EA=1; //开总中断
TR1=1; //开定时器1
}
波特率=(2SMOD/32)x(定时器1的溢出率) 定时器1的溢出率 = SYSclk/12(256-TH1)
char UARTReceive(void) //串口数据接收函数
{
char ch;
ch=SBUF;
return (ch); // 暂存接收到的数据
}
void main(void)
{
serial_port_initial(reload_count_2400bps,reload_count_2400bps);
//初始化串口参数
while(1);
}
void UART_Interrupr_Receive(void) interrupt 4 //串口接收中断处理函数
{
ES = 0;
RI = 0; //当串口接收到数据时,RI回被置1,同时引发中断,在中断处理函数中将其清零。
buf = UARTReceive();
ES = 1;
}
好了,今天简单地和大家分享了一下单片机中断的一些基本知识,在这里只是简单地具了几个例,中断的用法很有技巧,这需要大家在项目的实践中去掌握,吃透。
|