Skip to content

定时器

作者:姜蘅洋

1.时钟周期和时钟频率之间的关系:

  • 时钟频率:1Hz 时钟周期:1s
  • 时钟频率:1KHz 时钟周期:1ms
  • 时钟频率:1MHz 时钟周期:1μs
  • 时钟频率:1GHz 时钟周期:1ns
  • 给定一个时钟频率,可以快速确定其时钟周期:
    • 如果时钟频率是72MHz,那么时钟周期是1/72μs,72个时钟周期是1μs。
  • 给定一个时钟周期,可以快速确定其时钟频率:
    • 如果时钟周期是30μs,那么时钟频率是1/30MHz,大约是33.3KHz。

2.STC89C52RC定时器介绍:

  • STC89C52RC单片机中内置三个定时器:
    • 定时器T0、定时器T1、定时器T2。
  • 定时器T0定时器T1
    • 定时器T0和定时器T1都是16位定时器(由一个16位的寄存器构成),拥有定时和计数两种功能。
      • 16位计数器的计数范围是0 ~ 65535
    • 定时器的核心是加法计数器(当然也可以用减法计数器),本质是对脉冲信号进行计数:
      • 当输入脉冲来自系统时钟(周期恒定的脉冲)时,通常用于计时功能
      • 当输入脉冲来自单片机外部(周期不恒定的脉冲)时,通常用于计数功能(对脉冲进行计数)。

3.定时器T0:

  • 定时器T0的工作模式:

    • 模式0:13位定时器。
    • 模式1:16位定时器。
    • 模式2:8位自动重装载。
    • 模式3:分成两个8位定时器。
  • 相关寄存器:

    • 中断控制寄存器TCON:

      • image-20230607221413442
      • TF0位
        • 定时器T0的溢出中断标志。
        • 当定时器T0被允许计数之后,从初值开始加1计数,当最高位产生溢出时,由硬件置位为1,并且向CPU请求中断,当CPU相应中断后,该位可以由硬件清0,也可以由软件清0。
      • TR0位
        • 定时器T0的运行控制位。
        • 当TMOD.3 = 0,TR0 = 1时,定时器T0开始对脉冲信号计数。
        • 当TMOD.3 = 0,TR0 = 0时,定时器T0结束计数。
    • 定时器工作模式寄存器TMOD:

      • image-20230607222418833
      • 这里我们考虑定时器T0:
        • TMOD.3 / GATE位
          • 当GATE = 0时,TCON寄存器的TR0位直接控制定时器T0的开关。
          • 当GATE = 1时,TCON寄存器的TR0位和P3_2引脚共同控制定时器T0的开关。
        • TMOD.2 / C/T位
          • 当C/T = 0时,定时器T0的功能为定时功能,输入脉冲为系统时钟信号。
          • 当C/T = 1时,定时器T0的功能为计数功能,输入脉冲为外部信号。
        • M1位和M2位
          • 这两位用来进行模式的选择:
            • image-20230607223125982
    • 寄存器TH0和TL0:

      • TH0和TL0是两个8位寄存器,这两个寄存器合并作为定时器T0的16位寄存器。
    • 中断允许寄存器IE

      • image-20230607210959303
        • EA位
          • CPU总中断控制位。
          • 当EA = 1的时候,CPU开放所有中断请求。
          • 当EA = 0的时候,CPU关闭所有中断请求。
        • ET0位
          • 定时器T0的中断溢出允许位。
          • 当ET0 = 1的时候,定时器T0的溢出中断请求位打开。
          • 当ET0 = 0的时候,定时器T0的溢出中断请求位关闭。

4.定时器T1:

  • 定时器T1的工作模式:

    • 模式0:13位定时器。
    • 模式1:16位定时器。
    • 模式2:8位自动重装载。
  • 相关寄存器:

    • 中断控制寄存器TCON:

      • image-20230607221413442
      • TF1位
        • 定时器T1的溢出中断标志。
        • 当定时器T1被允许计数之后,从初值开始加1计数,当最高位产生溢出时,由硬件置位为1,并且向CPU请求中断,当CPU相应中断后,该位可以由硬件清0,也可以由软件清0。
      • TR1位
        • 定时器T1的运行控制位。
        • 当TMOD.7 = 0,TR1 = 1时,定时器T1开始对脉冲信号计数。
        • 当TMOD.7 = 0,TR1 = 0时,定时器T1结束计数。
    • 定时器工作模式寄存器TMOD:

      • image-20230607222418833
      • 这里我们考虑定时器T1:
        • TMOD.7 / GATE位
          • 当GATE = 0时,TCON寄存器的TR1位直接控制定时器T1的开关。
          • 当GATE = 1时,TCON寄存器的TR1位和P3_3引脚共同控制定时器T1的开关。
        • TMOD.6 / C/T位
          • 当C/T = 0时,定时器T1的功能为定时功能,输入脉冲为系统时钟信号。
          • 当C/T = 1时,定时器T1的功能为计数功能,输入脉冲为外部信号。
        • M1位和M2位
          • 这两位用来进行模式的选择:
            • image-20230607223603802
    • 寄存器TH1和TL1:

      • TH1和TL1是两个8位寄存器,这两个寄存器合并作为定时器T1的16位寄存器。

