【Protues仿真】定时器

目录

[0 基础知识](#0 基础知识)

[1.1 AT89C52的3个定时器](#1.1 AT89C52的3个定时器)

[1.2定时器在单片机里的 4 大作用](#1.2定时器在单片机里的 4 大作用)

[1.3 四种工作方式(T0/T1)](#1.3 四种工作方式(T0/T1))

[1.4使用步骤(以T0方式12 MHz 晶振产生 1 ms 中断为例)](#1.4使用步骤(以T0方式12 MHz 晶振产生 1 ms 中断为例))

[1.4.1 算初值计算](#1.4.1 算初值计算)

[1.4.2 寄存器配置](#1.4.2 寄存器配置)

1.5完整例子1------小灯闪烁1S

[1.5.1 电路原理图](#1.5.1 电路原理图)

[1.5.2 控制程序](#1.5.2 控制程序)

[1.5.3 小灯的输入电压实时检测](#1.5.3 小灯的输入电压实时检测)

[1.6 T2 简要补充(8052 专有)](#1.6 T2 简要补充(8052 专有))

1.7一句话总结

[1.8 定时器T0延时实现](#1.8 定时器T0延时实现)

[1.8.1 定时器T0的基本原理](#1.8.1 定时器T0的基本原理)

[1.8.2 定时器T0的初始化](#1.8.2 定时器T0的初始化)

[1.8.3 定时器T0实现延时函数](#1.8.3 定时器T0实现延时函数)

[1.8.4 代码说明](#1.8.4 代码说明)

[1.8.5 定时器T0模式1中的TF0](#1.8.5 定时器T0模式1中的TF0)

[1.9 阻塞式延时实现](#1.9 阻塞式延时实现)

[1.9.1 延时时间估算(假设12MHz晶振)](#1.9.1 延时时间估算(假设12MHz晶振))

[1.9.2 阻塞式延时程序//1ms](#1.9.2 阻塞式延时程序//1ms)

[1.9.3 详细解释](#1.9.3 详细解释)

[1.10 完整例子2------流水灯](#1.10 完整例子2——流水灯)

[1.10.1 电路原理图](#1.10.1 电路原理图)

[1.10.2 控制程序](#1.10.2 控制程序)


**摘要:**本文系统介绍了AT89C52单片机的定时器应用,重点讲解了T0/T1/T2三个定时器的工作原理及使用方法。主要内容包括:1. 定时器基础概念:机器周期计算、四种工作方式及应用场景;2. 定时器配置方法:以12MHz晶振产生1ms中断为例,详细说明初值计算和寄存器配置步骤;3. 两种延时实现方式:通过定时器中断和阻塞式循环,分别给出LED闪烁和流水灯的应用实例;4. 特殊功能补充:8052专有的T2定时器的自动重装、捕获等高级功能。文中配有完整的电路原理图和控制程序,通过对比分析帮助读者掌握定时器的核心应用技巧,实现精确计时和高效控制。

0 基础知识

频率单位:赫兹(Hz)

1 赫兹(Hz) :每秒1 周期:1s

1 千赫兹(Hz) :每秒1000 周期:1ms

1 兆赫兹(Hz) :每秒1000000 周期:1us

1 吉兹(Hz) :每秒1000000000 周期:1ns

机器周期(Machine Cycle)是 8051 单片机 执行一条指令的基本时间单位。理解它对于计算延时、定时器初值、波特率等都非常关键。

总结:

8051 的机器周期 = 12 × 时钟周期
12MHz 晶振下,1 机器周期 = 1μs

1.1 AT89C52的3个定时器

3个16位可编程定时/计数器:T0、T1、T2

T0、T1:标准 8051 兼容(方式 0~3)

T2:8052 专有,功能更强(可 16 位自动重装、捕获、波特率发生等)

1.2定时器在单片机里的 4 大作用

产生精确定时(1 ms、10 ms、1 s......)

对外部脉冲计数(T0/T1 脚当计数输入)

生成波特率(UART 方式 1、3 时)

做PWM/脉冲测量/电机测速(配合 T2 捕获功能)

1.3 四种工作方式(T0/T1)

|--------|-------------|---------|---------------|
| 方式 | 位数 | 特点 | 典型用途 |
| 0 | 13 位 | 早期兼容,少用 | 特殊场合 |
| 1 | 16 位 | 一次溢出重装 | 1 ms、50 ms 基时 |
| 2 | 8 位自动重装 | 低字节自动回装 | 波特率、高频中断 |
| 3 | T0 分成两个 8 位 | T1 失去中断 | 特殊应用 |

1.4使用步骤(以T0方式12 MHz 晶振产生 1 ms 中断为例)

1.4.1 算初值计算

机器周期 = 1 µs(12 MHz/12)

1 ms 需计数 1000 次 → 初值 = 65536 − 1000 = 64536 = 0xFC18

定时器T0 设置

TMOD &= 0xF0; // 清零 T0 位

TMOD |= 0x01; // T0 方式 1

定时周期(1ms)

TH0 = 0xFC; // 高 8 位

TL0 = 0x18; // 低 8 位

1.4.2 寄存器配置

定时器T0

TMOD &= 0xF0; // 清零 T0 位

TMOD |= 0x01; // T0 方式 1

TH0 = 0xFC; // 高 8 位

TL0 = 0x18; // 低 8 位

TR0 = 1; // 启动 T0

ET0 = 1; // 允许中断

EA = 1; // 总中断

定时器T0 中断服务函数

void Timer0_ISR(void) interrupt 1

{

TH0 = 0xFC; // 重装初值

TL0 = 0x18;

/* 用户代码:计数、刷新显示、产生 PWM 等 */

}

1.5完整例子1------小灯闪烁1S

1.5.1 电路原理图

电路原理图由AT89C52单片机、示波器、LED电路、复位电路和晶振电路组成,实现P1.0 引脚上的 LED 每 1 秒翻转一次,简单地说就是 1 Hz 的闪烁。

1.5.2 控制程序

定时器T0 实现延时方法1

objectivec 复制代码
//头文件与位定义
#include <reg52.h>
sbit LED = P1^0;
unsigned int cnt = 0;
//定时器0初始化
void inittimer()
{
    TMOD = 0x01;//设置定时器0为模式1(16位定时器) 
    TH0  = 0xFC;//高8位 定时器周期1 ms
    TL0  = 0x18;//低8位 定时器周期1 ms
    TR0  = 1;//启动定时器0
	ET0 = 1;// 允许定时器0中断
	EA = 1;// 打开总中断 
}
//主函数
void main()
{
inittimer();//初始化定时器
    while(1);//死循环
}
//定时器0中断服务函数
void Timer0_ISR() interrupt 1
{
TH0 = 0xFC; 
TL0 = 0x18;// 定时器周期1 ms
//小灯闪烁
    if(++cnt >= 1000)   // 1000 × 1 ms = 1 s
    {
        cnt = 0;
        LED = ~LED;     // LED 翻转
    }
}

定时器实现延时方法2

objectivec 复制代码
//头文件与位定义
#include <reg52.h>
sbit LED = P1^0;
// 定时器T0初始化函数
void Timer0_Init()
{
    TMOD |= 0x01;  // 设置定时器T0为模式1(16位定时器)
    TH0 = (65536 - 50000) / 256;  // 设置定时器初值(高8位)
    TL0 = (65536 - 50000) % 256;  // 设置定时器初值(低8位)
    ET0 = 1;  // 开启定时器T0中断
    EA = 1;   // 开启全局中断
    TR0 = 1;  // 启动定时器T0
}
// 定时器T0中断服务函数
void Timer0_ISR() interrupt 1
{
    TH0 = (65536 - 50000) / 256;  // 重新加载初值(高8位)
    TL0 = (65536 - 50000) % 256;  // 重新加载初值(低8位)
    // 在这里可以添加需要在定时器中断中执行的代码
}
// 延时函数
void Delay(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
    }
}
void main()
{
    Timer0_Init();  // 初始化定时器T0
    while (1)
{
   LED=1;
        Delay(1000);  // 延时1000ms
         LED=0;
        Delay(1000);  // 延时1000ms
    }
}

1.5.3 小灯的输入电压实时检测

由示波器检测实时电压可知,定时器(T0)中断服务函数实现1秒高低电平的切换。

1.6 T2 简要补充(8052 专有)

寄存器:T2CON、T2MOD、RCAP2H/L

功能:

16 位自动重装(比 T0/T1 方式 2 更宽)

捕获(测量脉冲宽度)

波特率发生器(UART 方式 1/3)

可编程时钟输出(P1.0 输出 50% 方波)

1.7一句话总结

AT89C52 的定时器 = "硬件计数/分频器 + 中断"

只要配置好初值、工作方式、中断,就能让 CPU 从"空转延时"里解放出来,去做更实时、更精确的事情。

1.8 定时器T0延时实现

AT89C52单片机是一款经典的8位单片机,它内部有定时器T0和T1,可以通过定时器实现精确的延时功能。

1.8.1 定时器T0的基本原理

定时器模式:定时器T0可以工作在模式0(13位定时器)、模式1(16位定时器)、模式2(8位自动重装载定时器)和模式3(拆分为两个独立的8位定时器)。

定时原理:定时器通过内部的计数器来实现延时。当计数器从初始值计数到溢出值时,产生一个溢出中断(如果中断使能)或可以通过查询标志位来判断是否达到延时。

1.8.2 定时器T0的初始化

在使用定时器T0之前,需要进行初始化,设置定时器的工作模式、初始值等参数。

1.8.3 定时器T0实现延时函数

objectivec 复制代码
#include <reg52.h>  // 包含AT89C52的寄存器定义
// 定时器T0初始化函数
void Timer0_Init()
{
    TMOD |= 0x01;  // 设置定时器T0为模式1(16位定时器)
    TH0 = (65536 - 50000) / 256;  // 设置定时器初值(高8位)
    TL0 = (65536 - 50000) % 256;  // 设置定时器初值(低8位)
    ET0 = 1;  // 开启定时器T0中断
    EA = 1;   // 开启全局中断
    TR0 = 1;  // 启动定时器T0
}
// 定时器T0中断服务函数
void Timer0_ISR() interrupt 1
{
    TH0 = (65536 - 50000) / 256;  // 重新加载初值(高8位)
    TL0 = (65536 - 50000) % 256;  // 重新加载初值(低8位)
    // 在这里可以添加需要在定时器中断中执行的代码
}
// 延时函数
void Delay(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
    }
}
void main()
{
    Timer0_Init();  // 初始化定时器T0
    while (1)
    {
        Delay(1000);  // 延时1000ms
        // 在这里可以添加需要在主循环中执行的代码
    }
}

1.8.4 代码说明

定时器初值:在模式1下,定时器是16位的,最大计数值为65536。如果需要延时50ms,假设单片机的时钟频率为12MHz,机器周期为1μs,那么50ms对应的计数值为50000。因此,定时器的初值为65536 - 50000 = 15536,分别加载到TH0和TL0中。

中断服务函数:在定时器中断服务函数中,重新加载初值,以实现周期性定时。

延时函数:通过循环等待定时器溢出标志TF0来实现延时。

1.8.5 定时器T0模式1中的TF0

在AT89C52单片机中,定时器T0在模式1(16位定时器模式)下,溢出标志TF0的行为和作用是至关重要的。

1. 模式1 的特性

16 位定时器:模式1是一个16位定时器,可以计数从0到65535(0xFFFF)。

初值设置:通过设置TH0(高8位)和TL0(低8位)来设置定时器的初始值。

溢出条件:当定时器从初始值计数到65535时,溢出标志TF0会被硬件自动置位。

2. 溢出标志TF0 的位置

TF0位于定时器控制寄存器TCON中,具体位置如下:

TCON 寄存器:地址为0x88,是一个8位寄存器,用于控制和指示定时器的状态。

TF0:是TCON寄存器的第7位(最高位),即TCON的第7位。

3. TF0 的作用

溢出标志:当定时器T0从其初始值计数到65535时,TF0会被硬件自动置位(变为1)。

中断请求:如果定时器T0的中断使能位ET0被设置为1,并且全局中断使能位EA也被设置为1,那么TF0置位时会触发一个中断请求。

查询标志:在非中断模式下,可以通过查询TF0的状态来判断定时器是否已经溢出。

4. 清除TF0

TF0可以通过以下两种方式清除:

硬件清除:当定时器T0的中断被响应时,TF0会被硬件自动清除。

软件清除:可以通过软件将TF0清零。例如:TF0 = 0; // 清除定时器T0溢出标志

5. 示例代码

完整的示例代码:如何在模式1 下使用TF0 来实现延时功能。

objectivec 复制代码
#include <reg52.h>  // 包含AT89C52的寄存器定义
// 定时器T0初始化函数
void Timer0_Init()
{
    TMOD |= 0x01;  // 设置定时器T0为模式1(16位定时器)
    TH0 = (65536 - 50000) / 256;  // 设置定时器初值(高8位)
    TL0 = (65536 - 50000) % 256;  // 设置定时器初值(低8位)
    TR0 = 1;  // 启动定时器T0
}

// 延时函数
void Delay(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
        TH0 = (65536 - 50000) / 256;  // 重新加载初值(高8位)
        TL0 = (65536 - 50000) % 256;  // 重新加载初值(低8位)
    }
}

void main()
{
    Timer0_Init();  // 初始化定时器T0
    while (1)
    {
        Delay(1000);  // 延时1000ms
        // 在这里可以添加需要在主循环中执行的代码
    }
}

6. 代码说明

初始化:在Timer0_Init函数中,设置定时器T0为模式1,并加载初始值。

延时函数:在Delay函数中,通过循环等待TF0置位来实现延时。每次TF0置位后,清除TF0,并重新加载定时器初值。

主循环:在主循环中调用Delay函数,实现周期性延时

1.9 阻塞式延时实现

1.9.1 延时时间估算(假设12MHz晶振)

AT89C52的一个机器周期 = 12个时钟周期 = 1μs(12MHz晶振下)

for(j=0;j<500;j++); 大约消耗 500× 2 ≈ 1000 个机器周期1000μs

外层循环 n 次,总延时 ≈ n × 1000μs

1.9.2 阻塞式延时程序//1ms

objectivec 复制代码
void delay(uint n)
{
    uint i = 0, j = 0;
    for(i = 0; i < n; i++)
    {
        for(j = 0; j <500; j++);  // 空循环
    }
}

1.9.3 详细解释

1. 8051 的时钟结构:

晶振频率:外部晶振(如 12MHz、11.0592MHz)

时钟周期 = 1 / 晶振频率

例如:12MHz → 1/12μs ≈ 83.33ns

机器周期 = 12 × 时钟周期

因为 8051 把 12 个时钟周期定义为 1 个机器周期

2. 举个例子(12MHz ):

|--------|------------|----------|
| 名称 | 计算方式 | 时间长度 |
| 时钟周期 | 1 / 12MHz | ≈ 83 ns |
| 机器周期 | 12 × 83 ns | 1 μs |
| 指令周期 | 1~4 个机器周期 | 1~4 μs |

3. 实际应用:

定时器初值计算: 如果你想让定时器每 1ms 中断一次:

1000μs / 1μs = 1000 个机器周期

初值 = 65536 - 1000 = 64536

TH0 = 64536 / 256

TL0 = 64536 % 256

1.4 注意

这是阻塞式延时,CPU 不能做其他事情。

如果你用了11.0592MHz 晶振,延时时间会略有不同。

1.10 完整例子2------流水灯

1.10.1 电路原理图

电路原理图由AT89C52单片机、流水灯电路、复位电路和晶振电路组成,实现P1.0~P1.7引脚上的 LED 每 1 秒轮流闪烁一次,其中流水灯为共阴极接法。

1.10.2 控制程序

1 、通过定时器T0 实现延时函数实现

objectivec 复制代码
//头文件与位定义
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
//定时器T0初始化
void inittimer()
{
    TMOD = 0x01;//设置定时器0为模式1(16位定时器) 
    TH0  = 0xFC;//高8位 定时器周期1 ms
    TL0  = 0x18;//低8位 定时器周期1 ms
    TR0  = 1;//启动定时器0
	ET0 = 1;// 允许定时器0中断
	EA = 1;// 打开总中断 
}
//延时函数
void Delay(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
    }
}//主函数
void main (void)
{
inittimer();//初始化定时器
	uchar i,temp;
//P1.0->P1.7依次点亮---> P1.7->P1.0依次点亮 照此一直循环
	while(1)
	{
// P1.0->P1.7依次点亮
		temp=0x01;
		for(i=0;i<8;i++)//左移循环
		{
			delay(500);
			temp=temp<<1;//左移一位
		}
// P1.7->P1.0依次点亮
		temp=0x80;
		for(i=0;i<8;i++)//右移循环
		{
			delay(500);
			temp=temp>>1;//右移移位
		}
	}
}
//定时器0中断服务函数
void Timer0_ISR() interrupt 1
{
TH0 = 0xFC; 
TL0 = 0x18;// 定时器周期1 ms
}

2 通过阻塞式延时函数实现

objectivec 复制代码
//头文件与位定义
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
//延时函数
void delay(uint n)
{
	uchar i;
	uint j;
	for(j=0;j<n;j++)
	for(i=0;i<123;i++);
}
//主函数
void main (void)
{
	uchar i,temp;
	while(1)
	{
		temp=0x01;
		for(i=0;i<8;i++)//左移循环
		{
			delay(500);
			temp=temp<<1;//左移一位
		}
		temp=0x80;
		for(i=0;i<8;i++)//右移循环
		{
			delay(500);
			temp=temp>>1;//右移移位
		}
	}
}

通过移位运算实现引脚P1的电平变化从而实现流水灯功能,通过定时器或阻塞式实现延时函数。

相关推荐
小小少年1231 小时前
基于51单片机的DS18B20大棚温度监控系统
stm32·单片机·嵌入式硬件
北极有牛2 小时前
keil添加文件夹
单片机
JasmineX-16 小时前
STM32的Sg90舵机
c语言·stm32·单片机·嵌入式硬件
不爱学英文的码字机器8 小时前
[CS创世SD NAND征文] CS创世CSNP1GCR01-AOW在运动控制卡中的高可靠应用
人工智能·嵌入式硬件·物联网·iot
机器视觉知识推荐、就业指导8 小时前
STM32 外设驱动模块九:TB6612FNG 电机驱动模块
stm32·单片机·嵌入式硬件
清风66666615 小时前
基于STM32单片机的二维码识别物联网OneNet云仓库系统
stm32·单片机·物联网·毕业设计·课程设计
猫猫的小茶馆18 小时前
【STM32】CubeMX(十二):FreeRTOS消息队列
驱动开发·stm32·单片机·嵌入式硬件·mcu·智能硬件
李永奉1 天前
51单片机-驱动步进电机模块教程
单片机·嵌入式硬件·51单片机
李永奉1 天前
51单片机-实现定时器模块教程
单片机·嵌入式硬件·51单片机