目录
一、中断概念
1、中断类型和中断号
2、中断允许寄存器IE
3、中断优先级寄存器IP
二、定时器中断
1、定时器中断概念
(1)定时器系统组成
(2)定时器工作方式
(3)TMOD和TCON值设置
(4)定时器初始重装值设定
(5)总结一下
2、实验任务一
(1)任务
(2)代码实现
(3)实验结果
3、实验任务二
(1)任务
(2)代码实现
(3)实验结果
测试程序下载链接
中断就是当CPU执行程序时,由于发生了某种随机的事件(外部或内部),引起CPU暂时中断正在运行的程序,转去执行一段特殊的服务程序(中断服务子程序或者中断处理程序),以处理该事件,该事件处理完后又返回被中断的程序继续执行,这一过程就称为中断,引发中断的称为中断源。有些中断还能够被其它高级优先级的中断所中断,这种情况叫做中断的嵌套。
中断示意图
51单片机有三种中断类型:外部中断、定时器中断、串行中断,一共有6个中断源:
INT0 - 外部中断0,由P3.2端口引入,低电平或下降沿引起。
INT1 - 外部中断1,由P3.3端口引入,低电平或下降沿引起。
T0 - 定时器/计数器 0中断,由T0计数器计满回零引起。
T1 - 定时器/计数器 1中断,由T1计数器计满回零引起。
T2 - 定时器/计数器 2中断,由T2计数器计满回零引起。(51单片机没有T2)
TI/RI - 串行口中断,串行端口完成一帧字符发送/接收后引起。
52中断级别如下图所示
(每个中断函数的中断号必须和序号 一 一对应)
52单片机中断级别
单片机在使用中断功能时,通常需要设置两个和中断有关的寄存器:中断允许寄存器IE和中断优先级寄存器IP。
中断允许寄存器用来设定各个中断源的打开和关闭,IE在特殊的功能寄存器中,字节地址为A8H,位地址(由低位到高位)分别是A8H-AFH,该寄存器可进行位寻址,即可对该寄存器的每一位进行单独操作。单片机复位时IE全部被清0,各位定义如表所示:
中断允许寄存器IE
EA - 全局中断允许位
EA=1,打开全局中断控制,在此条件下由各个中断控制位确定相应中断的打开或关闭。
EA=0,关闭全部中断
ES - 串行口中断允许位
ES=1,打开串行口中断
ES=0,关闭串行口中断
ET0 - 定时器/计数器0中断允许位
ET0=1,打开T0中断
ET0=0,关闭T0中断
ET1 - 定时器/计数器1中断允许位
ET1=1,打开T1中断
ET1=0,关闭T1中断
ET2 - 定时器/计数器2中断允许位
ET2=1,打开T2中断
ET2=0,关闭T2中断
EX0 - 外部中断0中断允许位
EX0=1,打开外部中断0中断
EX0=0,关闭外部中断0中断
EX1 - 外部中断1中断允许位
EX1=1,打开外部中断1中断
EX1=0,关闭外部中断1中断
中断优先级寄存器在特殊功能寄存器中,字节地址位B8H,位地址(由低位到高位)分别是B8H-BFH,IP用来设定各个中断源属于两级中断中的哪一级。该寄存器可进行位寻址,即可对该寄存器的每一位进行单独操作。单片机复位时IP全部被清0,各位定义见下表
中断优先级寄存器IP
PS - 串行口中断优先级控制位
PS = 1,串行口中断定义为高优先级中断。
PS = 0,串行口中断定义为低优先级中断。
PT0 - 定时器/计数器 0中断优先级控制位
PT0 = 1,定时器/计数器 0中断定义为高优先级中断。
PT0 = 0,定时器/计数器 0中断定义为低优先级中断。
PT1 - 定时器/计数器 1中断优先级控制位
PT1 = 1,定时器/计数器 1中断定义为高优先级中断。
PT1 = 0,定时器/计数器 1中断定义为低优先级中断。
PX0 - 外部中断0 中断优先级控制位
PX0 = 1 ,外部中断0 定义为高优先级中断。
PX0 = 0 ,外部中断0 定义为低优先级中断。
PX1 - 外部中断1 中断优先级控制位
PX1 = 1 ,外部中断1 定义为高优先级中断。
PX1 = 0 ,外部中断1 定义为低优先级中断。
在51单片机系列中,高优先级中断能够打断低优先级中断以形成嵌套中断。同优先级中断之间,或低级对高级中断则不能形成中断嵌套。若几个统计中断同时向CPU请求中断响应,在没有设置中断优先级的情况下,按照默认中断级别响应中断。在设置中断优先级后,则按设置顺序确定响应的先后顺序。
51单片机内部共有两个16位的可编程定时器/计数器,即定时器T0和定时器T1,52单片机内部多一个T2定时器/计数器。它们既有定时器功能、又有计数功能,通过设置与它们相关的特殊功能寄存器可以选择启用定时器功能或计数功能。定时器系统是单片机内部一个独立的硬件部分,它与CPU和晶振通过内部某些控制线连接并相互作用,CPU一旦设置开启定时功能后,定时器便再晶振的作用下启动开始计时,当定时器的计数器计满后会产生中断事件。
定时器/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器组成。TMOD是定时器/计数器的工作方式寄存器,确定工作方式和功能。TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。
51单片机定时器/计数器结构框图
加1计数器输入的计数脉冲有两个来源,一个是由系统的时钟振荡器输出脉冲经12分频后送来,另一个是T0或者T1引脚输入的外部脉冲源.每一个脉冲计数器加1,当加到计数器为全1时再输入一个脉冲就使计数器回零且计数器的溢出使TCON寄存器中TF0或TF1置1,向CPU发出中断请求(定时器中断允许时)。如果定时器/计数器工作于定时模式则表示定时时间已到;如果工作于计数模式,则表示计数值已满。
由此可见,由溢出时计数器的值减去计数初始值才是加1计数器的计数值。
(①定时器模式
设置为定时器模式时,加1计数器是对内部机器周期计数(1个机器周期等于12个振荡周期,既计数频率为晶振频率的1/12)。计数值N乘以机器周期 Tcy 就是定时时间 t 。
②计数模式
设置为计数器模式时,外部事件计数脉冲由T0或T1引脚输入到集水区。在每个机器周期的S5P2期间采样T0 、T1引脚电平。当某周期采样到一高电平输入而下一周期又采样到低电平时,则计数器加1。更新的计数值在下一个机器周期的S3P1期间装入计数器。由于,检验一个从1-0的下降沿需要2个机器周期,因此要求被采样的电平至少要维持一个机器周期。当晶振频率为12MHz时,最高计数频率不超过1/2MHz,既计数脉冲的周期要大于2us。
单片机在使用定时器或计数器功能时,通常需要设置两个与定时器有关的寄存器:定时器/计数器工作方式寄存器TMOD和定时器/计数器控制寄存器TCON。
①定时器/计数器工作方式寄存器TMOD
定时器/计数器工作方式寄存器,在特殊功能寄存器中,字节地址为89H,不能位寻址。TMOD用来确定定时器的工作方式及功能选择,单片机复位时TMOD全部被清0。其各位的定义如表所示
工作方式寄存器TMOD
TMOD的高4位用于设置定时器1,低四位用于设置定时器0。其对应的4位的含义如下:
GATE - 门控制位
GATE = 0,定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制。
GATE = 1,定时器/计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0或INT1)上的电平状态来共同控制。
C/T - 定时器模式和计数器模式选择位
C/T = 1,计数器模式
C/T = 0,定时器模式
M1M0 - 工作方式选择位
每个定时器/计数器都有4种工作方式,它们由M1M0设定,对应关系如下所示
定时器/计数器的4种工作方式
②定时器/计数器控制寄存器TCON
定时器/计数器控制寄存器在特殊功能寄存器中,字节地址为88H,位地址(由低位到高位)分别是88H-8FH,该寄存器可进行位寻址。TCON寄存器用来控制定时器的启、停,标志定时器溢出和中断情况。单片机复位时TCON全部被清0,其各位定义如下表格所示。其中,TF1、TR1、TF0、和TR0用于位定时器/计数器;IE1、IT1、IE0和IT0位用于外部中断,在这里一起介绍
定时器/计数器控制寄存器TCON
TF1 - 定时器1溢出标志位
当定时器1计满溢出时,由硬件使TF1置1,并且申请中断。进入中断服务程序后,由硬件自动清0。需要注意的是,如果使用定时器中断,那么该位完全不用人为去操作,但是如果使用软件查询方式的话,当查询到该位置1后,就需要用软件清0。
TR1 - 定时器1运行标志位
由软件清0关闭定时器1.当GATE=1,且INT1为高电平时,TR1置1启动定时器1;当GATE=0时,TR1置1启动定时器1。
TF0 - 定时器0溢出标志位,其功能及操作方法同TF1
TR0 - 定时器0运行控制位,其功能及操作方法同TR1
IE1 - 外部中断1请求标志
当IT1=0时,为外部电平触发方式,每个机器周期的S5P2采样INT1引脚,若INT1脚为低电平,则置1,否则IE1清0。
当IT1=1时,INT1为跳变沿触发方式,当第一个机器周期采样到INT1为低电平时,则IE1置1.IE=1,表示外部中断1正在向CPU申请中断。当CPU响应中断,转向中断服务程序时,该位由硬件清0。
IT1 - 外部中断1触发方式选择位
IE0 - 外部中断0请求标志,其功能及操作方法同IE1
IT0 - 外部中断0触发方式选择位,其功能及操作方法同IT1
以定时器0工作方式1的工作逻辑个定时器初值设置举例说明
①工作逻辑
从上面的讲解可以知道,每个定时器都有4种工作方式,可以通过设置TMOD寄存器中的M1M0位来进行工作方式选择,本届只讲解了其中一个定时器的一种工作方式——定时器0的工作方式1,16位定时器。方式1的计数位数是16位,对T0来说由TL0寄存器作为低8位、TH0寄存器作为高8位,组成了16位加1计数器,其逻辑结构框图如下所示
定时器0方式1逻辑结构框图
分析上面的逻辑图,当GATE=0,TR0=1时,TL0便在机器周期的作用下开始加1计数,当TL0计满后向TH0进一位,直到把TH0也计满,此时计数器溢出,置TF0为1,接着向CPU申请中断,接下来CPU进行中断处理。在这种情况下只要TR0为1,那么计数就不会停止,这就是定时器0的工作方式1工作过程。其它的8位定时器、13位定时器的工作方式也都是大同小异。
②初值设置
定时器一旦启动,它便在原来的数值上开始加1计数,若在程序开始时我们没有设置TH0、TL0,它们的默认设置值都是0。假设时钟频率为12MHz,12个时钟周期为一个机器周期,那么机器周期就是1us,计满TH0和TL0就需要2^16 - 1个数,再来一个脉冲计数器溢出,随机向COU申请中断。因此溢出一次共需要65526us,约等于65.5ms。如果要定时50ms的话,那么就需要先给TH0和TL0装一个初值,在这个初值的基础上计满50000个数后定时器溢出,此时刚好就是50ms中断一次。如果需要定时器1s,程序中经过20次50ms的定时中断便认为是1s。这样就可以精确控制定时时间了。
要计50000个数时,TH0和TL0中应该装入的总数是65536-50000=15536,把15536对256取模:15536/256=60装入TH0中,把15536对256取余:15536%256=176装入TL0中,这就是定时器初值的计数方法
1、重装值
当用定时器的方式1时,设机器周期为Tcy,定时器产生一次中断的时间为t,那么需要计数的个数N=t/Tcy,装入THx和TLx中的数分别为
THx=(65536-N)/256;
TLx=(65536-N)%256。
机器周期为Tcy计算方法是,根据系统时钟频率也急速单片机的晶振频率。
若晶振是12MHz,那么机器周期就是12*(1/12000000)=1us,那么t=50ms,N=50ms/1us,就是50000。
若晶振是11.0592MHz,那么机器周期就是12*(1/11059200)约等于1.09us,那么t=50ms,N=50ms/1.09us,就是45872。
2、使用定时器中断对应寄存器初始化过程
①对TMOD赋值,以确定T0和T1的工作方式。
②计算初值,并将初值写入TH0、TL0或者TH1、TL1。
③设定中断方式时,则对IE进行赋值,开放中断,既EA=1。
④开启定时器中断,既ET0=1或者ET1=1。
⑤启动定时器计时,既TR0=1或者TR1=1
3、中断中的寄存器赋值问题
①如果该寄存器D0-D7每一个位都有对应的对应的位符号,如中断允许IE寄存器,每一位的对应符号如下。
那么,如果要启用定时器0,则对应设置的寄存器值方式如下
EA=1; 开启全局中断
ET0=1; 开启定时器中断
IE、IP、TOCN等都是一样的。
②而TMOD寄存器的D0-D7则没有对应的位符号,则需要给TMOD写入具体的数值即可。
比如
TMOD=0X01:0000 0001 定时器0工作方式1
TMOD=0X11:0001 0001 定时器1工作方式1、定时器0工作方式1
4、中断函数名说明
举例1:
void T0_time() interrupt 1
{
//
}
void:固定格式
T0_time:中断函数名,只要不和C语言关键词重名可以随便写
():固定格式,括号中不能写参数
interrupt:固定格式
1:定时器0的中断号,每一个中断号是唯一的,前面概述中讲解过,下图表格在展示一下
举例2:
void T1_time() interrupt 3
{
//
}
3:定时器1的中断号(中断号是唯一的),如下图表格所示
要求:利用定时器0工作方式1,在开发板上实现一个LED灯以0.5的时间进行闪烁。
#include
#include
#define uint unsigned int
#define uchar unsigned char
sbit P1_0=P1^0;
uchar num;
void Delay_ms(uint xms) //延时函数
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void Main()
{
TMOD=0X01; //设置定时器0工作方式1
TH0=(65536-50000)/256; //重装值,12MHz定时50ms的数值为50000
TL0=(65536-50000)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
while(1); //程序运行到这里等待中断的发生
}
void T0_time() interrupt 1 //定时器0中断函数 -> 数字1表示定时器0的中断号(中断号是唯一的)
{
TH0=(65536-50000)/256; //重装值,12MHz定时50ms的数值为50000
TL0=(65536-50000)%256;
num++; //50ms自加一次
if(num==10) //累加10次,既500ms
{
P1_0=~P1_0; //led灯输出取反,即亮灭转换
num=0;
}
}
中断函数中的程序应当尽量的简化,否则可能因为逻辑程序执行时间太长导致部分程序无法执行,因此修改后的程序:
/*******************0.5秒闪烁灯—定时器0工作方式1实现—*****************************
#include
#include
#define uint unsigned int
#define uchar unsigned char
sbit P1_0=P1^0;
uchar num;
void Delay_ms(uint xms) //延时函数
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void Main()
{
TMOD=0X01; //设置定时器0工作方式1
TH0=(65536-50000)/256; //重装值,12MHz定时50ms的数值为50000
TL0=(65536-50000)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
while(1) //程序运行到这里等待中断的发生
{
if(num==10) //累加10次,既500ms
{
P1_0=~P1_0; //led灯输出取反,即亮灭转换
num=0;
}
}
}
void T0_time() interrupt 1 //定时器0中断函数 -> 数字1表示定时器0的中断号(中断号是唯一的)
{
TH0=(65536-50000)/256; //重装值,12MHz定时50ms的数值为50000
TL0=(65536-50000)%256;
num++; //50ms自加一次
}
略
要求:
①用定时器0的工作方式1,在开发板上实现一个LED灯以200ms闪烁
②用定时器1的工作方式1,在开发板上实现数码管前两位以0-59秒循环计时。
/*******************200毫秒闪烁灯—0到59秒计时—*****************************
#include
#include
#define uint unsigned int
#define uchar unsigned char
sbit P1_0=P1^0; //LED灯
sbit beep=P2^3; //蜂鸣器
sbit dula=P2^6; //段选锁存器-使能控制
sbit wela=P2^7; //位选锁存器-使能控制
uchar num1,num2;
uchar num,shi,ge;
uchar code table[]=
{
//0-9 A-F,共阴极数码管显示编码
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
void Delay_ms(uint xms) //延时函数--不精确
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void Display_SMG(uchar Shi,uchar Ge)
{
//第一个数码管显示
//段码显示
dula=1;
P0=table[Shi];
dula=0;
P0=0xFF; //消影功能-将所有数码管段都置高电平,都熄灭,就不会有亮点带到下一位数码管上了
//位码显示
wela=1;
P0=0xfe;
wela=0;
Delay_ms(2);
//第二个数码管显示
//段码显示
dula=1;
P0=table[Ge];
dula=0;
P0=0xFF;
//位码显示
wela=1;
P0=0xfd; //1111 1101
wela=0;
Delay_ms(2);
}
void Main()
{
TMOD=0X11; //设置定时器0工作方式1、定时器1工作方式1,0001 0001->对应TMOD D7-D0寄存器值
TH0=(65536-50000)/256; //定时器T0的重装值,12MHz定时50ms的数值为50000
TL0=(65536-50000)%256;
TH1=(65536-50000)/256; //定时器T1的重装值,12MHz定时50ms的数值为50000
TL1=(65536-50000)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
ET1=1; //开定时器1中断
TR0=1; //启动定时器0
TR1=1; //启动定时器1
while(1) //程序运行到这里等待中断的发生
{
if(num1==4) //累加10次,既500ms
{
P1_0=~P1_0; //led灯输出取反,即亮灭转换
//beep=~beep;
num1=0;
}
if(num2==20)
{
num2=0;
num++;
if(num==60)
{
num=0;
}
shi=num/10; //取模
ge=num%10; //取余
}
Display_SMG(shi,ge); //数码管显示计时数字
}
}
void T0_time() interrupt 1 //定时器0中断函数 -> 数字1表示定时器0的中断号(中断号是唯一的)
{
TH0=(65536-50000)/256; //重装值,12MHz定时50ms的数值为50000
TL0=(65536-50000)%256;
num1++; //50ms自加一次
}
void T1_time() interrupt 3 //定时器1中断函数 -> 数字3表示定时器1的中断号(中断号是唯一的)
{
TH1=(65536-50000)/256; //重装值,12MHz定时50ms的数值为50000
TL1=(65536-50000)%256;
num2++; //50ms自加一次
}
https://download.csdn.net/download/panjinliang066333/86675480