(六)定时器/计数器

(六)定时器/计数器

一、简介

定时器和计数器是两个名字,但是原理上来说是一样的,都是对脉冲进行计数,区别在于时钟来源,如果来自内部时钟信号,由于内部时钟通常是比较准确的,所以是定时器,如果来自外部引脚,而外部引脚的信号并一定准确,则只对其进行计数,所以是计数器。接下来主要以定时器为主进行简单介绍,计数器类同。

二、时间计算

顾名思义,定时器肯定是和时间有关系的,那么时间是怎么计算的呢,我们以普通51内核为例。如下图(图片来自百度,我觉得他和51不符,所以改了下),通常一个指令周期=2X机器周期=12X时钟周期。而时钟周期又来自晶振。因此晶振频率确定后,那么各个时间也就确定了。
(六)定时器/计数器_第1张图片

1. 计算内部指令周期

假设晶振频率是12MHz,那么机器周期=1/12MHz=1/12us,指令周期=12*机器周期=1us,也就是说单片机每执行一条指令,最小时间是1us。

2. 计算定时器初值

大多数定时器都可以工作在两种模式,一种是8位(最大计数256次)自动重装模式,一种是16位(最大计数65536次)自动重装模式,由于16位很显然计数或定时的范围是要远远大于8位的,因此,我们以16位模式应用为例,讲解计算方法。
定时器在进行计数时是采用向上的方式,也就是说每一个系统信号过来以后,定时器设置的值进行+1,这里就有两个方式:

  1. 给定时器设置结束的值,从0开始不断+1,直到达到设置值溢出结束
  2. 给定时器设置初始值,从初始值不断+1,直到达到65536溢出结束

我们的51单片机采用了第二种方式,所以给定时器设置值时,我们说设置的是初值。计算公式如下:

初值=65536-定时时长指令周期=65536-定时时长(12*机器周期)

当晶振取值12MHz时,指令周期最小时间就是1us,因此上式也可以写成
初值=65536-定时时长
定时时长取值范围:165536us或165.536ms

3. STC-12T系列单片机初值

STC单片机很多系列现在都做到了12T,也就是说指令周期最小可以做到等于机器周期,不需要再除以12。因此除了单片机运行速度加快以外,定时精度也更高,计算公式如下:

初值=65536-定时时长指令周期=65536-定时时长机器周期

当晶振取值12MHz时,指令周期最小时间就是1/12us
初值=65536-定时时长/12
定时时长取值范围:1/1265536/12us或1/1265.536/12ms

由于12不能整除,所以计算时会有小数点,精度上比普通51会高一个数量级

三、寄存器设置

举个例子,以定时器016位自动重装实现1秒定时,STC的C51定时器,需要使用到的寄存器有如下几个:
AUXR:辅助就寄存器

7 6 5 4 3 2 1 0
T0x12 T1x12 UART_M0x6 T2R T2_C/T T2x12 EXTRAM SIST2
0 定时器0工作在传统8051速度,12分频
1 定时器0工作在高速8051速度(1T),不分频

TCON:定时器/计数器中断控制寄存器,很多中断的控制寄存器都在这里,定时器中断允许等操作在这里

7 6 5 4 3 2 1 0
TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
定时器0溢出中断,硬件置位 定时0运行控制位,软件置1后开始运行,置0后结束运行

TMOD:定时器/计数器工作设置寄存器

7 6 5 4 3 2 1 0
GATE C/T M1 M0 GATE C/T M1 M0
0 定时器模式 0 0 十六位自动重装
1 计时器模式 0 1 十六位不可重装
1 0 8位自动重装
1 1 不可屏蔽中断16位自动重装

TL0:定时器初值低8位
TH0:定时器初值高8位
除以上寄存器以外,还有两个隐藏寄存器RL_TH0和RL_TL0,这两个寄存器和TL0、TH0两个寄存器使用同一个地址,设置初值时会自动给这两个寄存器设置值,也就是溢出后,会将这两个隐藏值重新装入TL0、TH0。

四、代码示例

/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC15F4K60S4 系列 定时器0的16位自动重装载模式举例---------------*/
/* --- Mobile: (86)13922805190 -------------- -------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966-------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.GXWMCU.com --------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序        */
/* 如果要在文章中应用此代码,请在文章中注明使用了STC的资料及程序        */
/*---------------------------------------------------------------------*/

//本示例在Keil开发环境下请选择Intel的8058芯片型号进行编译
//若无特别说明,工作频率一般为11.0592MHz


#include "reg51.h"

typedef unsigned char BYTE;
typedef unsigned int WORD;

//-----------------------------------------------

#define FOSC 11059200L

#define T1MS (65536-FOSC/1000)      //1T模式
//#define T1MS (65536-FOSC/12/1000) //12T模式

sfr AUXR = 0x8e;                    //Auxiliary register
sbit P10 = P1^0;

//-----------------------------------------------

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
    P10 = ! P10;                    //将测试口取反
}

void main()
{
    AUXR |= 0x80;                   //定时器0为1T模式
//  AUXR &= 0x7f;                   //定时器0为12T模式

    TMOD = 0x00;                    //设置定时器为模式0(16位自动重装载)
    TL0 = T1MS;                     //初始化计时值
    TH0 = T1MS >> 8;
    TR0 = 1;                        //定时器0开始计时
    ET0 = 1;                        //使能定时器0中断
    EA = 1;							//使能全部中断
    while (1);
}

五、Proteus仿真

由于Proteus只能仿真普通51内核的单片机,所以上述代码还需要进行简单修改,改成普通51代码。
示例:led灯隔一秒亮灭一次,GIF录得有问题

//设晶振为12MHz
#include "reg52.h"

sbit P20 = P2^0;
unsigned char count = 0;

void tm0_isr() interrupt 1
{
    //定时器设置为10ms,1s=100*10ms
    //这里使用count进行计数,100次即1s
    count++;
    if(count > 100)
    {
		P20 = ! P20;        //将测试口取反
        count = 0;			//count清零,进行下次计数
    }
}

void main()
{
    TMOD &= 0xF1;	//设置定时器模式,普通51和stc的不一样,模式不同
    TL0 = 0xF0;		//设置定时初值
    TH0 = 0xD8;		//设置定时初值
    TR0 = 1;			//定时器0开始计时
    ET0 = 1;      //使能定时器0中断
    EA = 1;
    while (1);
}

(六)定时器/计数器_第2张图片
(六)定时器/计数器_第3张图片

你可能感兴趣的:(C51)