定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。
定时器主要作用:
需要注意的是:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的(15w只有T0和T2两个计时器)。而我们的89C52RC的定时器个数有3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源。
下面介绍一下计时器的触发流程:
定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行。
就类似于我们睡午觉时候设置的闹钟一样,首先设定一个30分钟的闹钟(提供计数单元的时钟脉冲),闹钟每秒都会刷新一次,每一次刷新,我们能睡得时间就减少了(时钟计数),到了30分钟之后,闹钟就响了,这个时候你就知道:就要起来上课了(产生中断,执行定时任务)。
STC89C52RC的T0和T1均有四种工作模式:
在STC89C52RC中,模式一使用较多,所以我们着重讲解一下模式一。
计数器介绍:当计数器到了最大值(65535)之后,就会产生溢出,中断器就会产生一个标记位,就使程序跳转到中断服务函数中执行。
时钟介绍:
SYSclk:系统时钟,即晶振周期,本开发板上的晶振为11.0592MHz。C/T那个开关,给高电平就是连接下面那个计数器,给低电平就是连接上面那个计时器。而上面那个开关是控制计时间隔的。
中断系统介绍:
这个中断,和我们现实中的中断是一样的,比如你在写作业,突然有人发消息给你(一个中断),你就拿起手机来看,这个时候突然发现水烧开了(一个中断),又去关热水器,再回到写作业的状态。 你们看,这里面,出现了优先级不同的两个中断,就出现了优先级高的中断打断了优先级低的中断(中断嵌套),再回到原来的状态。
中断程序流程:
这个就是中断程序的电路图,就是通过给每个开关赋值来实现功能,比较抽象。
寄存器
具体流程和内容就是这样,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
延时函数之前介绍过,在此处就不做讲解。
具体运行结果如下所示:
https://live.csdn.net/v/embed/210574
计时器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;
}
}
}
}
}
这里也运用到了计时器函数,因为在前面介绍了,就不再重复。
运行效果如下所示:
https://live.csdn.net/v/embed/210577
计时器46