定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 定时器作用: (1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作 (2)替代长时间的Delay,提高CPU的运行效率和处理速度(Delay是占用cpu时间的)
定时器
一、STC89C52定时器资源
-
定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源。
-
注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的。
定时器框图
-
定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”(时间段),计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行
暂时无法在飞书文档外展示此内容
二、定时器工作模式
-
STC89C52的T0和T1均有四种工作模式: 模式0:13位定时器/计数器 模式1:16位定时器/计数器(常用) 模式2:8位自动重装模式 模式3:两个8位计数器
-
工作模式1框图:
-
在这个模式一这个图形中我们可以将时钟、计数单元、中断系统划分出来:
工作原理:时钟系统每隔一段时间会向计数系统发送一段脉冲,当计数系统接受到脉冲时,计数(TL0和TH0)会加一,计数系统最大能显示2^16(65,535),如果超过了这个数字,计数器中的值就会变0(溢出),然后标志位TF0会加一,当有TF0不为零时,就会向中断系统申请中断
-
TL0:Time low 0:计数器低8位,0代表这是定时器0
-
TH0:Time hight :计数器高8位,0代表这是定时器0
-
TF0:Time flag :标志位,0代表这是定时器0
计数系统分为计数和控制,控制时钟是怎么过来的,包括一些定时器的启动和暂停,TR0就是用于控制定时器是启动还是暂停的。
-
SYSclk(system clock):系统时钟,即晶振周期,本开发板上的晶振为12MHz(表示每秒发生12 000 000次周期变化)(M:为百万级倍数)
51单片机的时钟信号来源有两种方式,一种是通过SYSclk来提供,一种是通过T0 Pin,T0 Pin为外部引脚,当使用外部引脚提供时钟脉冲时,定时器也相当于计数器。
如果选择配置为12T(MCU in 12T mode)模式的分频12/12,这时输出的频率为1MHZ,一个周期为1us,(1s = 1000ms,1ms = 1us)
公式:(2^16– X)× 12 ÷ 晶振频率 = 定时时间(默认单位us)
X = 2^16 - 定时时间(us) * 晶振频率 / 12
—————————————————————————————————
定时器计数初值为 X,X是未知量
—————————————————————————————————
216是根据方式选择的,可以自行选择,方式1为16位
方式0 :213 (少用)
方式1 :216 (最常用)
方式2 :28 (常用)
————————————————
x = 2^16-1000*12/12 = 64536
该寄存器如果给1,则代表着C这个功能(count:计数),给0就是Time。如果给1开关则连接下面(T0 Pin),如果给0开关则连接上面(SYSclk)
中断系统
-
中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的.
-
当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多人中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。
-
当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。
一、中断程序流程
二、STC89C52中断资源
-
中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3)
-
中断优先级个数:4个
-
中断号:
-
注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等
三、定时器和中断系统
这条红线就相当于第一种定时器的整个流程。
四、定时器相关寄存器
寄存器是连接软硬件的媒介
在单片机中寄存器就是一段特殊的RAM存储器,一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式
寄存器相当于一个复杂机器的“操作按钮”
TCON :time control
TF:time flag
TR:time run
按键控制LED流水灯模式
#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) //如果K1按键按下
{
LEDMode++; //模式切换
if(LEDMode>=2)LEDMode=0;
}
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++; //T0Count计次,对中断频率进行分频
if(T0Count>=500) //分频500次,500ms
{
T0Count=0;
if(LEDMode==0) //模式判断
P2=_crol_(P2,1); //LED输出
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
-
GATE:结合电路图可知,当GATE置0时通过非门(取反),他的值就会变成1,GATE连接着非门和INT0连接着或门(有1为1),但是当GATE给0时,无论INT0给什么最终的结果都是1,这一部分和TR0连接着与门(有0为0),所以此时计时器的开关由TR0决定。当GATE置1时,此时计时器的开关则由TR0和INT0决定
-
C/T:该寄存器如果给1,则代表着C这个功能(count:计数),给0就是Time。如果给1开关则连接下面(T0 Pin:计数器功能),如果给0开关则连接上面(SYSclk:定时器,内部时钟)
-
M1、M0(定时器/计数器0模式选择):
0 0 13位定时器/计数器,兼容8048定时模式,TL1只用低5位参与分频,TL1整个8位全用。
0 1 16位定时器/计数器,TL1、TH1全用。
1 0 8位自动重装裁定时器,当溢出时将TH1存放的值自动重装入TL1。
1 1 定时器/计数器1此时无效(停止计数)。
由于使用T0定时器,所以TMOD寄存器的值为0x0001;
TCON为定时器/计数器T0、T1的控制寄存器,同时也锁存T0、T1溢出中断源和外部请求中断源等,TCON格式如下
-
TF(time flag):定时器/计数器T1溢出标志。T1被允许计数以后,从初值开始加1计数。当最高位产生溢 出时由硬件置“1”TF1,向CPU请求中断,一直保持到CPU响应中断时,才由硬件清 “0”TF1(TF1也可由程序查询清“0”)。
-
TR(time run):定时器的运行控制位。该位由软件置位和清零。当GATE(TMOD.7)=0,TR1=1时就 允许T1开始计数,TR1=0时禁止T1计数。当GATE(TMOD.7)=1,TR1=1且INT1输入高电平时,才允许T1计数
-
EA : CPU的总中断允许控制位,EA=1,CPU开放中断,EA=0,CPU屏蔽所有的中断申请。EA的作用是使中断允许形成两级控制。即各中断源首先受EA控制;其次还受各中断源自己的中断允许控制位控制。
-
ET0 : T0的溢出中断允许位。ET0=1,允许T0中断;ET0=0禁止T0中断。
#include <REGX52.H>
/**
* @brief 定时器0初始化,1毫秒@12.000MHz
* @param 无
* @retval 无
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
*/
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
定时器时钟
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
unsigned char Sec=55,Min=59,Hour=23;
void main()
{
LCD_Init();
Timer0Init();
LCD_ShowString(1,1,"Clock:"); //上电显示静态字符串
LCD_ShowString(2,1," : :");
while(1)
{
LCD_ShowNum(2,1,Hour,2); //显示时分秒
LCD_ShowNum(2,4,Min,2);
LCD_ShowNum(2,7,Sec,2);
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000) //定时器分频,1s
{
T0Count=0;
Sec++; //1秒到,Sec自增
if(Sec>=60)
{
Sec=0; //60秒到,Sec清0,Min自增
Min++;
if(Min>=60)
{
Min=0; //60分钟到,Min清0,Hour自增
Hour++;
if(Hour>=24)
{
Hour=0; //24小时到,Hour清0
}
}
}
}
}