04:定时器

news/2025/2/11 22:17:06/

定时器

  • 1、定时器如何定时
  • 2、寄存器简介
  • 3、定时器定时
    • 实验①
    • 实验②
  • 4、定时器中断
    • 实验③
    • 实验④
  • 5、定时器计数功能
    • 实验⑤
    • 实验⑥

1、定时器如何定时

通过晶振(晶体振荡器)发出脉冲,记录分频后的脉冲的个数来进行定时。51单片机的定时器时钟源分频系数为6T和12T。在下载器的STC-ISP中选择。默认为12T(12分频)。

在这里插入图片描述

在这里插入图片描述
如图:51单片机的晶振为12MHz,经过12T后变为1MHz,则时钟周期为1S/(1M) = 1(us),即定时器的计时器每隔1(us)进行+1。当定时器的计数器使用16位时,最大计数为65536。所以定时器最长定时时间为65536 * 1(us) = 65536(us) = 65.536ms

2、寄存器简介

在这里插入图片描述在这里插入图片描述

综上:若12T下需要定时1ms(即定时器启动,1ms后定时器溢出标志位置位),那么定时器T0的计数器的初值应该设置为多少喃?

1ms = 1000us,即65536 - 1000 = 64536。定时计数器T0的初值应该设置为64536,即定时计时器从64536开始计数。
TH0 = 64536 >> 8;
TL0 = 64536 & 0x00FF
定时器溢出后,计数器从0开始向65535计数。

3、定时器定时

实验①

实验:使用T0,定时器定时10ms,轮询式让LED每隔1s闪烁

①Time.c文件的代码如下:

#include "Time.h"/*** 定时器T0的初始化*/
void Time0_Init(void)
{/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */TMOD &= 0xF0;			//将低4位置0TMOD |= 0x01;			//最低位置1/* 设置定时计数器的初始值,定时10ms */TH0 = ((65536 - 10000) >> 8);TL0 = (65536 - 10000) & 0x00FF;/* 启动T0 */TF0 = 0;				//清除标志位TR0 = 1;				//启动定时器0
}

②Time.h文件的代码如下:

#ifndef __Time_H
#define __Time_H
#include <reg51.h>		//包含51头文件,里面全是寄存器地址>void Time0_Init(void);#endif

③main.c文件的代码如下:

#include "Time.h"
#include "LED.h"void main(void)
{unsigned char Num = 0;Time0_Init();			//定时器10mswhile(1){if(TF0 == 1)		//10ms定时器到了{TF0 = 0;		//清除标志位/* 重新设置定时计数器的初始值,定时10ms */TH0 = ((65536 - 10000) >> 8);TL0 = (65536 - 10000) & 0x00FF;Num++;if(Num == 100)	//定时1s到了{Num = 0;LED_Turn(1);//翻转LED1}}}
}

实验②

实验:使用T0构造延时函数,让LED每隔1s闪烁
①Time.c文件的代码如下:

#include "Time.h"/*** 使用T0构造延时函数*/
void Delay_ms(unsigned short second)
{/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */TMOD &= 0xF0;			//将低4位置0TMOD |= 0x01;			//最低位置1/* 设置定时计数器的初始值,定时1ms */TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 启动T0 */TF0 = 0;				//清除标志位TR0 = 1;/* 循环等待 */while(second){if(TF0 == 1){TF0 = 0;		//清除标志位--second;		//每隔1ms进行减1/* 设置定时计数器的初始值,定时1ms */TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;}}TR0 = 0;				//关闭定时器
}

②Time.h文件的代码如下:

#ifndef __Time_H
#define __Time_H
#include <reg51.h>		//包含51头文件,里面全是寄存器地址>void Delay_ms(unsigned short second);#endif

③main.c文件的代码如下:

#include "Time.h"
#include "LED.h"void main(void)
{while(1){Delay_ms(1000);LED_Turn(1);}
}

4、定时器中断

实验③

实验:使用T0,定时器定时1s,轮询式让LED每隔1s闪烁
①Time.c文件的代码如下:

