定时器和定时器时钟


定时器

定时器框图

按视频中的去理解,up主的板子晶振为12MHz,如果分频接了÷12的线路,那么传给计数器的就会是1µs计数一次(计算:1/(12MHz/12)=1/1*10^9s=1µs)

CT选择开关:那里给1counter计数器0timer定时器

GATE那里:三角是异门(1—>0 0—->1),第二个是或门(只有00情况给0,其余给1),第三个是与门跟C的异或与的与意思差不多

实操

1.TMOD(TIME_MODE)

由于TMOD不可寻址,所以要整体表示

(对于(不)可寻址的理解,可寻址像之前的点LED灯,直接P2=0x01<==>P2_1=1然后P2_2~8=0,不可寻址就是只能一坨地表示,就像P2=0x00这样)

目的:我们要实现定时器0运行且进入模式1

①M0&M1

所以M0—>1M1—>0

②C/T

因为是定时器 C/T—>0

③GATE

要让TR0参与控制,所以GATE—>0

附GATE的运行模式

因此

TMOD=0X01;//0000 0001

TMOD的优化

TMOD &= 0xF0;		//设置定时器模式       0xF0-->1111 0000
TMOD |= 0x01;      //                    0x01-->0000 0001

由于TMOD是同时控制定时器0和定时器1,我们希望在控制定时器0的时候,不影响到可能正在工作的定时器1,于是用到了以下操作

e.g.

原TMOD=1010 0011—-我们希望把它转换为—->1010 0001

1st———-1010 0011 & 1111 0000 =1010 0000

理解n & 1 时,n为几就返回几(此时不影响定时器1);n & 0 时,全为0(有点初始化定时器0的感觉)

2nd———1010 0000 | 0000 0001 =1010 0001

理解n | 0 时,n为几就返回几(还是不影响定时器1);0 | n 时,n为几也返回几(n是人工决定的,这时可以自行操控定时器0了)

2.TCON

①TR0

省流:GATE=0 && TR0=1时允许T0计数,开始工作

TR0=1;

②TF0

省流:TF0=1时就产生中断,所以要=0,防止刚配置好就产生中断

TF0=0;

③TH0&TL0

来自弹幕大佬:两个寄存器TH0、TL0为二进制八位(2^8),单独可计256次,低八位计满256次后高八位进1,所以除以256可得高八位得次数,取余就是低八位的次数,合并在一起就是所赋的初始值

来自UP主:123要放到两个容量为100的盒子里,高位次的盒子存储—-123/100=1低位次的盒子存储—-123%100=23合并之后就是123(初始值)

对应项目,就是两个容量为256的小盒子要存储64535这个庞然大物

TH0=64535/256;//high,拿出高八位
TL0=64535%256;//low,拿出低八位

④ET0&EA&PT0

把通道打通

ET0=1;
EA=1;
PT0=0;//虽然默认PT0为0,但还是说明一下比较好

3.Time0.c

#include <REGX52.H>

/**
  * @brief  定时器0初始化,1ms@11.0592MH
  * @param  无
  * @retval 无
  */
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式       0xF0-->1111 0000
	TMOD |= 0x01;     //                     0x0x-->0000 0001
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
    /**
    64535/256=252
    252--10进制转16进制-->FC
    
    64535%256=23
    23--10进制转16进制-->17
    但是我们这个有0.04%的偏差,所以...问题...应该不大吧...
    */
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;          //允许中断
	EA=1;
	PT0=0;
}

/*
定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;//为了不丢失这个数字
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		//这里要写具体实现什么
		T0Count=0;
	}
}
*/

对定时器中断函数模板的理解:

首先,中断程序本身可视为一个while循环,会一直执行这个函数

其次,对于秒数,这个计时器(TH0 TL0)最高可达到65535µs,我们设置定时初值时,用的是64535,它距离65535还有1000才即将溢出归零,所以我们让计时器计时1000µs(=1ms),每过1ms,T0Count++,当它加了1000次,此时已经过去1000ms(=1s)

最后,进入if执行具体实现,然后把T0Count归零,进入下一次中断程序(循环)

4.新学两个函数

要用到#include头文件

crol函数&cror函数(..头尾都要_..

循环移位

unsigned char a=0x80;
a=_crol_(a,1);
//a为0x01,循环回去开头了
//如果是<<的话,移到边界就溢出越界

5.最终呈现

main.c

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>


unsigned char KeyNum,LEDMode;

void main()
{
	P2=0xFE;//P2是LED模块噢,一端接了VCC,那么只有给P2_n赋值为0的时候才亮,0xFE转二进制为1111 1110
	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 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=500)//0.5s亮一次
	{
		T0Count=0;
		if(LEDMode==0)
			P2=_crol_(P2,1);
		if(LEDMode==1)
			P2=_cror_(P2,1);
	}
}

针对流水效果,我们添加了这些

if(T0Count>=500)
	{
		T0Count=0;
		if(LEDMode==0)           
			P2=_crol_(P2,1);//往左流
		if(LEDMode==1)
			P2=_cror_(P2,1);//往右流
	}

配合主函数食用

unsigned char KeyNum,LEDMode; //一开始初始化了KeyNum和LEDMode,这两个玩意初始值都为0

那么,当开关被按下的时候,LEDMode==0,开始往左流,对应下面这句

if(LEDMode==0)           
	P2=_crol_(P2,1);//往左流

然后接收KeyNum,当我不按P3_1时,LEDMode就一直为0,一直往左流

我按下P3_1时,配合Key.c食用,此时返回KeyNumber=1

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==2);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==3);Delay(20);KeyNumber=4;}

	
	return KeyNumber;
}

KeyNum==1后,执行

if(KeyNum==1)
{
	LEDMode++;
	if(LEDMode>=2)LEDMode=0;
}

这时候LEDMode++,LEDMode==1

if(LEDMode==1)
	P2=_cror_(P2,1);//往右流

再次按下P3_1时,LEDMode++,LEDMode==2,然后执行if让LEDMode归零

定时器时钟

main.c

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"

unsigned char Sec,Min,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 = 0x66;		//设置定时初值
	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;
				}
			}
		}
	}
}

这个,不难理解,dddd


文章作者: WB
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WB !
  目录