5.TH0和TL0中存储值的计算方法:

  • 在STC89C52RC中,输入到定时器中的时钟频率:
    • SYSCLK / 12,也就是把时钟频率12分频,时钟周期扩大12倍。
    • SYSCLK / 6,也就是把时钟频率6分频,时钟周期扩大6倍。
    • 大多数情况下,我们都选择12分频。
  • 假设定时时间是20ms:
    • 将系统时钟频率的单位变为Hz,对应的时间单位就变为了s:11.0592MHz = 11059200LHz,注意,这个值要用long int存储。
    • 将系统时钟频率12分频:输入时钟频率 = 11059200L / 12
    • 输入时钟周期:12 / 11059200L
    • 20ms = 0.02s,输入时钟周期数 = 0.02s / (12 / 11059200L) = 11059200L / 12 * 0.02 = 18432
    • TH0TL0赋一个初值,让其经过18432个机器周期后达到65536(因为16位寄存器只能存储0 ~ 65535)溢出。
      • 初值 = 65536 - 18432 = 47104 = 0xB800
      • TH0 = 0xB800 >> 8;
      • TL0 = 0xB800;
  • 使用定时器计算软件计算初值:
    • 目前,我们已经掌握了定时器初值的计算,此时学习的目的已经达到,因此接下来可以直接使用定时器计算软件。
    • image-20230608090037291
      • 注意,该款单片机没有AUXR寄存器。

6.使用定时器T0控制LED灯闪烁:

  • 场景描述:使用定时器创建1s延时函数来控制LED灯闪烁。

  • c
    //bsp_led.c
    void ChangeStatus_LED(void)
    {
    	LED_Control = 1;
    	Reg_LED = ~Reg_LED;
    	LED_Control = 0;
    }//我们在原有源代码的基础上增加了这样一个函数,通过按位取反操作改变LED的状态。
  • c
    //bsp_time2.c
    #include "bsp_time_0.h"
    uint_8 count_time0 = 0; 
    void Timer0_Isr(void) interrupt 1 //定时器T0每次计时50ms,我们在中断函数中设置一个计数变量count_time0,当计数变量到达20的时候,说明计数时间为1s。
    {
    	TL0 = 0x00;				
    	TH0 = 0x4C;	//由于没有重装载功能,因此要手动装载。
    	if (++count_time0 == 20)
    	{
    		count_time0 = 0;
    		ChangeStatus_LED();//每隔1s改变一次LED灯的状态。
    	}
    }
    void Timer0_Init(void)		//@11.0592MHz
    {	
    	TMOD &= 0xF0;			
    	TMOD |= 0x01;			//选择定时器T0的工作模式。
    	TL0 = 0x00;				
    	TH0 = 0x4C;				//对定时器初始值进行装载。
    	TF0 = 0;				//在初始化的时候,手动将定时器T0的溢出中断标志位清0。
    	TR0 = 1;				//启动定时器T0的计时功能。
    	ET0 = 1;				//开启定时器T0的中断溢出请求位。
    	EA = 1;					//开启CPU中断请求位。
    }
  • c
    //bsp_time0.h
    #ifndef __BSP_TIME_0_H__
    #define __BSP_TIME_0_H__
    #include "overwhelm.h"
    void Timer0_Init(void);//中断服务函数不需要进行声明。
    #endif /*__BSP_TIME_0_H__*/
  • c
    //main.c
    #include "overwhelm.h"
    
    void main(void)
    {
    	Init_LED();
    	Timer0_Init();
    	while (1)
    	{
    		//由于使用定时器中断的方式操控LED灯,因此while中为空。
    	}
    }

Released under the MIT License.