STC89C52RC定时器

kyaa111 2月前 ⋅ 256 阅读

如电路图

image.png

image.png

定时器分为四个模块

  • 时钟源模块
  • 计数器模块
  • 控制逻辑模块
  • 中断模块 (notify)

如果要使用定时器, 需要对模块对应的寄存器做初始化

本次选择定时器0, 工作模式1

image.png

image.png

配合芯片手册

初始化TCON和TMOD两个地址

image.png

image.png

所以

  1. 时钟源模块
    1. 使用默认的系统时钟源即可, 即C/T=0
  2. 控制模块
    1. GATE=0
    2. TR0=1
  3. 中断模块
    1. TF0=0
    2. IE0=1
    3. ET0=1
    4. EA=1总闸启用
    5. IT0=0低电平触发方式即可
  4. M1/M0两位共同选择模式, 赋值01代表模式1

image.png

image.png

  1. 计数器模块
    1. 时钟源会每隔一段时间发送一次信号, 计数器接受到信号, 就将计数加一
    2. 定时器的本质原理,每经过一个机器周期,与定时器相关的某个寄存器加一
      1. 什么是机器周期: 机器周期也称为CPU周期。在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段(如取指、译码、执行等),每一阶段完成一个基本操作。完成一个基本操作所需要的时间称为 机器周期。
      2. 一个机器周期又是若干个时钟周期,一般来说一个机器周期是6个时钟周期或者12个时钟周期,我们STC89C52RC兼容51系列, 默认是12T模式
      3. image.png
      4. 什么是时钟周期: 时钟周期也称为振荡周期,定义为时钟频率的倒数。时钟周期是计算机中最基本的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。时钟周期是一个时间的量。时钟周期表示了SDRAM所能运行的最高频率。更小的时钟周期就意味着更高的工作频率。
      5. 什么是晶振: 晶振(晶体震荡器),又称数字电路的“心脏”,是各种电子产品里面必不可少的频率元器件。数字电路的所有工作都离不开时钟,晶振的好坏、晶振电路设计的好坏,会影响到整个系统的稳定性。在我们要使用定时器进行计数时,一定要了解以上的这些东西。我们要怎样准确的来时间,这就需要晶振派上用场了。每个单片机上面都会有晶振,每个晶振的频率也大不相同。例如,我手上这块51单片机的频率是11.0592MHz。如上文所说,一个时钟周期是时钟频率的倒数,那么我手上这块51单片机的时钟周期是1/11.0592MHz.
      6. 机器周期 = n * 时钟周期 (此处n=12)
      7. 时钟周期 = 1 / 时钟频率
    3. 计数器是两个字节共同存储的, 当两个字节溢出后, 产生一次中断信号
    4. 计算出一个机器周期对应的时间, 设置好计数器的起始值, 也就能让计数器指定间隔多少时间输出一次中断信号了
    5. STC89C52RC时钟频率是11.0592MHz, 11.0592MHz的时钟源每隔约90.4224537037纳秒(即1 / 11.0592MHz)产生一个时钟脉冲信号。12T模式下, 一个机器周期耗时也就是12*90.4224537037=1085.0694444444纳秒, 我们需要让定时器间隔1毫秒输出一次信号, 也就是1毫秒=1000000 纳秒 / 1085.0694444444 纳秒 ≈ 921.6922, 即922个机器周期约为1毫秒
    6. 即两个字节最大为65535 - 922 + 1 = 64614 = 0xFC66. (注意当计数器计数922次后到达65535时没有发生溢出, 需要再计数一次才发生溢出, 所以+1) 即
      1. TH0=0xFC
      2. TL0=0x66

综上

TMOD

TMOD为不可位寻址 所以进行整体赋值

0000 0001

TMOD = 0x01

TCON

TCON可位寻址, 所以可以一个一个赋值

TF0=0

TR0=1

IE0=1

IT0=0

计数器

TH0=0xFC

TL0=0x66

附代码

#include "reg52.h"
#include "lcd1602.h"

typedef unsigned int u16;
typedef unsigned char u8;


sbit LED1 = P2^0;

void time0_init(void) {
    //选择为定时器0模式, 工作方式1
    TMOD = 0x01;
    // 给定时器赋初值, 定时1ms
    TH0 = 0xFC;
    TL0 = 0x66;
    // 打开定时器0中断允许
    ET0 = 1;
    // 打开总中断
    EA = 1;
    // 复位
    TF0 = 0;
    // 最后一步打开定时器
    TR0 = 1;
}


void main() {	
    LCD_Init();
    time0_init();

    while(1) {			

    }		
}

u16 a = 0;
u16 i = 0;

// 定时器0中断函数
void time0() interrupt 1 {
    // 定时器重新赋初值, 定时1ms
    TH0 = 0xFC;	
    TL0 = 0x66;
    i++;
    if (i == 1000) {
        i = 0;
        LED1 = !LED1;	
        a++;
        LCD_ShowNum(1, 1, a, 3);
    }						
}

烧录好程序, 即可看到LCD每隔1s (存在误差)自增, LED也进行亮灭