#include "Time.h"/*** 定时器T0的初始化,且开启中断*/
void Time0It_Init(void)
{/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */TMOD &= 0xF0;			//将低4位置0TMOD |= 0x01;			//最低位置1/* 设置定时计数器的初始值,定时10ms */TH0 = ((65536 - 10000) >> 8);TL0 = (65536 - 10000) & 0x00FF;/* 启动T0 */TF0 = 0;				//清除标志位TR0 = 1;/* 开启中断 */ET0 = 1;				//使能定时器溢出中断EA = 1;					//开启总开关
}/********中断服务函数*******/
/*** T0的中断服务函数(每隔10ms对Number加1,Number加到100,相当于隔了1s,在执行LED翻转)*/
static unsigned char Number = 0;
void Time0_Rountine(void) interrupt 1
{//这里不用清除标志位,硬件会自动清除TH0 = ((65536 - 10000) >> 8);TL0 = (65536 - 10000) & 0x00FF;Number++;if(Number == 100){Number = 0;LED_Turn(1);//翻转LED}
}

②Time.h文件的代码如下:

#ifndef __Time_H
#define __Time_H
#include <reg51.h>		//包含51头文件,里面全是寄存器地址>
#include "LED.h"void Time0It_Init(void);#endif

③main.c文件的代码如下:

#include "Time.h"
#include "LED.h"void main(void)
{Time0It_Init();			//定时器10mswhile(1){}
}

在这里插入图片描述

实验④

实验:
①使用T0中断,定时器定时1s,让数码管从60每隔1s减1,减到0后重新变为60,并且每次数值变化,LED就翻转一次

②使用T0中断每隔1ms对数码管进行刷新显示
①Time.c文件的代码如下:

#include "Time.h"/*** 定时器T0的初始化,且开启中断*/
void Time0It_Init(void)
{/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */TMOD &= 0xF0;			//将低4位置0TMOD |= 0x01;			//最低位置1/* 设置定时计数器的初始值,定时1ms */TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 启动T0 */TF0 = 0;				//清除标志位TR0 = 1;/* 开启中断 */ET0 = 1;				//使能定时器溢出中断EA = 1;					//开启总开关
}/********中断服务函数*******/
/*** T0的中断服务函数(刷新数码管显示,执行每隔1s数值+1,且LED的翻转)*/
static unsigned short Number = 0;
static unsigned char Counter1 = 0;
void Time0_Rountine(void) interrupt 1
{//这里不用清除标志位,硬件会自动清除TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 计数:累加时间,等隔1s后在执行 */Number++;				//每隔1ms加1if(Number == 1000)		//1s了{Number = 0;Counter1++;if(Counter1 > 60){Counter1 = 0;}LED_Turn(1);		//LED翻转}/* 每隔1ms就刷新显示数码管 */Show_Num(Counter1);		//注意将此函数的延时函数取消
}

②Time.h文件的代码如下:

#ifndef __Time_H
#define __Time_H
#include <reg51.h>		//包含51头文件,里面全是寄存器地址>
#include "LED.h"
#include "User_Seg.h"void Time0It_Init(void);#endif

③main.c文件的代码如下:

#include "Time.h"void main(void)
{Time0It_Init();	//启动定时器0while(1){}
}

在这里插入图片描述

综上:使用上面的定时器中断精髓在于,使用Number++;//每隔1ms加1,if(Number == 1000)//1s了,再去执行if里面的函数,这样相当于无形的构造了一个1s的定时器中断函数

5、定时器计数功能

定时器的计数功能就是记录外部脉冲信号的个数,此时定时器不在使用内部晶振时钟源。则寄存器TMOD中的C/T位应该置1,如下图所示:
在这里插入图片描述

实验⑤

实验:
①使用定时器T1对外部脉冲信号进行计数,并通过数码管显示出来
②并测量出脉冲信号的频率,并通过数码管显示出来
③使用外部中断0,按键切换数码管的显示界面(显示测量的脉冲个数/脉冲频率)

在这里插入图片描述
在这里插入图片描述

①Time.c文件的代码如下:

