单片机的定时/计数器
MCS-51单片机内部有2个16位的可编程定时/计数器。定时/计数器X(X=0、1)由计数器THX和TLX组成。定时/计数器由特殊寄存器TMOD和TCON决定。
方式寄存器TMOD(TIMER/COUNTER MODE CONTROL REGISTER):
TMOD | GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
其中低4位控制定时/计数器0,高4位控制定时/计数器1。
GATE:门控位。当GATE=1时,定时/技术器受外部中断信号INT的控制,当TRX为1时开始计数,为0时停止计数。
C/T(count/timer):当C/T=0时为定时方式,其计数器输入为晶振脉冲的12分频,即对机器周期计数。当C/T=1时为计数方式,计数器的触发输入来自T0或T1的外部脉冲。
M1和M0:操作方式选择位。
M1M0 | 操作方式 | 功能 |
00 | 方式1 | 13位计数器(TLX的高3位不使用) |
01 | 方式2 | 16位计数器 |
10 | 方式3 | 可自动再装载的8位计数器 |
11 | 方式4 |
定时/计数器0分为两个独立计数器 定时/计数器1为串行口波特率发生器 |
启/停控制寄存器TCON(TIMER CONTROL):
TCON | TF1 | TR1 | TF0 | TR0 | TE1 | IT1 | IE0 | IT0 |
TF(timer full):定时器溢出标志
TR(timer running):定时器运行控制位
后面四位是和中断有关的,前面的博客已经提过了。
定时/计数器的初始化:
1.对方式寄存器TMOD赋值,确定工作方式。
2.预置定时或计数初值,直接将初值写入TL0,TH0或TL1,TH1中。
3.根据需要对中断允许寄存器有关位赋值,以开放或禁止定时/计数器。
4.启动定时/计数器。
初始值的计算:
计数方式:X = M-计数值
定时器方式: X = M-定时器/T
/* 若单片机晶振为12MHz,用定时/计数器0编程实现从P1.0输出周期为500us的方波*/ // 选择定时/计数器0以方式2进行工作 #include<reg51.h> sbit P1_0 = P1^0; void mian(){ TMOD = 0x02; // 0000 0010 采用方式2 TH0 = 0x06; // 2^8-500/2=256-250=6 TL0 = 0x06; // 在方式2中,TL定义为加1计数器,TH定义为赋初值寄存器 TR0 = 1; // 启动计数/定时器0 for( ; ; ){ if(TF0){ //定时器打开后它直接就会跑了,当到了最大值,TF=1 TF0 = 0; P1_0 = !P1_0; } } } //采用中断的方式 #include<reg51.h> sbit P1_0 = p1^0; void main(){ //时钟初始化 TMOD = 0x02; TH0 = 0x06; TL0 = 0x06; TR0 = 1; //中断初始化 EA = 1; //打开中断的总允许 ET0 = 1; //打开定时器0的中断允许 while(1); }
//中断函数不用我们在主函数中调用,自己时间到了将会运行 void time0_fun(void) interrupt 1 using 0{ //T0的中断号是1 P1_0 = !P1_0; }
如果定时的时间小于8192us,可以用方式0。小于65536us,可以用方式1。但是方式0和1要在定时时间到后重新定时。
/* 实现周期为1s的方波输出*/ /*采用全局变量作软件计数,计算并判断中断次数实现 */ #include<reg51.h> sbit P1_1 = P1^1; unsigned char i; void main(){ //时钟初始化 TMOD = 0x01; TH0 = (65536-10000)/256; // 1000ms/2/50=10ms=10000us TL0 = (65536-10000)%256; //这样赋初值是因为TH0,TL0是八个字节的,不满256的给低位,高于256的给高位 //65536-10000=55536=1101100011110000B=D8F0H //中断初始化 EA = 1; ET0 = 1; TR0 = 1; i=0; while(1); } void time0_fun(void) interrupt 1{ TH0 = (65536-10000)/256; TL0 = (65536-10000)%256; i++; if(i==50){ P1_1 = !P1_1; i = 0; } } /* 采用定时/计数器1对定时/计数器0的定时时间进行计数实现 */ #include<reg51.h> sbit P1_1 = P1^1; sbit P3_5 = P3^5; // T1的引脚 void main(){ //时钟的初始化 TMOD = 0x61; //0110 001B T1为计数方式,以方式2工作 T0为定时方式,以方式0工作 TH0 = 0xD8; //与上面一样 TL0 = 0xf0; //T0每10ms就对T1进行一次变反,这样T1端有一个周期为20ms的周期输出 TH1 = 0xE7; //赋初值计数器 256-25 = 231 = 11100111B 25*20 = 500ms TL1 = 0xE7; //加一计数器 //中断的初始化 EA = 1; ET0 = 1; ET1 = 1; TR0 = 1; TR1 = 1; while(1); } void time0_fun(void) interrupt 1{ TH0 = 0xD8; TL0 = 0xf0; P3_5 = !P3^5; } void time1_fun(void) interrupt 3{ P1_1 = !P1_1; }