目录
目录
一、定时器介绍
51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成
1、定时器作用
(1)用于计时系统,可实现软件计时,或者使程序每个以固定定时间完成一项操作
(2)替代长时间的Delay,提高CPU的运转效率和处理速度
2、STC89C52定时器资源
(1)定时器个数:3个(T0,T1,T2).T0和T1与传统的51单片机兼容,T2是次型号单片机增加的资源。(我们可以参考数据手册,查看我们所能用到的定时器资源和原理)
(我们在学习单片机的时候一定要查找数据手册来确定他的一些内部资源,不同型号的单片机资源也是不一样的,我们要确定这个单片机里面有我们想要的资源才可以用)
注:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式所有51单片机所共有的
3、定时器的工作原理
(1)定时器的框图
定时器在但潘集内部就像一个小闹钟一样,根据时钟的输出信号,每隔”一秒“,技术单元的数值就增加一,当计数单元数值增加到”设定的闹钟提醒时间“时,计数单元就会向中断系统发出中断申请,产生”响铃提醒“,使程序跳转到中断服务函数中执行
(2)定时器的工作模式(相当于计数单元这部分)
STC89C52的T0和T1均有四种工作模式
模式0:13位定时器/计数器
模式1:16位定时器/计数器(常用)
模式2:8位自动重装模式
模式3: 两位8位计数器
注:在每一个中工作模式下有着不同的连接方式和结构框图,可以查看参考手册看结构图(最常用的就是模式1,模式0和模式3很少见,模式2很少用)
工作模式1的框图
定时器主要的三个部分(框图从左向右) 1:时钟 2:计数单元 3:中断;
(1)计数单元:它可以比喻成我们的一个沙漏,当达到最大值的时候就会向中断提出申请产生中断
(2)定时器时钟
(3)中断系统:中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。
3、STC89C52中断
(1)中断资源
中断源个数:8个(外部中断0、定时器0中断、外部中断1,定时器1中断,串口中断,外部中断2,外部中断3)
中断优先级个数:4个
中断号
注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同,中断优先级个数不同等等。
(2)中断流程图
(3)定时器和中断系统
4、定时器与中断相关寄存器
单片机通过配置寄存器来控制内部线路的连接
二、按键控制流水灯的模式
1、开启定时器,给定时器/计数器赋值
我们可以通过在STC-ISP烧录程序软件中自动生成
其中AUXR是新版本的单片机才使用的,这里我使用的单片机不需要这行设定,所以把初始化函数中第一行删除。
void Timer0Init(void) //定时器T0,1ms计数溢出,申请中断
{
TMOD &= 0xF0; //设置定时器模式
TMOD | = Ox01 //这里是将定时器的初值直接计算出来后,换成16进制赋值
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1; //中断允许总控制位
ET0=1; //T0中断允许控制位
PT0=0; //T0中断优先级设定位
}
2、编写程序每隔1s,使LED1闪烁
#include <REGX52.H>
void Timer0_Init() //定时器T0初始化,Init一般用于初始化
{
TMOD=0x01; //0000 0001,不可位寻址
//前面4位数控制T0,后面四位数T1
//第一位GATA默认为0,第二位0为定时器模式,1为计数器模式
//第3和第4位为01,则表示用第1种工作方式,也就是16位定时/计数器
//TCON可位寻址,直接对“位赋值”
TF0=0; //溢出标志位
TR0=1; //定时/计数器0开始工作
TH0=64535/256; //对定时器0赋初值,使T0每隔1ms就计数溢出
TL0=64535%256; //TH0放高8位,TL0放低8位
EA=1; //中断允许总控制位
ET0=1; //T0中断允许控制位
PT0=0; //T0中断优先级设定位
}
void main()
{
Timer0_Init();
while(1)
{
}
}
unsigned int T0Count; //在函数外面,为全局变量,在函数里面,为局部变量,只有函数内有效
void Timer0_Routine() interrupt 1 //定时器T0的中断函数,当T0计数1ms溢出,就会跳到中断函数
{
TH0=64535/256; //每次中断后,都要重新赋初值,不然中断响应后,定时/计数器会从0开始计数
TL0=64535%256;
T0Count++;
if(T0Count>=1000) //当计数超过1000次,也就是1s时,使P2_0取反
{
T0Count=0;
P2_0=~P2_0;
}
}
3、编写程序按键控制LED流水灯模式
(1)main.c主函数
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H> //函数库
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE; //1111 1110赋值给P2
Timer0Init();
while(1)
{
KeyNum=Key(); //获取独立按键键码
if(KeyNum) //如果按键按下
{
if(KeyNum==1) //如果K1按键按下
{
LEDMode++; //每次按键D1,会使LEDMode在0和1之间循环
if(LEDMode>=2)LEDMode=0;
}
}
}
}
void Timer0_Routine() interrupt 1 //定时器T0的中断函数,当T0计数1ms溢出,就会跳到中断函数
{
static unsigned int T0Count; //如果没有static,在函数内定义T0Count是局部变量
//在函数结束之后,会销毁,再申请的局部变量,就不是上次继续的值
//static是使T0Count为静态变量,使得退出程序以后,变量还能保留
//与全局变量区别在于,这个变量只能本函数使用
TL0 = 0x18; //每次中断响应后,都要重新赋初值
TH0 = 0xFC;
T0Count++; //每次中断响应后,T0Count会自动加1
if(T0Count>=500) //当计数溢出超过500次,也就是0.5s时,执行下面操作
{
T0Count=0;
if(LEDMode==0) //模式判断
P2=_crol_(P2,1); //_crol_(A,x)函数,使A里面的二进制数向左移x位
if(LEDMode==1)
P2=_cror_(P2,1); //_cror_(A,x)函数,使A里面的二进制数向右移x位
}
}
(2)定时器Timer0模块化
#include <REGX52.H>
/**
* @brief 定时器0初始化,定时1ms计数溢出
* @param 无
* @retval 无
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //使TMOD低四位为0001,高四位保持不变
TL0 = 0x18; //计算出定时器初值,转化成16进制,再赋值给TLx和THx
TH0 = 0xFC;
TF0 = 0; //清除TF0计数溢出标志位
TR0 = 1; //定时器0开始计时
ET0=1; //中断允许总控制位
EA=1; //T0中断允许控制位
PT0=0; //T0中断优先级设定位
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC;
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
(3)独立按键Key模块
#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;
}
(4)延迟函数Delay模块
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
三、定时器时钟
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
unsigned char Second=55,Minute=59,Hour=23; //秒,分钟,小时
void main()
{
LCD_Init();
Timer0_Init();
LCD_ShowString(1,1,"Clock:");
LCD_ShowString(2,3,":");
LCD_ShowString(2,6,":");
while(1)
{
LCD_ShowNum(2,1,Hour,2);
LCD_ShowNum(2,4,Minute,2);
LCD_ShowNum(2,7,Second,2);
}
}
void Timer0_Routine() interrupt 1 //定时器T0的中断函数,当T0计数1ms溢出,就会跳到中断函数
{
static unsigned int T0Count;
TL0 = 0x18; //每次溢出都要重新赋初值
TH0 = 0xFC;
T0Count++;
if(T0Count>=1000) //定时器溢出1000次时,也就是每秒会执行下面功能
{
T0Count=0;
Second++;
if(Second>=60)
{
Second=0;
Minute++;
if(Minute>=60)
{
Minute=0;
Hour++;
if(Hour>=24)
Hour=0;
}
}
}
}