#include "Time.h"/*** 定时器T0的初始化,且开启中断*/
void Time0It_Init(void)
{/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */TMOD &= 0xF0;			//将低4位置0TMOD |= 0x01;			//最低位置1/* 设置定时计数器的初始值,定时1ms */TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 启动T0 */TF0 = 0;				//清除标志位TR0 = 1;/* 开启中断 */ET0 = 1;				//使能定时器溢出中断EA = 1;					//开启总开关
}/*** 定时器T1的初始化,用作计数器测量外部脉冲个数*/
void Time1_Init(void)
{/* 设置T1的计数器为16,且时钟来源为外部 TMOD = 0101 xxxx */TMOD &= 0x0F;			//将高4位置0TMOD |= 0x50;			//高4位为0101/* 设置定时计数器的初始值为0 */TH1 = 0;TL1 = 0;/* 启动T1*/TF1 = 0;				//清除标志位TR1 = 1;
}/********中断服务函数*******/
/*** T0的中断服务函数(刷新显示数码管)*/
static unsigned short Number = 0;
static unsigned short Freq = 0;
static unsigned int Data = 0;
extern unsigned char Flag;
void Time0_Rountine(void) interrupt 1
{//这里不用清除标志位,硬件会自动清除TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 计数:累加时间,等隔1s后在执行 */Number++;				//每隔1ms加1if(Number == 1000)		//1s了{/* 测频率法:得出脉冲频率 */Data = (TH1 << 8) + TL1;Freq = Data - Freq; 			//脉冲频率}/* 每隔1ms就刷新显示数码管 */switch(Flag % 2)					//外部中断改变Flag的状态值{case 0:LED_On(1);					//LED1点亮Show_Num((TH1 << 8) + TL1);	//显示脉冲信号个数break;case 1:LED_OFF(1);					//LED1熄灭Show_Num(Freq);				//显示脉冲信号频率break;default:break;}
}

②Time.h文件的代码如下:

#ifndef __Time_H
#define __Time_H
#include <reg51.h>		//包含51头文件,里面全是寄存器地址>
#include "User_Seg.h"
#include "LED.h"void Time0It_Init(void);
void Time1_Init(void);#endif

③EXTI.c文件的代码如下:

#include "EXTI.h"/*** 外部中断INT0的初始化(下降沿触发)*/
void INT0_Init(void)
{IT0 = 1; 	//下降沿触发标志位EX0 = 1;	//IN0中断使能EA = 1;		//中断总开关	
}/*** 外部中断INT1的初始化(下降沿触发)*/
void INT1_Init(void)
{IT1 = 1; 	//下降沿触发标志位EX1 = 1;	//IN1中断使能EA = 1;		//中断总开关
}/*************中断服务函数******************/
/*** 外部中断0的服务函数*/
unsigned char Flag = 0;
void Int0_Routine(void) interrupt 0
{Flag++;		//改变Flag的值,用于切换数码管的显示状态if(Flag == 2){Flag = 0;//防止Flag数值溢出}
}/*** 外部中断1的服务函数*/
void Int1_Routine(void) interrupt 2
{LED_OFF(1);	//熄灭LED
}

④main.c文件的代码如下:

#include "Time.h"
#include "EXTI.h"void main(void)
{Time1_Init();		//计数器1初始化Time0It_Init();		//定时器0初始化INT0_Init();		//外部中断0初始化while(1){}
}

在这里插入图片描述
综上:代码代码得出频率是使用的测频法,即在1s内测量出脉冲的个数即为频率,此方法适用于高频信号。若信号频率较低,则使用测周法,即测量周期的时间,继而转换为频率。

实验⑥

使用测周法测量信号发生器产生的频率,并通过数码管显示出来

信号发生器连接到外部中断引脚,当信号由高电平变为低电平时,触发外部中断,在外部中断服务函数里面获取定时器T1的计数器的值,通过T1计数器的值得出周期。

①Time.c文件的代码如下:

#include "Time.h"/*** 定时器T0的初始化,且开启中断*/
void Time0It_Init(void)
{/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */TMOD &= 0xF0;			//将低4位置0TMOD |= 0x01;			//最低位置1/* 设置定时计数器的初始值,定时1ms */TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 启动T0 */TF0 = 0;				//清除标志位TR0 = 1;/* 开启中断 */ET0 = 1;				//使能定时器溢出中断EA = 1;					//开启总开关
}/*** 定时器T1的初始化,用作计数器测量外部脉冲个数*/
void Time1_Init(void)
{/* 设置T1的计数器为16,且时钟来源为晶振 TMOD = 0001 xxxx */TMOD &= 0x0F;			//将高4位置0TMOD |= 0x10;			//高4位为0001/* 设置定时计数器的初始值为0 */TH1 = 0;TL1 = 0;/* 启动T1 */TF1 = 0;				//清除标志位TR1 = 1;
}/********中断服务函数*******/
/*** T0的中断服务函数*/
extern unsigned int Freq;	//频率
void Time0_Rountine(void) interrupt 1
{//这里不用清除标志位,硬件会自动清除TH0 = ((65536 - 1000) >> 8);TL0 = (65536 - 1000) & 0x00FF;/* 数码管显示频率值 */Show_Num(Freq);
}

