(六)51单片机基础——定时器

        定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。

定时器主要作用:

  1. 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作。
  2. 替代长时间的Delay,提高CPU的运行效率和处理速度。

        需要注意的是:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0T1的操作方式是所有51单片机所共有的(15w只有T0和T2两个计时器)。而我们的89C52RC的定时器个数有3个(T0T1T2),T0T1与传统的51单片机兼容,T2是此型号单片机增加的资源。

下面介绍一下计时器的触发流程:

        定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行。

 

        就类似于我们睡午觉时候设置的闹钟一样,首先设定一个30分钟的闹钟(提供计数单元的时钟脉冲),闹钟每秒都会刷新一次,每一次刷新,我们能睡得时间就减少了(时钟计数),到了30分钟之后,闹钟就响了,这个时候你就知道:就要起来上课了(产生中断,执行定时任务)

STC89C52RCT0T1均有四种工作模式:

  •   模式013位定时器/计数器
  •   模式116位定时器/计数器(常用)
  •   模式28位自动重装模式
  •   模式3:两个8位计数器

在STC89C52RC中,模式一使用较多,所以我们着重讲解一下模式一。

计数器介绍:当计数器到了最大值(65535)之后,就会产生溢出,中断器就会产生一个标记位,就使程序跳转到中断服务函数中执行。

时钟介绍

SYSclk:系统时钟,即晶振周期,本开发板上的晶振为11.0592MHz。C/T那个开关,给高电平就是连接下面那个计数器,给低电平就是连接上面那个计时器。而上面那个开关是控制计时间隔的。

中断系统介绍:

        这个中断,和我们现实中的中断是一样的,比如你在写作业,突然有人发消息给你(一个中断),你就拿起手机来看,这个时候突然发现水烧开了(一个中断),又去关热水器,再回到写作业的状态。

        你们看,这里面,出现了优先级不同的两个中断,就出现了优先级高的中断打断了优先级低的中断(中断嵌套),再回到原来的状态。

 中断程序流程

这个就是中断程序的电路图,就是通过给每个开关赋值来实现功能,比较抽象。

 寄存器

  • 寄存器是连接软硬件的媒介
  • 在单片机中寄存器就是一段特殊的RAM存储器,一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式
  • 寄存器相当于一个复杂机器的“操作按钮”

具体流程和内容就是这样,51单片机主要就是通过操控寄存器来实现功能的,下面结合代码来理解一下:

这个是主函数

#include <REGX52.H>
#include "Time0.h"
#include "Key.h"
#include <INTRINS.h>
//void Timer0_Init()
//{
// 定时器部分
	// 配置TMOD
//	TMOD = 0x01;
// 与或赋值法	
//	TMOD &= 0xF0;	// 把TMOD的低四位清零,高四位不变
//	TMOD |= 0xF0	// 把TMOD的最低位置1,高四位不变
//	 配置TMOD
//	TF0 = 0;	//T0溢出中断标志
//	TR0 = 1;	//定时器T1的运行控制位
	
	// 配置TH0
//	TH0 = 64535/256; // 取高位
	// 配置TL0
//	TL0 = 64535%256; // 取低位
// 中断部分	
//	ET0 = 1;
//	EA = 1;
//	PT0 = 0;
//	void Timer0Init(void)		//1毫秒@11.0592MHz
//{
//	AUXR |= 0x80;		//定时器时钟1T模式
//	TMOD &= 0xF0;		//设置定时器模式
//	TL0 = 0xCD;		//设置定时初始值
//	TH0 = 0xD4;		//设置定时初始值
//	TF0 = 0;		//清除TF0标志
//	TR0 = 1;		//定时器0开始计时
//	ET0 = 1;
//	EA = 1;
//	PT0 = 0;
//}


//}

unsigned char KeyNum, LEDMode;

void main(){
	P2 = 0xFE;    //初始化,让D1亮
	Timer0Init();
	while(1){
		KeyNum = Key();
		if(KeyNum){
			if(KeyNum == 1){
				LEDMode++;    //改变LED灯模式
				if(LEDMode >= 2)LEDMode = 0;	
			}
			
		}
	}
}


// 计时器0中断之后运行的函数
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0xCD;		//设置定时初始值
	TH0 = 0xD4;	
	T0Count++;
	if(T0Count >= 500){
	T0Count = 0;		
		if(LEDMode == 0){
			P2 = _crol_(P2, 1);   
//位移函数,在这个头文件里“#include <INTRINS.h>”,能够循环移位,比移位符好用,这个是向左移位(灯向右移)
		}
		if(LEDMode == 1){
			P2 = _cror_(P2, 1);
//向左移位
		}
		
	}
}

这个是定时器的函数,包含.c和.h文件

//.c代码
#include <REGX52.H>

/**
  * @brief 定时器0初始化, 1毫秒@11.0592MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)		//1毫秒@11.0592MHz
{

	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初始值
	TH0 = 0xD4;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
	PT0 = 0;
}

/*
// 计时器0中断之后运行的函数
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0xCD;		//设置定时初始值
	TH0 = 0xD4;	
	T0Count++;
	if(T0Count >= 1000){
	T0Count = 0;		
	P2_0 = ~P2_0;
//	Delay(100);
		
	}
}
*/


//.h代码
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);

#endif

控制键盘按下的函数

#include <REGX52.H>
#include "Delay.h"


/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范伟:0~4,无按键按下时返回0
  */
unsigned char Key()
{
	unsigned char KeyNumber = 0;
	if(P3_1 == 0){Delay(20);while(P3_1 == 0);Delay(20);KeyNumber = 1;}
	if(P3_0 == 0){Delay(20);while(P3_0 == 0);Delay(20);KeyNumber = 2;}
	if(P3_2 == 0){Delay(20);while(P3_2 == 0);Delay(20);KeyNumber = 3;}
	if(P3_3 == 0){Delay(20);while(P3_3 == 0);Delay(20);KeyNumber = 4;}
	return KeyNumber;
}
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();

#endif

延时函数之前介绍过,在此处就不做讲解。

 具体运行结果如下所示:

计时器3

接下来,运用我们所学知识,来设计一个时钟,具体代码如下所示:

#include <REGX52.h>
#include "Delay.h"
#include "LCD1602.h"
#include "Time0.h"

unsigned char Sec, Hour=23, Min = 59;
void main(){
	//初始化
	LCD_Init();
	Timer0Init();
	//LCD显示
	LCD_ShowString(1, 1, "Clock:");
	LCD_ShowString(2, 1, "  :  :");
	while(1){
		LCD_ShowNum(2, 1,Hour,2); 
		LCD_ShowNum(2, 4,Min,2); 
		LCD_ShowNum(2, 7,Sec,2); 
		
	}
}
// 计时器0中断之后运行的函数
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;	
	//计时和进位
	T0Count++;
	if(T0Count >= 1000){
	T0Count = 0;		
	Sec++;
		if(Sec==60){
			Sec = 0;
			Min++;
			if(Min == 60){
				Min = 0;
				Hour++;
				if(Hour == 24){
					Hour=0;
				}
			}
		}		
	}
}

这里也运用到了计时器函数,因为在前面介绍了,就不再重复。

运行效果如下所示:

计时器46

  • 21
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值