目录
1、TCON(Timer Control)定时器控制寄存器:
2、TMOD(Timer Mode)定时器模式控制寄存器:(不可位寻址)
3、IE(Interrrupt Enable)中断允许寄存器:
一、定时器工作过程:
系统时钟或者外部传入脉冲信号给定时计数器,定时器就会加一,而定时计数器TX分为高八位THX,低八位TLX即十六位,假设这十六位都用上就有65536位,当定时计数器计数到65535次,下一次就会溢出,导致系统发生中断,也就是定时器中断。
其中12分频的意思是系统产生12次脉冲才传给定时计数器1次
二、中断过程:(具体参考上一节)
三、定时器相关寄存器:
1、TCON(Timer Control)定时器控制寄存器:
(1)TF0、TF1:定时器溢出标志位,由硬件自动置“1”“0”,我们不用管。
(2)TR0、TR1:定时器运行控制位:当GATE=0时,置“1”开始计数。(还有另一种情况我们没用到,详情看手册)
2、TMOD(Timer Mode)定时器模式控制寄存器:(不可位寻址)
(1)GATE:没用到,置“0”就行
(2)C/T:Clock/Timer,计数器/定时器,置“1”为计数器
(2)M1、M2:设置四种不同的工作模式,这里我们选择模式0,即00,16位自动重装载模式,当溢出时RL_THx、RL_TLx存放的自动装入TH1、TL1
3、IE(Interrrupt Enable)中断允许寄存器:
(1)ET0、ET1:定时器0、1溢出中断允许位,“1”为允许
(2)EA:总中断允许位,"1"为允许,相当于总闸
4、AUXR(auxiliary)辅助寄存器:
(1)T0x12、T1x12:定时器速度选择位:置“0”,12T;置“1”,1T模式;置“0”,12T模式(晶振振动12次单片机完成1个机器周期即计数1次)
四、计算定时器初值:
我们知道定时器是从0一直累加到65535直到溢出,一共计数65536次,每记一次数就相当于晶振振动12次(12T模式),假设晶振频率为12MHZ,也就是每振动相当于1/12us,由此我们可以得到定时器最大计时时间:65536*12*1/12=65536us。
而我们如果要每次计时1ms怎么办呢?这时候就要设置定时器初值使技术次数减少,1ms=1000us,每计数一次就相当于1us,即初值要为(65536-1000),让定时器计数1000次就溢出。
根据第一大点我们可以知道,定时器是用THx高八位,TLx低八位存储16位数的,所以
THx=(65536-计时次数)/ 256,THx=(65536-计时次数)% 256
(如果晶振频率为12MHZ,计时次数=计时多少微秒)
特别的:由于模式0采用16位自动重装载模式,所以我们不需要每次重新载入初值,只需要载入一次就行
五、定时器实验:
实现功能:利用定时器T0的模式0实现间隔定时,每隔1秒L1闪烁一下,也就是亮0.5秒,灭0.5秒; 每隔10秒L8闪烁一下
1、代码思路:
首先配置和开启定时器0,编写中断服务函数控制灯的亮灭
2、宏定义:
#ifndef _PUBLIC_H
#define _PUBLIC_H
#include "STC15F2K60S2.H"
#define u8 unsigned char
#define u16 unsigned int
void Delay_1ms(u16 num);
void Close_All(void);
void Delay_10us(u16 num);
#endif
#include "Public.h"
// 延时函数(最小约1ms@12MHz)
void Delay_1ms(u16 num)
{
unsigned int i;
while(num--)
for(i=0; i<628; i++);
}
/*
输入变量:无
输出变量:无
功能:关闭蜂鸣器和继电器
*/
void Close_All(void)
{
//关闭蜂鸣器和继电器
P0 = 0x00;
P2 = (P2 & 0x1f) | 0xA0;
P2 &= 0x1f;
//关闭LED灯
P0 = 0xff;
P2 = (P2 & 0x1F) | 0x80;
P2 &= 0x1f;
}
void Delay_10us(u16 num)
{
u16 i;
while(num--)
for(i=0; i<3; i++);
}
3、主函数:
// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
sbit L1 = P0^0;
sbit L8 = P0^7;
u16 count;
u8 sign1,sign2;
void Timer_0_Init(u16 time);
// 主函数
void main(void)
{
Close_All();
Timer_0_Init(50000);//50ms
//默认为开灯
L1 = 0;
L8 = 0;
while(1)
{
if(sign1 == 1)
{
L1 = !L1;
P2 = (P2 & 0x1f) | 0x80;
P2 &= 0x1f;
sign1 = 0;
}
if(sign2 == 1)
{
L8 = !L8;
P2 = (P2 & 0x1f) | 0x80;
P2 &= 0x1f;
sign2 = 0;
}
}
}
/*
输入变量:定时时长___us
输出变量:无
功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
//12T模式
AUXR &= 0x7f;
//定时器0 模式0
TMOD &= 0xf0;
//设置初值
TH0 = (65536-time)/256;
TL0 = (65536-time)%256;
//打开中断
ET0 = 1;
EA = 1;
//开始计数
TR0 = 1;
}
void Timer_0_IT(void) interrupt 1
{
count++;
if(count%10 == 0)
sign1 = 1;
if(count%100 == 0)
sign2 = 1;
if(count == 200)
count = 0;
}
更新:对LED代码进行更新
4、主函数:(优化)
// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
u16 count;
u8 sign,last_led = 0xff;
void Timer_0_Init(u16 time);
void LED_ON_Lx(u8 L_X);
// 主函数
void main(void)
{
Close_All();
Timer_0_Init(50000);//50ms
//默认为开灯
LED_ON_Lx(1);
LED_ON_Lx(8);
while(1)
{
if(sign == 1)
{
LED_ON_Lx(1);
sign = 0;
}
if(sign == 2)
{
LED_ON_Lx(8);
sign = 0;
}
}
}
/*****************定时器**********************/
/*
输入变量:定时时长___us
输出变量:无
功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
//12T模式
AUXR &= 0x7f;
//定时器0 模式0
TMOD &= 0xf0;
//设置初值
TH0 = (65536-time)/256;
TL0 = (65536-time)%256;
//打开中断
ET0 = 1;
EA = 1;
//开始计数
TR0 = 1;
}
void Timer_0_IT(void) interrupt 1
{
count++;
if(count%10 == 0)
sign = 1;
if(count%100 == 0)
sign = 2;
if(count == 200)
count = 0;
}
/*****************LED**********************/
/*
输入变量:Lx灯翻转
输出变量:无
功能:选择相应的锁存器后,通过P0口控制某个LED灯翻转,但不影响其他LED灯
注意:使用前要对u8 last_led = oxff进行宏定义
*/
void LED_ON_Lx(u8 L_X)
{
//由于P0口是公用的口,我们要对每次点灯的数据进行记录,不然会受其他操作的影响
P0 = last_led ^ (0x01<<(L_X-1));
last_led = P0;
P2 = (P2 & 0x1f) | 0x80;
P2 &= 0x1f;
}