目录
1.定时器介绍
定时器介绍:
51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成
定时器作用:
(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
(2)替代长时间的Delay,提高CPU的运行效率和处理速度
(…)
2.STC89C52定时器资源
定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源
注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的
3.定时器框图
定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行
4.定时器工作模式
模式1最常用
5.定时器时钟
模式:时钟--计数最大65535(计数系统TL0\TH0:每来一个脉冲+1方法计数)-TF0(标志位,到最大了回到0)-中断:
非门与门图形为控制部分(TR0是否启动暂定)
定时器部分:
时钟可以由系统提供(上图,晶振),也可以由外部T0P提供(如下图引脚)
C/T,给1连上面为控制器,给0连接下面为定时器(如下图):
6.中断系统
高优先级的中断可以打断低优先级的中断。中断是可以对外界紧急事件中断。
7.中断程序流程
8.STC89C52中断资源
9.定时器和中断系统
10.定时器相关寄存器
11.按键控制LED流水灯代码
第一步:
先看定时器寄存器工作原理图
TMOD寄存器工作模式、TCON控制寄存器,定时器0配置使用(不可位寻址,只能整体赋值)
定时器模式1:门控端给0,就是tr0单独控制:C/T,T这里有一横表示低电平有效,就给0是用T(定时器模式),给1用C(控制器模式),M1,M0工作模式选择
第二步:
跟据图写代码
第三步:
看图
控制计数器(可位寻址,可以单独每一位赋值)
中断溢出标志位:
TF=0(等于1产生中断);
TR0=1(定时器是否开启,给1开始,电机开始工作);
IE0、IT0:控制外部中断引脚,可以不配置
TH0=64535存不下这么大的数要分开存,这里是16进制
第四步:
定时器配置TH0\TL0
中断配置T0-->ET0=1--EA=1,PT0=0
定时器配置完成(TMOD定时器工作模式,TCON定时器控制器(单独赋值TF0中断溢出标志位(TF=0整体赋值)\TR0开始计算))第六行改代码为TF0=0
中断完成,可验证。(P2_0\TMOD等已经定义了所有可以直接使用,包含头文件进来即可)
检测是否进入中断函数里面
第五步:
代码优化,TMOD问题(不可位寻址)配置两个的时候,后面的会把前面的覆盖;
不会改变高4位
简写
差1毫秒原因
第六步:
定时器模块化
static修饰变量程序结束后,内存还有,不清理
独立按键模块化,前面学了(while检测松手)P2改为P3,按键为P3,灯为P2
头文件
第七步:
main调用
流水灯模式P2=0亮
循环左右移,移动到最高又回到最低位
流水灯代码
最终代码:
模块化:
main.c
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum;
unsigned char LEDMode;
void main()
{
P2 = 0xFE;
Timer0Init();
while(1)
{
KeyNum = Key();
if(KeyNum)
{
if(KeyNum==1)
{
LEDMode++;
if(LEDMode >= 2)LEDMode = 0;
}
}
}
}
void Timer0_Routine() interrupt 1 //中断函数
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count >= 500)
{
T0Count = 0;
if(LEDMode == 0)
{
P2 = _crol_(P2,1);
}
if(LEDMode == 1)
{
P2 = _cror_(P2,1);
}
}
}
Timer0.c
#include <REGX52.H>
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
PT0 = 0; //中断系统
}
/**
*@brief 定时器0初识化,1毫秒@12.000MHz
*@param 无
*@retval无
*/
/*void Timer0_Routine() interrupt 1 //定时器中断函数(要用的时候,复制到主函数)
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count >= 1000)
{
T0Count = 0;
}
}*/
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Key.c
#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;
}
Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
Delay.c和Delay.h前面的章节有
12.定时器时钟代码
第一步:
把LCD1602液晶显示、延迟、定时器、的代码复制到工程目录下,导入
第二步:
主函数包含其他模块头文件并初始化
第三步:
复制定时器中断函数(过程不要太长,一般简单任务)到main函数下
第四步:
定义变量,秒计数、分、小时并显示
第五步:
最终代码:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Time0.h"
unsigned char Sec;
unsigned char Min;
unsigned char Hour;
void main()
{
LCD_Init();
Timer0Init();
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);
}
}
void Timer0_Routine() interrupt 1 //定时器中断函数
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初始值
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;
}
}
}
}
}
模块化和按键控制LED流水灯代码一样