一.写在前面
stc89c51有两个定时/计数器,今天主要测试它的定时功能。使用定时器来进行时间计算要比使用循环来的更精准一些。
这里我使用的晶振为12MHz,至于为什么使用12MHz的晶振,原因是stc89c51的机器周期是12个时钟周期,选用12MHz晶振后单片机执行一个机器周期的时间刚好是1us。而定时器的工作原理就是每过一个机器周期就自动加一直到溢出。
stc89c51的定时器为16位,下图给出的是定时/计数器相关的寄存器TCON
此寄存器可以按位寻址,就是说你可以这样赋值TR1 = 1(开启定时器1);对于那些不能按位寻址的寄存器比如TMOD就不能这样赋值了。
TF1:定时器/计数器T1溢出标志。T1被允许计数以后,从初值开始加1计数。当最高位产生溢出时由硬件置‘1’TF1,向CPU发送中断请求,一直保持到CPU响应中断时,由硬件自动清零,当不执行中断时,也可以通过查询的方式对TF1标志位进行软件清零
TR1:定时器T1的运行控制位。由软件置位和清零。当GATE(TMOD.7)=0,TR1=1时就运行T1开始计数,TR1=0时禁止T1计数。当GATE(TMOD.7)=1,TR1=1且INTI外部输入高电平时,才允许T1计数
TF0:同TF1拥有两种清零方式。
本次测试只使用TCON的高四位,低四位为中断使用,下一次在测试。
还有一个寄存器TMOD需要使用
对于TMOD的模式选择
•模式 1(M1=0,M0=1),是THn和TLn组成了一个16位的定时器,计数范围是0~65535,溢出后,只要不对THn和TLn重新赋值,则从0开始计数。(最常用的一种定时模式)
•模式 2 (M1=1,M0=0),是8位自动重装载模式,只有TLn做加1计数,计数范围0~255,THn的值并不发生变化,而是保持原值,TLn溢出后,TFn就直接置1了,并且THn原先的值直接赋给TLn,然后TLn从新赋值的这个数字开始计数。 (常用于串口通信)
二.具体使用方法
本次在P0^0口接上一个LED灯希望LED灯能够1s亮,1s灭。
/* Main.c file generated by New Project wizard
*
* Created: 周一 6月 17 2019
* Processor: AT89C51
* Compiler: Keil for 8051
单片机时钟周期为12MHz
12/12MHz = 1us
*/
#include <reg51.h>
#include <stdio.h>
//初始化LED灯,和计数器counter
int counter = 0;
sbit LED = P0^0;
void main(void)
{
// Write your code here
TMOD = 0x01;//定时器工作在模式1
//设置定时器初始值(每次定时50ms)
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
TR0 = 1;//开启定时器
while (1){
if(TF0 == 1){//定时器溢出
//对定时器重新初始化
TF0 = 0;
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
//counter计数
counter++;
if(counter == 20){//计数满1s
LED = ~LED;
counter = 0;
}
}
}
}
说明:由于定时器是16位的所以当计数到65536时就会溢出,单片机会置TF0 = 1作为溢出标志。
因为我们希望一次溢出为50ms所以要对它设置初始值即(65536 - 50000)
为该十六位寄存器的初始值,
但是我们不能直接对该十六位寄存器赋值,只能通过高位TH0和低位TL0进行赋值
此时就会有初始值的求模运算结果赋值给TH0;求余运算结果赋值给TL0。