振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期)
状态周期:2个振荡周期为1个状态周期,用S表示。振荡周期又称S周期或时钟周期。
机器周期:1个机器周期含6个状态周期,12个振荡周期。
指令周期:完成1条指令所占用的全部时间,它以机器周期为单位。
例如:外接晶振为12MHz时,51单片机相关周期的具体值为:
振荡周期=1/12us;
状态周期=1/6us;
机器周期=1us;
指令周期=1~4us;
在学习定时器之前需要明白的
51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。
定时器/计数器和单片机的CPU是相互独立的。
定时器/计数器工作的过程是自动完成的,不需要CPU的参与。
51单片机中的定时器/计数器是根据机器内部的时钟或者是外部的脉冲信号对寄存器中的数据加1。
有了定时器/计数器之后,可以增加单片机的效率,一些简单的重复加1的工作可以交给定时器/计数器处理。CPU转而处理一些复杂的事情。同时可以实现精确定时作用。
定时/计数器的工作原理
定时/计数器实质上是一个加1计数器。它随着计数器的输入脉冲进行自加1,也就是每来一个脉冲,计数器就自动加1,,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。
可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。
51单片机定时器结构
定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。
定时/计数器的控制
51单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD用于设置其工作方式;TCON用于控制其启动和中断申请。
1、工作方式寄存器TMOD
工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:
GATE是门控位, GATE=0时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;
GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了INT0/1引脚为高电平这一条件。
C/T :定时/计数模式选择位。C/T =0为定时模式;C/T =1为计数模式。
M1M0:工作方式设置位。定时/计数器有四种工作方式。
2、控制寄存器TCON
TCON的低4位用于控制外部中断,已在前面介绍。TCON的高4位用于控
制定时/计数器的启动和中断申请。其格式如下:
TF1(TCON7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。
TR1(TCON6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。
TF0(TCON5):T0溢出中断请求标志位,其功能与TF1类同。
TR0(TCON4):T0运行控制位,其功能与TR1类同。
定时/计数器的工作方式
1、方式0
方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
定时器模式时有:N=t/ Tcy
计数初值计算的公式为:X=2^13-N。
定时器的初值还可以采用计数个数直接取补法获得。
计数模式时,计数脉冲是T0引脚上的外部脉冲。
门控位GATE具有特殊的作用。当GATE=0时,经反相后使或门输出为1,此时仅由TR0控制与门的开启,与门输出1时,控制开关接通,计数开始;当GATE=1时,由外中断引脚信号控制或门的输出,此时控制与门的开启由外中断引脚信号和TR0共同控制。当TR0=1时,外中断引脚信号引脚的高电平启动计数,外中断引脚信号引脚的低电平停止计数。这种方式常用来测量外中断引脚上正脉冲的宽度。
2、方式1
方式1的计数位数是16位,由TL0作为低8位,TH0
作为高8位,组成了16位加1计数器 。
计数个数与计数初值的关系为:X=2^16-N
3、方式2
方式2为自动重装初值的8位计数方式。
计数个数与计数初值的关系为:X=2^8-N
工作方式2特别适合于用作较精确的脉冲信号发生器。
4、方式3
方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。
工作方式3将T0分成为两个独立的8位计数器TL0和TH0 。
使用定时器,该做哪些工作
初始化程序应完成如下工作:
1对TMOD赋值,以确定T0和T1的工作方式。
2计算初值,并将其写入TH0、TL0或TH1、TL1。
3中断方式时,则对EA赋值,开放定时器中断。
4使TR0或TR1置位,启动定时/计数器定时或计数。
计数器初值的计算:
机器周期也就是CPU完成一个基本 *** 作所需要的时间。
机器周期=1/单片机的时钟频率。
51单片机内部时钟频率是外部时钟的12分频。也就是说当外部晶振的频率输入到单片机里面的时候要进行12分频。比如说你用的是12MHZ的晶振,那么单片机内部的时钟频率就是12/12MHZ,当你使用12MHZ的外部晶振的时候。机器周期=1/1M=1us。
而我们定时1ms的初值是多少呢,1ms/1us=1000。也就是要计数1000个数,初值=65535-1000+1(因为实际上计数器计数到64536才溢出)=64536=FC18H
定时器中断
使用定时器,该做哪些工作
初始化程序应完成如下工作:
对TMOD赋值,以确定T0和T1的工作方式。
计算初值,并将其写入TH0、TL0或TH1、TL1。
中断方式时,则对EA赋值,开放定时器中断。
使TR0或TR1置位,启动定时/计数器定时或计数。
TR0 是51单片机定时器T0的定时器启动位。
TR0=1 表示开启定时器(在EA打开的前提下)。
EA 是51单片机的总中断开关,
所有中断都必须先使EA=1。
51单片机中的定时器控制字中有两个控制位TR0、TR1,分别用于启动、停止定时器的计数,任何时刻,当TR0/TR1为1时,T0/T1定时器计数;当TR0/TR1为0时,T0/T1定时器停止计数,置TR0/TR1为1的指令一般应该在初始化程序或主程序或其他程序中。
扩展资料:
定时/计数器T0和T1分别是由两个8位的专用寄存器组成,即定时/计数器T0由TH0和TL0组成,T1由TH1和TL1组成。此外,其内部还有2个8位的特殊功能寄存器TMOD和TCON,TMOD负责控制和确定T0和T1的功能和工作模式,TCON用来控制T0和T1启动或停止计数,同时包含定时/计数器的状态。
TF1:定时器1溢出标志。定时/计数器溢出时由硬件置位。中断处理时由硬件清除。或用软件清除。
TF0:定时器0溢出标志。定时/计数器溢出时由硬件置位。中断处理时由硬件清除,或用软件清除。
参考资料来源:百度百科-定时器中断
看看这样行不?sbit KEY=P1^0;
bit BKeyLast;
main()
{
……//初始化定时器
TR0=BKeyLast=KEY;
while(1)
{
while(KEY==BKeyLast) ;
if(BKeyLast) TR0=0; //BKeyLast=1时,KEY==0,按下。
else TR0=1;
for(i=0;i<250;i++) ; //去抖动。
BKeyLast=!BKeyLast;
}
}
……//定时服务程序/
蜂鸣器唱歌程序
当独立按键P3^2按下时蜂鸣器便开始唱歌。
/
#include<reg52h>
#define uchar unsigned char
#define uint unsigned int
uchar Count;
sbit Speak =P1^2;
sbit key1=P3^2;
unsigned char code SONG[] ={
0x26,0x20,0x20,0x20,0x20,0x20,0x26,0x10,0x20,0x10,0x20,0x80,0x26,0x20,0x30,0x20,
0x30,0x20,0x39,0x10,0x30,0x10,0x30,0x80,0x26,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,
0x20,0x80,0x2b,0x20,0x26,0x20,0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x80,0x26,0x20,
0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x60,0x40,0x10,0x39,0x10,0x26,0x20,
0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x80,0x26,0x20,0x2b,0x10,0x2b,0x10,
0x2b,0x20,0x30,0x10,0x39,0x10,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x20,
0x20,0x10,0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x18,0x20,0x18,0x20,0x26,0x20,
0x20,0x20,0x20,0x40,0x26,0x20,0x2b,0x20,0x30,0x20,0x30,0x20,0x1c,0x20,0x20,0x20,
0x20,0x80,0x1c,0x20,0x1c,0x20,0x1c,0x20,0x30,0x20,0x30,0x60,0x39,0x10,0x30,0x10,
0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x10,0x26,0x10,0x26,0x10,0x2b,0x10,0x2b,0x80,
0x18,0x20,0x18,0x20,0x26,0x20,0x20,0x20,0x20,0x60,0x26,0x10,0x2b,0x20,0x30,0x20,
0x30,0x20,0x1c,0x20,0x20,0x20,0x20,0x80,0x26,0x20,0x30,0x10,0x30,0x10,0x30,0x20,
0x39,0x20,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x10,0x40,0x10,0x20,0x10,
0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x00
};
void Time0_Init()
{
TMOD = 0x01;
IE = 0x82;
TH0 = 0xDC;
TL0 = 0x00;
}
/
功能 : 定时器中断,中断中实现 Count 加一
输入 : 无
输出 : 无
/
void Time0_Int() interrupt 1
{
TH0 = 0xDC;
TL0 = 0x00;
Count++;
}
/
名称 : Delay_xMs()
功能 : 延时子程序
输入 : x
输出 : 无
/
void Delay_xMs(uint x)
{
uint i,j;
for(i=0; i<x; i++)
{
for(j=0; j<3; j++);
}
}
void delay(void)
{
int i;
for(i=0;i<1827;i++);
}
/
名称 : Play_Song()
功能 : 播放蜂鸣器控制程序
输入 : 无
输出 : 无
/
void Play_Song(void)
{
uchar Temp1,Temp2;
uint Addr;
Count = 0; //中断计数器清0
Addr =0;
while(1)
{
Temp1 = SONG[Addr++];
if (Temp1 == 0xFF) //休止符
{
TR0 = 0;
Delay_xMs(100);
}
else if (Temp1 == 0x00) //歌曲结束符
{
return;
}
else
{
Temp2 = SONG[Addr++];
TR0 = 1;
while(1)
{
Speak = ~Speak;
Delay_xMs(Temp1);
if(Temp2 == Count)
{
Count = 0;
break;
}
}
}
}
}
/
名称 : Main()
功能 : 主函数
输入 : 无
输出 : 无
/
void Main()
{
Time0_Init(); //定时器0中断初始化
while(1)
{
if(key1==0)
{
delay();
if(key1==0) Play_Song();
}
}
}这段代码是先初始化参数,再停止定时器,再启动定时器。结束定时器需要等到当前的节拍结束,才能正式写入停止,所以用while判断是否成功写入,如果没写入,说明没到节拍结束,未正常置位,继续写/定时器0计数次数越多,代表PWM波周期越长,蜂鸣器声音就深沉一些,次数低了频率就高了,声音尖一些。
定时器1的功能是决定定时器0的频率切换。/
#include<reg52h>
#define uint unsigned int
#define uchar unsigned char
uint flag=0;
uint fre;
uchar tt=0; //flag fre tt都是全局变量,初值为0,随时赋值,值随时改变
sbit beep=P0^7; //蜂鸣器输出引脚P07设为beep,以后beep就代表P07
void main() //主程序,void意思是没返回值
{
beep=0; //拉低蜂鸣器引脚
TMOD=0x11; //设置定时器T0和定时器T1的工作方式为1
TH0=(65536-50000)/256;
TL0=(65535-50000)%256; // TO控制频率,设置初值
TH1=(65536-fre)/256;
TL1=(65535-fre)%256; //T1控制间隔,设置初值
EA=1; //开总中断,开中断,开始计数
ET0=1;
TR0=1;
ET1=1;
TR1=1;
while(1) ; //等待中断
}
void time1() interrupt 3 //控制间隔,定时器1溢出的时候会进入这个程序运行
{
TH1=(65536-50000)/256;//计数50000的初值高8位赋值
TL1=(65535-50000)%256; //计数50000的初值低8位赋值
flag++; //自加1
if(flag==320) //自加320次,置0
{
flag=0;
}
}
void time0() interrupt 1 //控制频率 定时器1溢出的时候会进入这个程序运行
{
TR0=0; //暂停计数
TH0=(65536-fre)/256; //赋初值
TL0=(65535-fre)%256;
if (flag<40)
{
tt++;
if(tt==10) //定时器1溢出40以内时,定时器0计数5000010次蜂鸣器引脚取反一次
{
tt=0;
fre=50000;
beep=~beep;
}
}
/定时器1溢出40-80时,定时器0计数50000次蜂鸣器引脚取反一次/ if(flag>=40&&flag<80)
{
fre=50000;
beep=~beep;
}
/定时器1溢出80-120时,定时器0计数10000蜂鸣器引脚取反一次/ if(flag>=80&&flag<120)
{
fre=10000;
beep=~beep;
}
/定时器1溢出120-160时,定时器0计数5000次蜂鸣器引脚取反一次/ if(flag>=120&&flag<160)
{
fre=5000;
beep=~beep;
}
/定时器1溢出160-200时,定时器0计数2500次蜂鸣器引脚取反一次/ if(flag>=160&&flag<200)
{
fre=2500;
beep=~beep;
}
/定时器1溢出200-240时,定时器0计数1250次蜂鸣器引脚取反一次/ if(flag>=200&&flag<240)
{
fre=1250;
beep=~beep;
}
/定时器1溢出240-280时,定时器0计数625次蜂鸣器引脚取反一次/ if(flag>=240&&flag<280)
{
fre=625;
beep=~beep;
}
/定时器1溢出280-320时,定时器0计数500次蜂鸣器引脚取反一次/ if(flag>=280&&flag<320)
{
fre=500;
beep=~beep;
}
TR0=1;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)