1
定时器是单片机内部的特殊功能模块。
在控制系统中,常常要求有一些实时时钟以实现定时或者延时控制,如定时中断、定时检测、定时扫描等等,也往往要求有计数器,对外部事件进行计数。
要实现定时或者延时功能,一般有三种方法:软件定时,不可编程硬件定时,可编程硬件定时。
软件定时——让软件循环执行一段程序,程序本身并无执行目的,而是通过执行程序延时固定的时间,也就是以前的程序中经常使用的延时程序。这种方法降低了cpu的利用率。
不可编程硬件定时——如外部芯片555 时基电路,通过外部阻容,达到一定的延时功能,改变阻容大小可以改变延时长度。这种定时器取决于硬件,设定好以后不能通过软件更改。
可编程定时器——这种定时器的定时值可以通过软件确定和修改,使用灵活便捷。
本节所讲的定时器为第三种,可编程定时器,51单片机中T0/T1为2个相同的16位定时/计数器。
定时/计数器的结构:
图 1 定时/计数器的结构
TCON控制寄存器:
TCON用于控制外部中断和定时/计数器启动和中断,低4位用于控制外部中断,高4位用于控制定时/计数器T0和T1。
TCON.0~TCON.3(IT0、IE0、IT1、IE1)均为外部中断相关位,详见外部中断。
TR0(TCON.4):定时/计数器T0运行控制位。TR0=1时,T0开始工作;TR0=0时,T0停止工作。TR0由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。
TF0(TCON.5):定时/计数器T0溢出中断请求标志位。TF0=1时,申请进去定时器中断。T0计数溢出时由硬件自动置TF0为1。CPU响应中断后TF0由硬件自动清0。T0工作时,CPU可随时查询TF0的状态。所以,TF0可用作查询测试的标志。TF0也可以用软件置1或清0,同硬件置1或清0的效果一样。
TR1(TCON.6):定时/计数器T1运行控制位,其功能与TR0类同。
TF1(TCON.7):定时/计数器T1溢出中断请求标志位,其功能与TF0类同。
TMOD模式控制寄存器:
图 3 TMOD模式控制寄存器格式
TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1
GATE: 门控位。GATE=0时,只要用软件使TCON中的TR0或TR1为1,就可以启动
定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚或也为高电平时,才能启动定时/计数器工作。即此时定时器的启动多了一条件。
M1M0:工作方式设置位。定时/计数器有四种工作方式,由M1M0进行设置。
表1 定时/计数器工作方式表
一、方式0
方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
图 4 方式0工作原理图
计数初值计算初值的公式为:
二、方式1
方式1的计数位数是16位,由TL0作为低8位、TH0作为高8位,组成了16位加1计数器。
图 5 方式1工作原理图
计数个数与计数初值的关系为:
三、方式2
方式2为自动重装初值的8位计数方式。当TL0装满溢出时,系统自动将TH0中的数值装给TL0,TLO重新开始计数。
图 6 方式2工作原理图
计数个数与计数初值的关系为:
四、方式3
方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。工作方式3将T0拆分成为两个独立的8位定时/计数器TL0和TH0,两个计数器独立工作。
图 7 方式3工作原理图
计数个数与计数初值的关系为:
#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit LED=P1^2; //定义LED端口
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=0x00; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=0x00;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
Init_Timer0();
while(1);
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
TH0=0x00; //重新赋值
TL0=0x00;
LED=~LED; //指示灯反相,可以看到闪烁
}
定时器0的程序代码
定时/计数器0 使用16位定时模式,计数初值为0,计数到65536 溢出,中断程序中LED取反,LED 以65536*2个时钟周期为周期闪烁。
计数个数与计数初值的关系为:
#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit LED=P1^3; //定义LED端口
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer1(void)
{
TMOD |= 0x10; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH1=0x00; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL1=0x00;
EA=1; //总中断打开
ET1=1; //定时器中断打开
TR1=1; //定时器开关打开
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
Init_Timer1();
while(1);
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer1_isr(void) interrupt 3 using 1
{
TH1=0x00; //重新赋值
TL1=0x00;
LED=~LED; //LED闪烁
}
定时1的程序代码
#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit OUT=P1^2; //定义OUT输出端口
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=(65536-500)/256; //给定初值,这里使用定时器最大值从500开始计数一直到65535溢出
TL0=(65536-500)%256; //12M晶振计算指令周期1us,1ms方波半个周期500us,即定时500次
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
Init_Timer0();
while(1);
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
TH0=(65536-500)/256; //重新赋值
TL0=(65536-500)*256;
OUT=~OUT; //溢出然后输出端取反
//用示波器可看到方波输出
}
图 10 1ms方波的程序代码
示波器显示周期为1ms的方波信号。
#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=(65536-500)/256; //给定初值,这里使用定时器最大值从500开始计数一直到65535溢出
TL0=(65536-500)%256; //12M晶振计算指令周期1us,1ms方波半个周期500us,即定时500次
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
Init_Timer0();
while(1);
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
static unsigned char i;
TH0=(65536-500)/256; //重新赋值
TL0=(65536-500)*256;
i++;
P1=i; //P1口8路输出不同频率,相当于一个分频器,高频用示波
//器测量,低频可以直接用led观测
//P1.0输出1ms方波,P1.1输出2ms,p1.2输出4ms,以此类推
}
图 11 多路不同频率方波的程序代码
中断部分,相当于一个分频器,在P1 口可以测量出8 路不同频率的方波。
P1 口测量不同频率方波,周期依次增大一倍。
全部0条评论
快来发表一下你的评论吧 !