51单片机学习-----独立按键控制流水灯状态

2024-10-09 16:04:38 浏览数 (5)

前言

对于独立按键控制流水灯状态需要用到定时器以及相关中断的知识,所以我们首先需要了解什么是定时器?什么是中断?以及简单的运用中断和定时器的寄存器,配置定时器等相关知识。

一、定时器是什么?

定时器属于单片机的内部资源,在单片机的内核中,下面是定时器的简图:

定时器的作用:

代码语言:javascript复制
 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
代码语言:javascript复制
代替长时间Delay,提高CPU的运行效率和处理速度。

定时器分为三个部分:时钟、计数单元、中断系统

对上述结构进行分析:

1:系统时钟,即晶振周期,本开发板的晶振为12MHz。注:时钟可长可短。 2:作用是分频,在2中它会把12兆的系统时钟进行分频,分频之后就是输出的频率就是1兆Hz输出的周期就是1微妙,每隔1微妙单片机的计数单元就记一个数。 3:也是一个分频的模式 4:时钟的来源一个是单片机的内部资源SYSclk另一个则是T0Pin,T0Pin是单片机的外部接口,由外部引脚来提供,当由外部引脚提供时,时钟就是一个计数器,相当于一个记脉冲的计数器。 5:TMOD的一个寄存器,当5配置0时,就表现为计时器,当5配置为1时就表现为计数器。 6:TCON的一个寄存器,高字节是TH,低字节是TL,左边的TH提供一个脉冲,右边的计时器就会 1,对于这个寄存器总共可以存储65535,当溢出时就会重置为0,并记一个标记位传给TF0,有了这个标记位就会申请中断。 7:TF0溢出标志位,也就是中断申请标志位。 8:与门,只要有一个输入端是0输出端就是0,两个输入端都是1,输出端才是1. 9:或门:两个输入端有一个是1输出端就是1,两个输入端都是0,输出端才是0. 10:TR0定时器控制寄存器。 11:门控端:GATE门控端是一种电子元件,主要用于控制电路的通断。在电路中,GATE门控端接收输入信号,根据输入信号的逻辑状态来决定输出信号的通断。常见的GATE门控端有与门、或门、非门等。 12:定时器控制寄存器 11右边的三角形:非门:非门的输入端输入0,输出端就输出1,输入端输入1,输出端就输出0.

时钟中用到的寄存器

二、中断系统是什么

1.概念

中断系统是为使CPU具有对外界紧急时间的实时处理能力而设置的。 当中央处理器CPU正在处理某件事的时候外界发生紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再 回到原来被中断的地方,继续原来的工作,这个过程称为中断。 在单片机中,定时器溢出就是一种中断源。 中断可以理解为下图:

当多个中断源出现时,就需要规定一个轻重缓急排队,规定每一个中断源的优先级别。CPU总是先响应优先级最高的中断请求。 当CPU正在处理一个中断源时,发生了一个优先级比他高的中断源请求,如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断源请求,处理完以后,再回到源优先级中断服务程序,这样的过程叫做中断源嵌套。 这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。 总结:高优先级的中断可以打断低优先级的中断。 注意:中断的资源和单片机的型号也是关联在一起的,不同型号可能会有不同的中断资源,例如中断源个数不同、中断优先级的个数不同等等。 89C52的中断源的个数是8个(外部中断0,定时器0中断,外部中断1,定时器1中断,串口中断,外部中断2,外部中断3) 中断优先级个数:4个 下图就是一个中断系统:

当中断系统接收到溢出时产生的中断申请标志位时,就会传到中断系统中,中断系统会根据中断优先级进行处理。 下面是中断系统中涉及到的寄存器

三、代码实现独立按键对流水灯控制

1. .c文件

Delay.c

代码语言:javascript复制
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
		{
			i = 2;
			j = 239;
			do
			{
				while (--j);
			} while (--i);
		}
}

Key.c

代码语言:javascript复制
#include <REGX52.H>
#include "Delay.h"
/**
   *  @brief 获取独立按键键码
   *  @param 无
   *  @relval 按下按键的数字,返回:0~4,无按键按下时返回值为0
   */
unsigned char Key()
{
	unsigned int Keynum=0;
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);Keynum=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);Keynum=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);Keynum=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);Keynum=4;}
	return Keynum;
}

main.c

代码语言:javascript复制
#include <REGX52.H>
#include "timer0.h"
#include "Key.h"
#include <INTRINS.H>


unsigned char KeyNum,LEDMode;


unsigned char KeyNumber;
void main()
{
	P2=0xfe;
	Timer0_Init();//初始化
	while(1)
	{
		KeyNumber=Key();
		if(KeyNumber)
		{
			if(KeyNumber==1)
			{
				LEDMode  ;
				if(LEDMode>=2)LEDMode=0;
			}
		}
	}
}

//时钟的中断
void timer0_Routine() interrupt 1//中断函数
{
	static unsigned int T0Count;
	TH0=64535/256;
	TL0=64535%6;//
	//每次定时器完了之后进入中断都会重置前面的计数单元,所以需要对计数单元进行人为的赋值
	
	T0Count  ;
	if(T0Count>=500)
	{
		T0Count=0;
		if(LEDMode==0)
		{
			P2=_crol_(P2,1);
		}
		if(LEDMode==1)
		{
			P2=_cror_(P2,1);
		}
		
	}
}

timer0.c

代码语言:javascript复制
#include <REGX52.H>



/**
   *  @brief 定时器初始化,一毫秒12MHz
   *  @param 无
   *  @relval 无
   */

void Timer0_Init()
{

	//配置TMOD
	//前四个0是配置定时器1,后面四个数是配置定时器0
	//0表示配置GATE,0表示配置C/T,最后两个数表示配置M1和M0
	//	TMOD=0x01;//0000 0001
	TMOD&=0xF0;//把TMOD的低四位清零:高四位保持不变  与清零
	
	TMOD|=0x01;//把TMOD的低四位置1,高四位保持不变  或置1
	//&操作相当于
	//配置中断溢出标志位
	TF0=0;//清零防止刚打开就产生中断
	TR0=1;
	TH0=64535/256;//十进制数除以10相当于左移1位,二级制数除以256就相当于
	//向左移8位,但是是/所以是取的高位,TH0就表示取高位
	TL0=64535%6;//这里表示取余数取二进制余数取的低位
	
	//配置中断
	ET0=1;
	EA=1;
	PT0=0;//低优先级
}



/*
void timer0_Routine() interrupt 1//中断函数
{
	static unsigned int T0Count;
	TH0=64535/256;
	TL0=64535%6;//
	//每次定时器完了之后进入中断都会重置前面的计数单元,所以需要对计数单元进行人为的赋值
	
	T0Count  ;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/

2. .h文件

Delay.h

代码语言:javascript复制
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);

#endif

Key.h

代码语言:javascript复制
#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();

#endif

timer0.h

代码语言:javascript复制
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void );

#endif

四、总结

对于独立按键控制流水灯状态来说不是特别难,还可以继续发散更多好玩的

0 人点赞