⏰1.配置寄存器
首先,我们先来配置下定时器,如何配置定时器,定时器就是要先把相关的符号进行声明的,但是由于#include<REGX52.H>当中已经帮我们声明好了,那么我们直接使用就可以

🌷1.1TMOD配置

TMOD配置就是配置定时器的模式
那么我们先创建一个子函数 void Timer0_Init() ⇥ 对定时器进行初始化。
那么首先是TMOD的一个配置,定时器1我们先不管(高四位定时器全部给上0),只管低四位的一个定时器0的一个配置。
在前面的定时器工作有介绍过,STC89C52 的 T0 和 T1 一共有四种工作模式:在这里我们选择最常用的工作模式1。
Ⅰ:工作模式①的话,我们只需要把 M1 = 0,M0 = 1 就是定时器模式①的配置了。
Ⅱ:C/T(取反):这个我们只需要给C/T(取反) = 0即可,SYSclk⇢系统时钟。
Ⅲ:GATE(门控端),GATE = 0,这里当中都是数字电路当中的一些基础逻辑门,TR0 = 1。
经过上述的一一配置和讲解,那么,TMOD=0x01 //0000 0001
TMOD是不可寻位址;只能对它进行整体的赋值
🌷1.2TCON配置
TCON是来配置计时系统的寄存器

TCON可位寻址,注→可位寻址可以为每一位寄存器单独赋值。
在这个我们主要针对 TF0 和 TR0,注:这里我们是单独赋值,用二进制(0/1)来。
Ⅰ: TF0中断溢出标志位,TF0 = 0 被允许计数以后,从处置开始计数+1,当最高位产生溢出的时候,由n硬件置”1″TF0 = 1的时候就会向CPU请求中断。
在程序当中我们先可以直接给TF0 = 0,因为一旦TF0 = 1的就会产生中断。
Ⅱ:TR0 就是计数系统会不会开启,TR0 = 1的时候就代表着开始计数。
那么我们就可以给 TR0 = 1 开始计数工作。
拓展→IE0和IT0就是用来控制外部中断引脚的,但是因为GATE门控端 = 0,那么我们就可以不用去配置这些东西。

:我们还需要配置 TL0 和 TH0 这里我们也需要给它写好一个值。上篇说过,这个计数脉冲就是在12MHZ情况下,每隔1us进行+1,等加到最大值的时候 65535us,它才进行产生一个中断。TL0是低字节,TH0是高字节。它们都是计数系统,这两个字节总共可以存储0~65535。每隔1us加1,总共时间是65535us,这就相当于是65ms计满之后就计数不下去了(好比一个沙漏⏳的沙子已经放满了)
64535us离计数器溢出差值1000us=1ms,每隔1ms的时候产生中断。每一次中断之后再次的计一次数,每计数1000us的时候再做其它的事情。
注:定时器的工作单位方式是以微妙(us)为单位的。
那么在这里我们可以先定义一个1ms的时间,所以我们刚开始的时候就可以给64535离计数器计满(溢出)差值的时候就为1000个数(1ms),注:我们寄存器是⑧个比特位为一位的,⑧位的只能存的下256。而这个65535它是指的是两个⑧位的拼接在了一起,一句话:要分开来。
TH0 = 64535/256;把高8位拿出来了,TL0=64535%256;低8位拿出来了。这个可能理解起来会比较难点,但是其实这样就很好理解了,用画图的方法来演示下吧↓

🌷1.3中断系统的配置

经过上面的操作,定时器的配置已经配置好了,接下来就是中断的配置了
在这里我们只需要配置T0的那一条路线就可以了,有ET0=1,EA=0,PT0=0(默认是0)
⏰2.写代码的时候可能会有的一些问题
🍓2.1TMOD的问题
当然上述代码当中还是存在着缺陷的,那就是TMOD,在上述当中我们TMOD是不可谓寻址就是不能单个赋值初始值必须⑧位才行。在这里我们使用一个定时器是当然没有任何问题的,因为我们的定时器1更本就没有开始工作不会出现问题。
出问题是在于:同时使用⒉个定时器的时候,定时器1和定时器0的话。高位会被刷新!
当然,实际上TOMD = 0x11;也是可以使用两个定时器的。但是它的操作上有很大的区别↓
TMOD = TMOD&0xF0;
TMOD = TMOD|0x01;
:TMOD默认为低电平0000 0000。
TMOD低四位清0,高四位保持不变。 0000 0000 & 1111 0000 = 0000 0000
任何数1&1还是等于1,任何数&0还是等于0的。
TMOD最低为置1(模式一),高四位保持不变。 0000 0000 | 0000 0001 = 0000 0001
任何数或上一个0,就是等于自身的那个数。
那么这个与或赋值法就可以操作其中的几个位而不会影响其它的位。
当然这个也可以用STC-ISP-进行自动配置

AUTR:可以删除因为已经是12T模式了。当然这里还是少了中断的配置我们需要加上的。
Ⅰ:ET0 = 1
Ⅱ:EA = 1
Ⅲ:PT0 = 0
⏰3.代码演示
main.c
#include <REGX52.H>
#include <INTRINS.H>
#include "Key.h"
#include "Timer0.h"
unsigned char Keynum,Ledmode;
void main()
{
P2=0xFE;//第一个灯是亮的
Timer0Init();//调用初始化函数之后就会跳转到中断系统函数
while(1)
{
Keynum=Key();
if(Keynum)
{
if(Keynum==1)//如果是P3_0即K1按键按下的时候
{
Ledmode++;
if(Ledmode>=2)Ledmode=0;//模式转换
}
}
}
}
//中断系统
unsigned int count;//全局变量默认是0
void Timer0_Routine() interrupt 1
{
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
//对计时器的高位和低位重新赋值,保证1ms的时候就启动中断系统了
count++;
if(count>=1000)
{
count = 0;
//输入你要的操作
if(Ledmode==0)
P2=_crol_(P2,1);//l指得是left向左移,1表示的是向左边移动多少
if(Ledmode==1)
P2=_cror_(P2,1);//r指的是right向右移,1表示的是向右移动1位
}
//_crol_和_cror_的特点就是移动的时候溢出来的那一位会到最低位或者是最高位上面去
//实现流水灯的效果
}
Timer0.c
#include <REGX52.H>
void Timer0Init()
{
TMOD &= 0xF0;//这里采用的是定时器
TMOD |= 0x01;//设置定时器的模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
//中断系统模板
/*unsigned int count;//全局变量默认是0
void Timer0_Routine() interrupt 1
{
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
//对计时器的高位和低位重新赋值,保证1ms的时候就启动中断系统了
count++;
if(count>=1000)
{
count = 0;
//输入你要的操作
}
}*/
Timer.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init();//定时器初始化
#endif
delay.c
void delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
delay.h
#ifndef __DELAY_H__
#defend __DELAY_H__
void delay(unsigned int xms);
#endif
Key.c
#include <REGX52.H>//对按键进行操作
#include "delay.h"//操作按键的时候需要用到
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