②Time.h文件的代码如下:

#ifndef __Time_H
#define __Time_H
#include <reg51.h>		//包含51头文件,里面全是寄存器地址>
#include "User_Seg.h"void Time0It_Init(void);
void Time1_Init(void);#endif

③EXTI.c文件的代码如下:

#include "EXTI.h"/*** 外部中断INT0的初始化(下降沿触发)*/
void INT0_Init(void)
{IT0 = 1; 	//下降沿触发标志位EX0 = 1;	//IN0中断使能EA = 1;		//中断总开关	
}/*************中断服务函数******************/
/*** 外部中断0的服务函数*/
unsigned int Freq = 0;
extern unsigned int timeVlau;
void Int0_Routine(void) interrupt 0
{TR1 = 0;//关闭定时器T1/* 获取定时器的计数器的值 */Freq = 1000000 / (((TH1 << 8) + TL1) + timeVlau * 65535);/* 将定时器中的计数器清0 */TH1 = 0;TL1 = 0;timeVlau = 0;TR1 = 1;//开启定时器T1
}

④main.c文件的代码如下:

#include "Time.h"
#include "EXTI.h"unsigned int timeVlau = 0;
void main(void)
{Time1_Init();	Time0It_Init();INT0_Init();while(1){if(TF1 == 1){TF1 = 0;timeVlau++;}}
}

在这里插入图片描述


http://www.ppmy.cn/news/1571262.html

相关文章

cpp--实战项目,list的模拟实现,注释超详细!

list的模拟实现 list的模拟实现list.htest.cpp list的模拟实现 相信大家看完我的这篇有关list使用的博客cpp–list的介绍及使用&#xff0c;一看就会&#xff01;之后对于list类的基本使用有了一定的了解&#xff0c;如果大家想对于list的底层有所了解&#xff0c;就可以看看我…

Java爬虫获取微店店铺所有商品API接口设计与实现

一、引言 在当今的互联网时代&#xff0c;电商平台的数据对于商家、市场分析师以及消费者来说都具有巨大的价值。微店作为一个知名的电商平台&#xff0c;拥有海量的商品信息。通过爬虫技术获取微店店铺的所有商品信息&#xff0c;不仅可以帮助商家更好地了解竞争对手&#xf…

基于SpringBoot1de1宠物猫认养系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

探寻制造型企业MES管理系统:功能、架构与应用全解析

在当今制造业蓬勃发展的背景下&#xff0c;制造执行MES系统对于制造型企业的高效运营起着举足轻重的作用。MES管理系统作为连接企业上层管理与底层生产的关键桥梁&#xff0c;其功能模块设计、架构搭建、系统集成以及实际应用都对企业的生产效能和竞争力有着深远影响。 一、MES…

Oracle中与 NLS(National Language Support,国家语言支持) 相关的参数

在Oracle中&#xff0c;NLS_DATABASE_PARAMETERS 和 NLS_INSTANCE_PARAMETERS 是两个重要的视图&#xff0c;用于存储与 NLS&#xff08;National Language Support&#xff0c;国家语言支持&#xff09; 相关的参数。它们的作用和区别如下&#xff1a; 1. NLS_DATABASE_PARAME…

301.华为交换机堆叠技术基础

华为交换机堆叠技术基础 一、概念及原理部分1.堆叠简介1.1 什么是堆叠1.2 可靠性网络架构1.3 华为堆叠设备1.4 其他厂商的堆叠2.堆叠的示意图3.堆叠的应用3.1 中小企业3.2 园区网4.堆叠的原理4.1基本的概念4.2 堆叠建立4.3 角色选举4.4 版本同步4.5 配置同步4.6 堆叠系统的登录…

DeepSeek 助力 Vue 开发:打造丝滑的步骤条

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

uniappX开发是否需要安卓调试

需要安卓调试&#xff0c; 使用web环境调试通过&#xff0c;打包安卓时出现问题。