一、定时器寄存器配置
为了理解寄存器的配置,在这里先记录自己配置的方法,记录完后会说简便方法。
这是定时器/计数器0和1的相关寄存器,对以下寄存器进行配置,达到自己想要的效果。
1、先配置TMOD(模式)因为TMOD是不可位寻址,就是说只能整体赋值。
根据数据手册,当前只用一个定时器0所以高4位都为0,GATE都设置为0(不用到),c/t为0时用作定时器,M1M0的配置根据表中设置为01(16位定时器)
所以TMOD=0x01;//0000 0001,在此处对TMOD配置低四位时会影响到高四位,因为此时只用一个定时器所以没有影响,若要用两个定时器时,应该这样配置
TMOD=TMOD&0xF0;//把TMOD低四位清0,高四位不变
TMOD=TMOD|0x01;//把TMOD最低位置1,高位不变
2、配置TCON是可位寻址,所以可以进行每一位单独赋值。
因为此时只用定时器0,TF0=0,TR0=1;IE0,IT0由于我们对GATE已经赋值为0是用不到的所以可以不用配置。
3、对TH0和TL0配置
因为是16位,所以可以计0-65535,因为脉冲16分频分频后,每个周期1us计数加一所以总共定时是65535us,我们给寄存器赋初值64535,距离溢出差值是1000,计时1ms。
TH0=64535/256;TL0=64535%256;取出高低位。
4、简便方法
运用stc进行配置,因为使用的是STC89c52RC,晶振是12Mhz,定时器0,定时长度1ms,模式的话只有16位没有16位重组,定时器时钟选择12T,生成代码。因为AUXR这个寄存器并没有,所以这一句可以删除,我们已经是12T模式并不需要配置。
二、中断系统配置
2.1配置开关和优先级
由上一篇文章介绍所说,传统的51单片机中断系统是向下兼容的,所以可以按照传统51的单片机中断系统图进行配置会简单许多。这里使用的是定时器0,因为只用一个定时器中断,这里的优先级可以默认为0。
ET0=1;EA=1;PT0=0;
2.2中断标志位
根据标志位的图设置。
在此设置void Timer0_Rountine(void) interrupt 12.3
2.3配置代码
定义Time0.c,对定时器0进行模块化编程,代码如图,之后运行定时器0,只需添加头文件即可。
#include <REGX52.H>
#include "Time0.h"
/**
* @brief 定时器0初始化//1毫秒@12.000MHz
* @parm 无
* @retval 无
*/
void Timer0_Init() //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
P2=~P2;
}
}
*/
三、独立按键模块
编辑独立按键模块返回键码,这样就可以在按下不同按键时在main中写出不同的功能。
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @parm 无
* @retval 按下按键的键码,0~4
*/
unsigned char Key()
{
unsigned char KeyNumber=0;//局部变量初值不确定
if(P3_1==0)
{
Delay1ms(20);//消抖
while(P3_1==0);//检测松手
Delay1ms(20);
KeyNumber=1;
}
if(P3_0==0)
{
Delay1ms(20);//消抖
while(P3_0==0);//检测松手
Delay1ms(20);
KeyNumber=2;
}
if(P3_2==0)
{
Delay1ms(20);//消抖
while(P3_2==0);//检测松手
Delay1ms(20);
KeyNumber=3;
}
if(P3_3==0)
{
Delay1ms(20);//消抖
while(P3_3==0);//检测松手
Delay1ms(20);
KeyNumber=4;
}
return KeyNumber;
}
四、流水灯主函数
不设置按键也可以运行,就单纯定时器控制流水灯,这里设置按键的目的就是让流水灯移动的方向进行改变。这里用到了两个函数(必须得加头文件<INTRINS.H>才能使用):
_cror_ (unsigned char, unsigned char); _crol_ (unsigned char, unsigned char);
可以快速的实现左移右移并且可以循环,而不是用单纯的>> ,<<再加if增到最大值返回最小值。
#include <REGX52.H>
#include "Time0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char Keynum,LedMode;//LedMode 控制模式
void main()
{
P2=0xFE;//赋予初值点亮一个灯
Timer0_Init();//定时器初始化
while(1)
{
Keynum=Key();//获取按键码
if(Keynum)//如果按下按键
{
if(Keynum==1)//如果按下按键模式+1
{
LedMode++;
if(LedMode>=2)//模式只有01两种
{
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);//左移1位
}
else if(LedMode==1)
{
P2=_cror_(P2,1);//右移1位
}
}
}