学习51单片机中断与定时器工作原理
目录
中断系统的原理
1.51单片机中断原理
2.中断响应原理
3.中断优先级原理
4.中断标志位复位原理
中断系统的具体应用
1.一级中断的具体应用编程
2.二级中断具体应用编程
3.中断嵌套的具体应用编程
定时器/计数器的工作原理
定时器/计数器的具体应用
1.定时计数器控制LED灯
A.应用实例
B.Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察
2.计数器中断实例
中断程序优化方案
总结
中断系统的原理
1.51单片机中断原理
中断系统结构见下图。中断系统有5个中断请求源(简称中断源),2个中断优先级,可实现2级中断服务程序嵌套。每一中断源可用软件独立控制为允许中断或关闭中断状态;每一个中断源的优先级均可用软件设置。
由上图,中断系统共有5个中断请求源,它们是:
(1)INT0*—外部中断请求0,外部中断请求信号(低电平或负跳变有效)由INT0*引脚输入,中断请求标志为IE0。
(2)INT1*—外部中断请求1,外部中断请求信号(低电平或负跳变有效)由INT1*引脚输入,中断请求标志为IE1。
(3)定时器/计数器T0计数溢出的中断请求,标志为TF0。
(4)定时器/计数器T1计数溢出的中断请求,标志为TF1。
(5)串行口中断请求,标志为发送中断TI或接收中断RI。
2.中断响应原理
一个中断源中断请求被响应,须满足以下必要条件:
(1)总中断允许开关接通,即IE寄存器中的中断总允许位EA=1。
(2)该中断源发出中断请求,即该中断源对应的中断请求标志为“1”。
(3)该中断源的中断允许位=1,即该中断被允许。
(4)无同级或更高级中断正在被服务。 中断响应就是CPU对中断源提出的中断请求的接受,当查询到有效的中断请求时,满足上述条件时,紧接着就进行中断响应。
中断响应过程: 首先由硬件自动生成一条长调用指令“LCALL addr16”。即程序存储区中相应的中断入口地址。例如,对于外部中断1的响应,硬件自动生成的长调用指令为:
LCALL 0013H
生成LCALL指令后,紧接着就由CPU执行该指令。首先将程序计数器PC内容压入堆栈以保护断点,再将中断入口地址装入PC,使程序转向响应中断请求的中断入口地址。各中断源服务程序入口地址是固定的,见表6-2。
其中两个中断入口间只相隔8字节,一般情况下难以安放一个完整的中断服务程序。
3.中断优先级原理
中断请求源有两个中断优先级,每一个中断请求源可由软件设置为高优先级中断或低优先级中断,也可实现两级中断嵌套。
所谓两级中断嵌套,就是AT89S51正在执行低优先级中断的服务程序时,可被高优先级中断请求所中断,待高优先级中断处理完毕后,再返回低优先级中断服务程序。
两级中断嵌套见下图。
各中断源的中断优先级关系,可归纳为下面两条基本规则:
(1)低优先级可被高优先级中断,高优先级不能被低优先级中断。
(2)任何一种中断(不管是高级还是低级)一旦得到响应,不会再被它的同级中断源所中断。如果某一中断源被设置为高优先级中断,在执行该中断源的中断服务程序时,则不能被任何其他的中断源的中断请求所中断。
4.中断标志位复位原理
在微控制器系统中,中断标志位是用来指示特定类型的中断事件是否发生。
当中断源(如外部中断、定时器溢出、接收完成等)触发时,相应的中断标志位会被设置。
中断处理程序(Interrupt Service Routine, ISR)需要检查这些标志位以确定中断的来源,并执行相应的处理逻辑。处理完成后,很关键的一步是复位(清除)这些中断标志位,以便系统可以响应后续的同类型中断。这里的复位原理涉及几个方面:
自动复位:某些微控制器的中断标志位在中断响应后会自动被硬件清零。这意味着,当中断被CPU识别并开始执行对应的ISR时,中断标志位自动清除,无需手动编程清除。
手动复位:大多数情况下,中断标志位需要在ISR中手动清除。这通常通过写特定的值到相关的寄存器来实现。复位中断标志位的方法依赖于具体的微控制器及其寄存器结构。例如,对于许多微控制器来说,可能需要向中断标志位寄存器写入`1`来清除中断标志位(写`1`清零)。
为什么需要复位中断标志位?
如果不清除中断标志位,中断服务程序完成后,中断控制逻辑可能会再次判断中断仍然有效,并再次进入相同的中断处理程序,从而形成循环,不再返回到主程序执行,导致程序卡在中断处理中。因此,正确管理中断标志位是中断编程中非常关键的一部分。
中断系统的具体应用
1.一级中断的具体应用编程
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关K1。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。
c语言代码
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i)
{
unsigned int j;
for(;i>0;i--)
{
for(j=0;j<333;j++)
{;}
}
}
void main()
{
EA=1;
EX0=1;
IT0=1;
while(1)
{
P2=0;
}
}
void int0() interrupt 0 using 0
{
uchar m;
EX0=0;
for(m=0;m<5;m++)
{
P2=0x0f;
Delay(400);
P2=0xf0;
Delay(400);
EX0=1;
}
}
Proteus上完成的实验
普中单片机板上完成的实验
2.二级中断具体应用编程
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接有一只按钮开关K1。在外部中断1输入引脚(P3.3)接有一只按钮开关K2。要求K1和K2都未按下时,P1口的8只LED呈流水灯显示,仅K1(P3.2)按下再松开时,上下各4只LED交替闪烁10次,然后再回到流水灯显示。如果按下再松开K2(P3.3)时,P1口的8只LED全部闪烁10次,然后再回到流水灯显示。设置两个外中断的优先级相同。
c语言代码
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i)
{
uchar j;
for(;i>0;i--){
for(j=0;j<125;j++)
{;}
}
}
void main()
{
uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned int a;
for(;;)
{
EA=1;
EX0=1;
EX1=1;
IT0=1;
IT1=1;
IP=0;
for(a=0;a<9;a++)
{
Delay(500);
P2=display[a];
}
}
}
void int0_isr(void) interrupt 0 using 1
{
uchar n;
for(n=0;n<10;n++)
{
P2=0x0f;
Delay(500);
P2=0xf0;
Delay(500);
}
}
void int1_isr(void) interrupt 2 using 2
{
uchar m;
for(m=0;m<10;m++)
{
P2=0xff;
Delay(500);
P2=0;
Delay(500);
}
}
Proteus上完成的实验
K1和K2都未按下时
仅K1(P3.2)按下再松开时
按下再松开K2(P3.3)时
普中单片机板上完成的实验
K1和K2都未按下时
仅K1(P3.2)按下再松开时
按下再松开K2(P3.3)时
3.中断嵌套的具体应用编程
设计一中断嵌套程序:要求K1和K2都未按下时,P1口8只LED呈流水灯显示,当按一下K1时,产生一个低优先级外中断0请求(跳沿触发),进入外中断0中断服务程序,上下4只LED交替闪烁。此时按一下K2时,产生一个高优先级的外中断1请求(跳沿触发),进入外中断1中断服务程序,使8只LED全部闪烁。当显示5次后,再从外中断1返回继续执行外中断0中断服务程序,即P1口控制8只LED,上、下4只LED交替闪烁。设置外中断0为低优先级,外中断1为高优先级。
c语言代码
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i)
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main()
{
uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uchar a;
for(;;)
{
EA=1;
EX0=1;
EX1=1;
IT0=1;
IT1=1;
PX0=0;
PX1=1;
for(a=0;a<9;a++)
{
Delay(500);
P2=display[a];
}
}
}
void int0_isr(void) interrupt 0 using 0
{
for(;;)
{
P2=0x0f;
Delay(500);
P2=0xf0;
Delay(500);
}
}
void int1_isr(void) interrupt 2 using 1
{
uchar m;
for(m=0;m<5;m++)
{
P2=0;
Delay(500);
P2=0xff;
Delay(500);
}
}
Proteus上完成的实验
要求K1和K2都未按下时
当按一下K1时
当按一下K1时,产生一个低优先级外中断0请求(跳沿触发),进入外中断0中断服务程序,上下4只LED交替闪烁。此时按一下K2时:
普中单片机板上完成的实验
要求K1和K2都未按下时
当按一下K1时
当按一下K1时,产生一个低优先级外中断0请求(跳沿触发),进入外中断0中断服务程序,上下4只LED交替闪烁。此时按一下K2时:
定时器/计数器的工作原理
定时器/计数器是微控制器中非常重要的组件,广泛用于时间管理、事件计数、协议通信、PWM产生等。它们的工作原理可以根据其功能分为两大类:定时器模式和计数器模式。
定时器模式
在定时器模式下,定时器/计数器根据内部或外部时钟源(通常是微控制器的系统时钟)递增其计数值。当计数值达到预设值时,可以触发中断或其他事件,如改变输出引脚状态。
1. 初始化:首先设定定时器的基本参数,包括预分频值(决定计数速度)和初始计数值。
2. 启动:启动定时器,使其开始根据时钟源递增计数值。
3. 计数到达预设值:当计数值达到预设值时,根据配置,定时器可能会发生以下几种情况之一: – 产生中断,由CPU处理。 – 自动重装初值并继续计数,用于周期性任务。 – 改变某个输出引脚的电平状态,用于生成波形等。
4. 中断处理:如果定时器触发了中断,CPU会暂停当前任务,执行中断服务程序(ISR)。在ISR中,通常会清除定时器的中断标志位,以便定时器可以继续工作。
计数器模式
在计数器模式下,定时器/计数器不再依赖内部时钟源,而是通过外部事件(如外部引脚的电平变化)来递增计数值。这使得计数器可以用于计数外部事件的发生次数。
1. 初始化:设置计数器的工作模式和初始计数值。
2. 启动:启动计数器。
3. 外部事件计数:每当检测到预定义的外部事件(例如外部引脚上的上升沿或下降沿),计数器的计数值就会递增。
4. 计数到达预设值:与定时器模式相同,当计数值达到预设值时,可以配置计数器产生中断、重置计数值或进行其他操作。
共同特点 :
1.预分频:定时器/计数器通常具有预分频功能,允许调整计数速度,以适应不同的应用需求。
2.中断功能:定时器/计数器达到预设值时,常常可以配置为触发中断,允许CPU进行相应处理。
3.自动重载:许多定时器/计数器支持自动重载功能,当计数值达到预设值后,自动重置为初始值,从而实现周期性任务。
定时器/计数器是微控制器中功能强大且多用途的组件,通过精巧的配置和编程,可以实现各种复杂的功能。
定时器/计数器的具体应用
1.定时计数器控制LED灯
A.应用实例
在AT89S51的P1口上接有8只LED,原理电路如下。采用T0方式1的定时中断方式,使P1口外接的8只LED每1s闪亮一次。
(1)设置TMOD寄存器
T0工作在方式1,应使TMOD寄存器的M1、M0=01;应设置C/T*=0,为定时器模式;对T0的运行控制仅由TR0来控制,应使相应的GATE位为0。定时器T1不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x01。
(2)计算定时器T0的计数初值
设定时时间10ms(即10 000µs),设T0计数初值为X,假设晶振的频率为11.059 2MHz,则定时时间为:
定时时间=(216−X)×12/晶振频率 则 10 000=(65536 −X) ×12/11.059 2 得 X = 56320, 转换成十六进制:0xdc00,其中0xdc装入TH0,0x00装入TL0。
(3)设置IE寄存器
本例由于采用定时器T0中断,因此需将IE寄存器中的EA、ET0位置1。
(4)启动和停止定时器T0
将定时器控制寄存器TCON中的TR0=1,则启动定时器T0;TR0=0,则停止定时器T0定时。
c语言代码
#include <reg51.h>
char i=100;
void main()
{
TMOD=0x01;
TH0=0xdc;
TL0=0x00;
P2=0x00;
EA=1;
ET0=1;
TR0=1;
while(1);
{;}
}
void timer0() interrupt 1
{
TH0=0xdc;
TL0=0x00;
i--;
if(i<=0)
{
P2=~P2;
i=100;
}
}
在Proteus上
在普中单片机板上
B.Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察
Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察,测量真实的周期数,并与采用软件循环进行周期定时的精度进行对比,看哪一种方式更加精准。
定时器循环
软件循环
如图软件定时一个周期内约为0.924755
秒,而采用定时器定时一周期内约为0.93338
秒。
因此定时器定时较软件定时更为精确。
2.计数器中断实例
T1采用计数模式,方式1中断,计数输入引脚T1(P3.5)上外接按钮开关,作为计数信号输入。按4次按钮开关后,P1口的8只LED闪烁不停。如图:
(1)设置TMOD寄存器
T1工作在方式1,应使TMOD的M1、M0=01;设置C/T*=1,为计数器模式;对T0运行控制仅由TR0来控制,应使GATE0=0。定时器T0不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x50。
(2)计算定时器T1的计数初值 由于每按1次按钮开关,计数1次,按4次后,P1口的8只LED闪烁不停。因此计数器初值为65 536−4=65 532,将其转换成十六进制后为0xfffc,所以,TH0=0xff,TL0=0xfc。
(3)设置IE寄存器 本例由于采用T1中断,因此需将IE寄存器的EA、ET1位置1。
(4)启动和停止定时器T1将寄存器TCON中TR1=1,则启动T1计数;TR1=0,则停止T1计数。
c程序
#include <reg51.h>
void Delay(unsigned int i)
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main()
{
TMOD=0x50;
TH1=0xff;
TL1=0xfc;
EA=1;
ET1=1;
TR1=1;
while(1);
}
void T1_int(void) interrupt 3
{
for(;;)
{
P2=0xff;
Delay(500);
P2=0;
Delay(500);
}
}
在Proteus上
在普中单片机板上
中断程序优化方案
为了实现按4次按钮后使P1口的8只LED不停闪烁,可以采用计数器中断结合按键检测的方法。下面是一个简化的示例代码,展示了如何在C语言中实现这个功能。
#include <reg51.h> // 适用于8051,根据实际微控制器调整
volatile unsigned int buttonPressCount = 0; // 按钮按下计数器,用volatile修饰,因为它会在中断服务例程中被修改
// 假设使用外部中断0来检测按键按下
void ExternalInterrupt0_ISR(void) interrupt 0 {
buttonPressCount++; // 按键按下计数
if(buttonPressCount >= 4) {
// 达到4次按键后的处理逻辑
// 这里仅改变状态或设置标志位,具体闪烁逻辑在main函数中实现
}
}
void main() {
IE = 0x81; // 开启外部中断0和全局中断
IT0 = 1; // 设置为边缘触发模式
while(1) {
if(buttonPressCount >= 4) {
P1 = ~P1; // 切换P1口状态,实现LED闪烁
// 延时函数,根据需要调整延时时长来控制闪烁速度
// 注意,实际使用中应避免使用过长的延时,或者改用计时器中断实现非阻塞延时
}
}
}
重要注意事项
中断向量号和寄存器:上述代码示例采用了8051系列微控制器的外部中断0(interrupt 0
)和相关寄存器(如IE
和IT0
)作为示例。具体的中断向量号、寄存器和设置方法取决于你使用的具体微控制器型号,因此在实际应用中需要参考相应的微控制器手册。
去抖动:实际应用中,按键输入需要去抖动处理以避免误操作。去抖动通常通过软件实现,即在检测到按键动作后,延时一小段时间再确认按键状态。
延时处理:示例中的延时处理非常简化。在实际应用中,考虑使用计时器中断而非阻塞式延时来实现LED的闪烁,这样可以避免阻塞程序其他部分的执行。
这个示例提供了一种实现思路。具体实现细节,如IO口的配置、中断优先级的设置等,需要根据实际使用的微控制器和开发环境进行调整。
总结
通过此次学习51单片机中断系统和定时/计数器的相关内容,掌握了中断系统的原理和使用方法,了解了如何利用中断来实现对外部事件的实时响应,还学习了定时/计数器的工作原理和编程方法,掌握了如何利用定时器来实现时间精确控制,提高了系统的时间管理能力。
了解了中断和定时/计数器的工作机制,学会了合理设置中断优先级和定时器的工作参数,从而能够有效地节省系统资源,提高系统的性能和效率。
通过实际的应用案例,如按键中断、定时器控制LED闪烁等,将理论知识与实际操作相结合,加深了对中断系统和定时/计数器的理解和掌握。
作者:abcdxymsj