当前位置: 首页 > backend >正文

【Protues仿真】定时器

目录

0 基础知识

1.1 AT89C52的3个定时器

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

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

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

1.4.1 算初值计算

1.4.2 寄存器配置

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

1.5.1 电路原理图

1.5.2 控制程序

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

1.6 T2 简要补充(8052 专有)

1.7一句话总结

1.8 定时器T0延时实现

1.8.1 定时器T0的基本原理

1.8.2 定时器T0的初始化

1.8.3 定时器T0实现延时函数

1.8.4 代码说明

1.8.5 定时器T0模式1中的TF0

1.9 阻塞式延时实现

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

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

1.9.3 详细解释

1.10 完整例子2——流水灯

1.10.1 电路原理图

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

//头文件与位定义
#include <reg52.h>
sbit LED = P1^0;
unsigned int cnt = 0;
//定时器0初始化
void inittimer()
{TMOD = 0x01;//设置定时器0为模式1(16位定时器) TH0  = 0xFC;//高8位 定时器周期1 msTL0  = 0x18;//低8位 定时器周期1 msTR0  = 1;//启动定时器0ET0 = 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

//头文件与位定义
#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();  // 初始化定时器T0while (1)
{LED=1;Delay(1000);  // 延时1000msLED=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实现延时函数

#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();  // 初始化定时器T0while (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来实现延时功能。

#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();  // 初始化定时器T0while (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

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实现延时函数实现

//头文件与位定义
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
//定时器T0初始化
void inittimer()
{TMOD = 0x01;//设置定时器0为模式1(16位定时器) TH0  = 0xFC;//高8位 定时器周期1 msTL0  = 0x18;//低8位 定时器周期1 msTR0  = 1;//启动定时器0ET0 = 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 通过阻塞式延时函数实现

//头文件与位定义
#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的电平变化从而实现流水灯功能,通过定时器或阻塞式实现延时函数。

http://www.xdnf.cn/news/18784.html

相关文章:

  • 构建智能提示词工程师:LangGraph 的自动化提示词生成流程
  • [在实践中学习] 中间件理论和方法--Redis
  • WPF基于LiveCharts2图形库,实现:折线图,柱状图,饼状图
  • Python爬虫实战:研究开源的高性能代理池,构建电商数据采集和分析系统
  • Pycharm
  • ​告别复杂计划!日事清推出脑图视图,支持节点拖拽与聚焦模式,让项目管理更直观​
  • MySQL 入门
  • 虚幻5引擎:我们是在创造世界,还是重新发现世界?
  • 基于SpringBoot的摄影跟拍约拍预约系统【2026最新】
  • [CS创世SD NAND征文] CS创世CSNP1GCR01-AOW在运动控制卡中的高可靠应用
  • 神经网络参数量计算详解
  • 如何用企业微信AI解决金融运维难题,让故障响应快、客服专业度高
  • EB_NXP_K3XX_GPIO配置使用
  • 深入理解内存屏障(Memory Barrier):现代多核编程的基石
  • Java大厂面试实战:从Spring Boot到微服务架构的全链路技术拆解
  • 破解VMware迁移难题的技术
  • 给高斯DB写一个函数实现oracle中GROUPING_ID函数的功能
  • 性能瓶颈定位更快更准:ARMS 持续剖析能力升级解析
  • Docker Compose 使用指南 - 1Panel 版
  • NR --PO计算
  • nginx代理 flink Dashboard、sentinel dashboard的问题
  • 数据结构(时空复杂度)
  • 论文阅读(四)| 软件运行时配置研究综述
  • 推荐系统学习笔记(十四)-粗排三塔模型
  • iOS 审核 4.3a【二进制加固】
  • Web前端开发基础
  • sdi开发说明
  • Python在语料库建设中的应用:文本收集、数据清理与文件名管理
  • WebSocket简单了解
  • HIVE的高频面试UDTF函数