一、单片机的时序知识:

当外接晶振为12MHZ,51单片机的相关周期:

1.时钟周期(振荡周期)为\frac{1}{12MHZ} = \frac{1}{12} us

2.机器周期,传统8051单片机中,1个机器周期=12个时钟周期(如12MHz晶振对应1μs)。

3.指令周期,执行一条指令所需的机器周期数,有单周期指令、双周期指令、四周期指令。

二、定时器的工作原理:

        定时器的本质就是计数器。定时器的工作原理‌是基于一个16位的加1计数器,由高8位和低8位两个寄存器THxTLx组成。每当接收到一个脉冲,计数器的值就会自动加1,当计数器的值达到最大值(2^{16}=65535)时,就会产生溢出,并触发中断请求‌。

三、51单片机的定时器:

        以AT89C51为例,包含两个定时器:Timer0 和 Timer1。每个定时器有四种工作模式,通过TMOD寄存器配置。

1.定时器的四种工作模式:

 模式0:使用 THx(高 8 位) + TLx 的低 5 位,共 13 位计数器(最大计数2^{13}=8192)。

 模式1:使用 THx(高 8 位) + TLx (低 8 位),共 16 位计数器(最大计数2^{16}=65536)。

              适用于需要长周期定时的场合(如延时、PWM 生成)。

 模式2(8 位自动重装定时器):

        TLx 作为计数器,THx 存储重装初值,TLx 溢出后,自动从 THx 重装初值,无需软件干预。适用于高频定时任务(如串口通信波特率生成)。

模式3(双 8 位定时器):

Timer0 拆分为两个独立 8 位定时器,

        TL0:独立 8 位定时器,使用 Timer0 的控制位(TR0、TF0)。

        TH0:独立 8 位定时器,借用 Timer1 的控制位(TR1、TF1)。

注意:模式0、模式1在溢出后需软件重装初值;模式3仅Timer0可用,Timer1 在模式 3 下停止工作,但仍可配置为其他模式。

2.定时器工作模式的寄存器配置:

通过 TMOD(Timer Mode Control Register,地址 0x89) 配置 Timer0 和 Timer1 的工作模式:

  • 低 4 位(Bit0~Bit3):配置 Timer0 的模式和功能(定时器/计数器)。

  • 高 4 位(Bit4~Bit7):配置 Timer1 的模式和功能。

关键位:

  • M1/M0:选择模式(00=模式0,01=模式1,10=模式2,11=模式3)。

  • C/T:置0=定时器模式(内部时钟),置1=计数器模式(外部引脚 T0/T1 输入)。

  • GATE:置0=由 TRx 位控制定时器启停,置1=由 TRx 和 INTx 引脚共同控制。

如下图以定时器0的模式1为例,定时器的工作/配置原理图:

SYSclk(时钟周期):可以选择12分频和6分频。通过12分频可以得出来一个机器周期。

3.定时器初值的计算:

        假设定时时间为T,

        机器周期 = 12 / 晶振频率(单位秒)

        计数值 = 定时时间T / 机器周期

        初值 = 最大计数值 - 计数值

        THx= 初值/256

        TLx= 初值%256

例如在12MHz晶振下,使用定时器0模式1,如何计算1ms的定时初值:

这时候机器周期是1微秒,1ms需要1000个机器周期。初值就是65536 - 1000 = 64536

TH0=64536/256=0xFC      TL0=64536%256=0x18

四、定时器的配置流程:

  • 1.对寄存器TMOD赋值,确定定时器Timer0 和 Timer1 的工作模式

  • 2.根据要定时的时间来计算好初值,并对THx、TLx赋值

  • 3.配置寄存器TCON,开启定时器Timer0 / Timer1的中断

  • 4.对TR0 / TR1置1,启动定时器

接下来以12MHz晶振,使用定时器0来产生中断,控制LED灯间隔1秒闪烁:

#include<reg51.h>
sbit LED = P1^1; //定义LED引脚
void timer0_init() //定时器0初始化函数
{
 TMOD = 0x01; //选择定时器0为工作模式1
 TH0 = 64536/256;
 TL0 = 64536%256; //定时1ms的TH,TL值
 EA = 1; //开启总中断开关
 ET0 = 1; //开启定时器0中断开关
 TR0 = 1; //置1开始计时,为0停止计时
}
void main()
{
 timer0_init();
 while(1);

}

void timer0_ISR() interrupt 1
{
 static unsigned int i=0; //定义静态变量
 TH0 = 64536/256;
 TL0 = 64536%256; //对TH,TL初值重装
 i++;
   if(i==1000) //经过了1000次中断,即1s
   {
    i=0;
    LED=!LED; //LED间隔闪烁
   }
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