2023/11/23 定时器 独立按键控制LED流水灯

定时器作用
(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
(2)替代长时间的Delay,提高CPU的运行效率和处理速度
(…)
(相当于cpu可以在原本delay的时候同时进行其他任务)

2023/11/23 定时器 独立按键控制LED流水灯_第1张图片

定时器:时钟发出脉冲,计数单元进行计数,当计数值达到时,产生一个TF0(T0溢出中断标志),让中断系统产生中断,执行定时任务。
SYSclk:系统时钟,即晶振周期; T0 Pin:外部引脚,从外界接受脉冲

2023/11/23 定时器 独立按键控制LED流水灯_第2张图片

2023/11/23 定时器 独立按键控制LED流水灯_第3张图片



中断系统:使CPU具有对外界紧急事件的实时处理能力而设置,要求CPU正在处理某件事发生紧急事件请求后,去转而处理这个事件,处理完后再回去继续处理原来的工作。一般允许多个中断源,规定每个有个优先级别。(&中断嵌套)

2023/11/23 定时器 独立按键控制LED流水灯_第4张图片

2023/11/23 定时器 独立按键控制LED流水灯_第5张图片
寄存器:单片机通过配置寄存器来控制内部线路的链接。在单片机中寄存器就是一段特殊的RAM存储器,一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式。寄存器相当于一个复杂机器的“操作按钮”。
        M0,M1:1,1--停止计数
                 0,1--16位
               C/T:置0定时器,置1计数器

#include 

/**
  * @brief 定时器0初始化 1毫秒@11.0592MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
    ET0=1;
    EA=1;
    PT0=0;
}
/*定时器中断函数模板
void Timer_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
	 
	}
}
*/

定时器函数

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
    ET0=1;
    EA=1;
    PT0=0;
}
  • 配置TCOM
TMOD=0x01 ;

2023/11/23 定时器 独立按键控制LED流水灯_第6张图片

TCOM不可位寻址,只能整体赋值。

这里取0000 0001,只启用定时器0。GATE取0,让或门为1,这样与门只由TR0的值控制。而C/T取0意味控制是否打开定时器0,M1,M0取0,1启用16位定时器。 

TMOD=TMOD&0xF0;
TMOD=TMOD|0x01;

 把TMOD低四位清零,高四位不变:不影响同时使用定时器1和定时器0。1010 0000&1111 0000=1010 0000

把TMOD最低位置1,高四位不变。1010 0000|0000 0001=1010 0001.

这种赋值法你可以想改那个就改那个,因为都说了不可位寻址,只能通过这种方式更改位。直接赋值是必须8位一起赋,如果只想改变四位,就必须要与或。

  • 配置TCON
TF0=0;//清零,使中断器溢出中断为0
TR0=1;//让定时器开始工作

2023/11/23 定时器 独立按键控制LED流水灯_第7张图片

TCON可位寻址,可以每一位单独赋值

  • 配置TL0,TH0

0~65535,每隔1us计数加一,总共定时时间65535.赋初值为64535,离计数器溢出差值为100,所以计时为1ms。寄存器是八个为一位,所以要把两个八位寄存器拼在一起才能存65535这么多

TH0=64535/256;
TL0=64535%256;

 相当于256进制。类比于十进制123中123/10=1,123%10=23。和十进制一样,除以10是小数点左移一位。除以256在二进制里就是小数点左移8位。两个寄存器TH0、TL0为二进制八位,单独可计256次,低八位计满256次后高八位进1,合并在一起就是所赋的初始值。所以除以256可得高八位得次数,取余就是低八位的次数。然而我们这种会少一微秒,所以

TH0=64535/256;
TL0=64535%256+1;
TL0 = 0x66;		//设置定时初值
TH0 = 0xFC;		//设置定时初值

  • 配置中断系统

2023/11/23 定时器 独立按键控制LED流水灯_第8张图片

ET0=1;
EA=1;
PT0=0;
  • 中断函数

2023/11/23 定时器 独立按键控制LED流水灯_第9张图片

interrupt 1就是中断子函数。

void Timer_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
	
	}
}

这样设置中断函数,使它每一次过了1s都执行一下

T0Count=0;
       P2_0=~P2_0;

然后TL0,TH0重新赋初值,使其恢复到原位。

这样就设置好了定时器和中断函数。然后我们针对我们的目的写代码:按下独立按键,使流水灯的方向发生改变。然后我们定义独立函数的模块:(需注意,这里要用到Delay)

#include 
#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;
}	

回到主函数,我们定义一个LEDMode变量,如果按键被按下,就让LEDMode的值在0和1之间变化。这样如果LEDMode值仍然为0,那么流水灯方向保持向1-8方向;为1,则为8-1方向。这里使用了crol(字符循环左移)和cror(字符循环右移)

顾名思义,循环移位函数是一个函数操作,可以对一个数据进行循环移位操作,循环的意思是移出位的那位二进制数,不是进行舍弃,而是又从另外一端补位进来。

循环移位函数有两个参数,格式为_xxx_(c,b)。c为要移位的数据,b为移动的位数。移位函数一共有6个:
_crol_: 字符循环左移
_cror_: 字符循环右移
_irol_: 整数循环左移
_iror_: 整数循环右移
_lrol_: 长整数循环左移
_lror_: 长整数循环右移
————————————————
版权声明:本文为CSDN博主「一只爬爬虫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_72963799/article/details/127313328

timer:

#include 

/**
  * @brief 定时器0初始化 1毫秒@11.0592MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
    ET0=1;
    EA=1;
    PT0=0;
}
/*定时器中断函数模板
void Timer_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
	 
	}
}
*/

key:

#include 
#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;
}	

main: 

#include 
#include "Timer0.h"
#include "Key.h"
#include 


unsigned char KeyNum,LEDMode;
void main()
{
	P2=0xFE;//1111 1110
	   Timer0Init();
      while(1)
      {
						KeyNum=Key();
				if(KeyNum)
				{
					LEDMode++;
					if(LEDMode>=2)LEDMode=0;
				}
       }
 
}

void Timer_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=500)
	{
		T0Count=0;
	  if(LEDMode==0)
		P2=_crol_(P2,1);
		if(LEDMode==1)
			P2=_cror_(P2,1);
			
	}
}

独立按键控制LED流水灯

你可能感兴趣的:(51单片机,51单片机)