首页 > 其他分享 >51单片机:多功能时钟(附代码详解)

51单片机:多功能时钟(附代码详解)

时间:2024-07-06 22:56:09浏览次数:17  
标签:ShowNum Keynum1 51 按下 unsigned Delay 单片机 LCD 详解

一、基本功能介绍:

1.时钟系统(TIME-24h)

1.可根据当地时间自由修改!(非联网)

按下按键S1

                                                   默认时间05:12:01(小彩蛋*1)

                      使用定时器完成,保证在执行其他功能时,这套时钟系统能够自动刷新

2.定时器初始化代码如下:

#include <REGX52.H>
/**
  * @brief  定时器0初始化,1毫秒@11.0592MHz
  * @param  无
  * @param  无
  * @retval 无
  */
    
  
//由软件生成的定时器计算,注意每次要重新配置参数
void Timer0_Init(void)		
{
	//AUXR &= 0x7F;			//(89C52因为版本老没有这个寄存器)定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	
	//(补上)
	ET0=1;//允许中断
	EA=1;//允许总中断
	PT0=0;//中断优先级为0
}



/*
void Timer0_Init()//定时器+中断系统的初始化函数
{
	
	//原理图在开发手册P190
	//TMOD=0x01;  
	//0000 0001  from 开发手册P189-定时器工作模式
	//TMOD是不可位寻址只能整体赋值	
	
	
	TMOD=TMOD&0xF0;//把TMOD的低四位清零,高四位保持不变
	/*
	假设TMOD为
	1010 0011
	1010 0011 & 1111 0000 = 1010 0000
	TMOD=TMOD&0xF
	低四位清零,高四位保持不变

	
	
	TMOD=TMOD|0x01;//把TMOD的最低位改为1,高四位保持不变

	1010 0000 | 0000 0001 =1010 0001
	最低位改为1,高四位保持不变
	
	
	TF0=0;   //from 开发手册P188-定时器控制-中断
	//TCOM是可位寻址可以对其中的每一位单独赋值,TF0就是其中一位
	
	
	TR0=1;  //from 开发手册P188-定时器控制-开始计数
	
	

	0~65535
	每隔一微秒计数加一
	总共定时时间位65535微秒
	如果赋初始值为64535,距离计数器计数器溢出差值1000
	所以计时时间为1毫秒
	P190原理图

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

16进制存储在两个寄存器,分高低位

如果以10进制为例子
123存储在两个寄存器内
123/100=1(高位)
123%100=23(低位)


//下面是中断系统的初始化,是老一代51单片机,现在单片机可以向下兼容的。
	ET0=1;
	EA=1;
	PT0=0;

}
*/



/*初始化后如何在主代码中使用定时器T0的功能,定时器T0的中断号为1

举个例子

void Timer0_Routine() interrupt 1
{   
	static unsigned int T0Count;//退出此程序后不刷新数据,保留数据,称为局内的静态数据
	TL0 = 0x66;
	TH0 = 0xFC; 
	//计时器溢出默认为0,下一次中断会变成65倍的时间
	//将其设定为
	T0Count++;
	if(T0Count>=500)
	{
		T0Count=0;
		
	}

	
}
*/

3.使用定时器代码如下:

void Timer0_Routine() interrupt 1
{   
	static unsigned int T0Count;//退出此程序后不刷新数据,保留数据,称为局内的静态数据
	TL0 = 0x66;
	TH0 = 0xFC; 
	//计时器溢出默认为0,下一次中断会变成65倍的时间
	//将其设定为
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		Sec++;
		if(Sec>=60)
		{
			Sec=0;
			Min++;
			if(Min>=60)
			{
				Min=0;
				Hou++;
				if(Hou>=24)
				{
					Hou=0;
				}				
			}	
		}
	}

4.显示时间代码如下:

		if(a==1)//调整至时钟模式
		{
			
			for(i=1;i>0;i--)
			{
				LCD_ShowString(1,1,"TIME:");
				LCD_ShowString(2,1,"  :  :  ");
			}
			
			LCD_ShowNum(2,1,Hou,2);
			LCD_ShowNum(2,4,Min,2);		
			LCD_ShowNum(2,7,Sec,2);

        }

二、进阶功能介绍:

1.使用独立按键调节时钟系统的时间(TIME)

按下K1,增加一小时

按下K2,增加一分钟

按下K3,增加一秒钟

代码如下:

		KeyNum=Key();//按下独立按键,键码范围:1~4;无按键按下时为0
		Keynum1=MatrixKey();//按下矩阵按键,键码范围:1~16;此处无按键按下时候,数值不变0
		a=Keynum1;		
        if(a==1)//调整至时钟模式,自由调节时间,并且可以锁定时间
		{
			
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"TIME:");
				LCD_ShowString(2,1,"  :  :  ");
			}
			
			LCD_ShowNum(2,1,Hou,2);
			LCD_ShowNum(2,4,Min,2);		
			LCD_ShowNum(2,7,Sec,2);
		
			if(KeyNum==1 && state==0)//按下K1,增加1小时
			{
				Hou++;
				LCD_ShowNum(2,1,Hou,2);

				if(Hou>=24)
				{
					Hou=0;
				}							
			}
		
			if(KeyNum==2 && state==0)//按下K2,增加1分钟
			{
				Min++;
				LCD_ShowNum(2,4,Min,2);

				if(Min>=60)
				{
					Min=0;
					LCD_ShowNum(2,1,Hou,2);
					Hou++;
					if(Hou>=24)
					{
						Hou=0;
						LCD_ShowNum(2,1,Hou,2);
					}
				}								
			 }
		
		
			if(KeyNum==3 && state==0)//按下K3,增加1秒钟
			{
				Sec++;
				LCD_ShowNum(2,7,Sec,2);

				if(Sec>=60)
				{
					Sec=0;
					Min++;
					LCD_ShowNum(2,4,Min,2);
					if(Min>=60)
					{
						Min=0;
						LCD_ShowNum(2,1,Hou,2);
						Hou++;
						if(Hou>=24)
						{
							Hou=0;
							LCD_ShowNum(2,1,Hou,2);
						}
					}

				}							
			}

2.锁定时间(TIME)

按下K4,锁定时间,不可以使用按键调整时间

再次按下K4,解除时间锁定,可以再使用按键调整时间

			if(KeyNum==4 )//按下K4,增加和取消锁
			{
				state++;
				if(state>=2)
				{
					state=0;
				}
				if(state==1)
				{
					LCD_ShowString(1,10,"LOCKED");

				}
				if(state==0)
				{
					LCD_ShowString(1,9,"          ");
				}
			}

3.计时器系统-开始计时(TIMER)

按下S2开始计时

                                      已经计时5分30秒

代码如下:

		if(a==2)//调整至计时器模式
		{
			
//			LCD_ShowNum(1,12,a,2);
//			LCD_ShowNum(2,12,KeyNum,2);
			
			
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"TIMER       ");
				LCD_ShowString(2,1,"00:00:00");
			}
			
			
			
			
            //延时一秒,减少按键检测的延迟			
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			
		
			
			Sec1++;
								
		    if(Sec1>=60)
		    {
				Sec1=0;
				Min1++;
				if(Min1>=60)
				{
					Min1=0;
					Hou1++;
					if(Hou1>=24)
					{
						Hou1=0;
					}				
				}	
			}			
			LCD_ShowNum(2,1,Hou1,2);
			LCD_ShowNum(2,4,Min1,2);		
			LCD_ShowNum(2,7,Sec1,2);
						
		}

4.计时器系统-停止计时(TIMER)

按下S3停止计时

                                        按下S3后,计时器停留在5分30秒

代码如下:

		if(a==3)//停止计时
		{
			LCD_ShowNum(2,1,Hou1,2);
			LCD_ShowNum(2,4,Min1,2);		
			LCD_ShowNum(2,7,Sec1,2);														
		}

5.倒计时系统(COUNTDOWN)

按下S4进入倒计时系统

代码如下:

		if(a==4)//调整至倒计时模式
		{
//			LCD_ShowNum(1,12,a,2);
//			LCD_ShowNum(2,12,KeyNum,2);
			
			
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"COUNTDOWN               ");
				LCD_ShowString(2,1,"00:00:00");
			}
        }

6.设定倒计时(COUNTDOWN)

按下K1,增加一小时

按下K2,增加一分钟

按下K3,增加一秒钟

代码如下

			if(KeyNum==1 )//按下K1,增加1小时
			{
				Hou2++;
				LCD_ShowNum(2,1,Hou2,2);

				if(Hou2>=24)
				{
					Hou2=0;
				}							
			}
		
			if(KeyNum==2 )//按下K2,增加1分钟
			{
				Min2++;
				LCD_ShowNum(2,4,Min2,2);

				if(Min2>=60)
				{
					Min2=0;
					LCD_ShowNum(2,1,Hou2,2);
					Hou2++;
					if(Hou2>=24)
					{
						Hou2=0;
						LCD_ShowNum(2,1,Hou2,2);
					}
				}								
			 }
		
		
			if(KeyNum==3 )//按下K3,增加1秒钟
			{
				Sec2++;
				LCD_ShowNum(2,7,Sec,2);

				if(Sec2>=60)
				{
					Sec2=0;
					Min2++;
					LCD_ShowNum(2,4,Min2,2);
					if(Min2>=60)
					{
						Min2=0;
						LCD_ShowNum(2,1,Hou2,2);
						Hou2++;
						if(Hou2>=24)
						{
							Hou2=0;
							LCD_ShowNum(2,1,Hou2,2);
						}
					}

				}							
			}			
			
	
			LCD_ShowNum(2,1,Hou2,2);
			LCD_ShowNum(2,4,Min2,2);		
			LCD_ShowNum(2,7,Sec2,2);

7.开始倒计时(COUNTDOWN)

按下K4开始倒计时

                                                                 开始倒计时

代码如下:

			if(KeyNum==4 )//按下K4开始倒计时
			{
				for( ;Sec2>=0 ;Sec2-- )
				{	
				
					if(a==16)
					{
						Hou2=0,Min2=0,Sec2=0;
						i=1;
						LCD_ShowString(1,1,"                    ");
						LCD_ShowString(2,1,"                    ");						
					}								
                    if(Sec2==0 )
					{
						if(Min2>=1)
						{
							Min2--;	
							Sec2=59;
						}						
						if(Sec2==0 && Min2==0 && Hou2>=1)
						{
							LCD_ShowString(2,1,"01:00:00                    ");
							LCD_ShowNum(2,1,Hou2,2);
							Delay(1000);
							Hou2--;
							Min2=59;
							Sec2=59;
						}
					}
										
					LCD_ShowNum(2,1,Hou2,2);
					LCD_ShowNum(2,4,Min2,2);		
					LCD_ShowNum(2,7,Sec2,2);
															
					//延时一秒,减少按键检测的延迟			
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;	
										
//					LCD_ShowNum(1,15,Sec2,2);
										
				}
				Sec2=0;
				LCD_ShowNum(2,7,Sec2,2);								
			}

8.闹钟系统(CLOCK)

按下S5进入闹钟系统

		if(a==5)//定闹钟
		{
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"CLOCK:");
				LCD_ShowString(2,1,"  :  :  ");
			}		
        }

9.设定闹钟时间(CLOCK)

按下K1,增加一小时

按下K2,增加一分钟

按下K3,增加一秒钟

代码如下:

			if(KeyNum==1 )//按下K1,增加1小时
			{
				Hou3++;
				LCD_ShowNum(2,1,Hou3,2);

				if(Hou3>=24)
				{
					Hou3=0;
				}							
			}
		
			if(KeyNum==2 )//按下K2,增加1分钟
			{
				Min3++;
				LCD_ShowNum(2,4,Min3,2);

				if(Min3>=60)
				{
					Min3=0;
					LCD_ShowNum(2,1,Hou3,2);
					Hou3++;
					if(Hou3>=24)
					{
						Hou3=0;
						LCD_ShowNum(2,1,Hou3,2);
					}
				}								
			 }
		
		
			if(KeyNum==3 )//按下K3,增加1秒钟
			{
				Sec3++;
				LCD_ShowNum(2,7,Sec3,2);

				if(Sec3>=60)
				{
					Sec3=0;
					Min3++;
					LCD_ShowNum(2,4,Min3,2);
					if(Min3>=60)
					{
						Min3=0;
						LCD_ShowNum(2,1,Hou3,2);
						Hou3++;
						if(Hou3>=24)
						{
							Hou3=0;
							LCD_ShowNum(2,1,Hou3,2);
						}
					}

				}							
			}			
					
			LCD_ShowNum(2,1,Hou3,2);
			LCD_ShowNum(2,4,Min3,2);		
			LCD_ShowNum(2,7,Sec3,2);			

		}

(时钟系统)到达闹钟时间,显示Time is over!!:

代码如下

		if(Sec==Sec3 && Hou==Hou3 && Min==Min3)
		{
				LCD_ShowString(1,1,"Time is over!    ");
			LCD_ShowString(2,1,"  :  :     ");
			
		}

10.不同系统间的切换

先按S16清空

再按相应系统对应的按键,实现系统间的切换

代码如下:

		if(a==16)//每次切换功能的时候要先按下按键5进行复位
		{
			i=1;
			LCD_ShowString(1,1,"                   ");
			LCD_ShowString(2,1,"                    ");
			Hou1=0,Min1=0,Sec1=0;
			Hou2=0,Min2=0,Sec2=0;
		}

三、模块化代码:

1.LCD1602.c

#include <REGX52.H>
 
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
 
//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
    unsigned char i, j;
 
    i = 2;
    j = 239;
    do
    {
        while (--j);
    } while (--i);
}
 
/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
    LCD_RS=0;
    LCD_RW=0;
    LCD_DataPort=Command;
    LCD_EN=1;
    LCD_Delay();
    LCD_EN=0;
    LCD_Delay();
}
 
/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
    LCD_RS=1;
    LCD_RW=0;
    LCD_DataPort=Data;
    LCD_EN=1;
    LCD_Delay();
    LCD_EN=0;
    LCD_Delay();
}
 
/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
    if(Line==1)
    {
        LCD_WriteCommand(0x80|(Column-1));
    }
    else if(Line==2)
    {
        LCD_WriteCommand(0x80|(Column-1+0x40));
    }
}
 
/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
    LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
    LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
    LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
    LCD_WriteCommand(0x01);//光标复位,清屏
}
 
/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
    LCD_SetCursor(Line,Column);
    LCD_WriteData(Char);
}
 
/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
    unsigned char i;
    LCD_SetCursor(Line,Column);
    for(i=0;String[i]!='\0';i++)
    {
        LCD_WriteData(String[i]);
    }
}
 
/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
    unsigned c;
    char i;
    int Result=1;
    for(i=0;i<Y;i++)
    {
        Result*=X;
    }
    return Result;
}
 
/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    LCD_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
    }
}
 
/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
    unsigned char i;
    unsigned int Number1;
    LCD_SetCursor(Line,Column);
    if(Number>=0)
    {
        LCD_WriteData('+');
        Number1=Number;
    }
    else
    {
        LCD_WriteData('-');
        Number1=-Number;
    }
    for(i=Length;i>0;i--)
    {
        LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
    }
}
 
/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i,SingleNumber;
    LCD_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        SingleNumber=Number/LCD_Pow(16,i-1)%16;
        if(SingleNumber<10)
        {
            LCD_WriteData(SingleNumber+'0');
        }
        else
        {
            LCD_WriteData(SingleNumber-10+'A');
        }
    }
}
 
/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    LCD_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
    }
}

2.LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__
 
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
 
#endif

3.Timer0.c

#include <REGX52.H>
/**
  * @brief  定时器0初始化,1毫秒@11.0592MHz
  * @param  无
  * @param  无
  * @retval 无
  */
    
  
//由软件生成的定时器计算,注意每次要重新配置参数
void Timer0_Init(void)		
{
	//AUXR &= 0x7F;			//(89C52因为版本老没有这个寄存器)定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	
	//(补上)
	ET0=1;//允许中断
	EA=1;//允许总中断
	PT0=0;//中断优先级为0
}



/*
void Timer0_Init()//定时器+中断系统的初始化函数
{
	
	//原理图在开发手册P190
	//TMOD=0x01;  
	//0000 0001  from 开发手册P189-定时器工作模式
	//TMOD是不可位寻址只能整体赋值	
	
	
	TMOD=TMOD&0xF0;//把TMOD的低四位清零,高四位保持不变
	/*
	假设TMOD为
	1010 0011
	1010 0011 & 1111 0000 = 1010 0000
	TMOD=TMOD&0xF
	低四位清零,高四位保持不变

	
	
	TMOD=TMOD|0x01;//把TMOD的最低位改为1,高四位保持不变

	1010 0000 | 0000 0001 =1010 0001
	最低位改为1,高四位保持不变
	
	
	TF0=0;   //from 开发手册P188-定时器控制-中断
	//TCOM是可位寻址可以对其中的每一位单独赋值,TF0就是其中一位
	
	
	TR0=1;  //from 开发手册P188-定时器控制-开始计数
	
	

	0~65535
	每隔一微秒计数加一
	总共定时时间位65535微秒
	如果赋初始值为64535,距离计数器计数器溢出差值1000
	所以计时时间为1毫秒
	P190原理图

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

16进制存储在两个寄存器,分高低位

如果以10进制为例子
123存储在两个寄存器内
123/100=1(高位)
123%100=23(低位)


//下面是中断系统的初始化,是老一代51单片机,现在单片机可以向下兼容的。
	ET0=1;
	EA=1;
	PT0=0;

}
*/



/*初始化后如何在主代码中使用定时器T0的功能,定时器T0的中断号为1

举个例子

void Timer0_Routine() interrupt 1
{   
	static unsigned int T0Count;//退出此程序后不刷新数据,保留数据,称为局内的静态数据
	TL0 = 0x66;
	TH0 = 0xFC; 
	//计时器溢出默认为0,下一次中断会变成65倍的时间
	//将其设定为
	T0Count++;
	if(T0Count>=500)
	{
		T0Count=0;
		
	}

	
}
*/

4.Timer.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

#endif

5.Delay.c

void Delay(unsigned int xms)	
{
	unsigned char data i, j;
	while(xms--)
	{
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
	}
}

6.Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

7.Key.c

#include <REGX52.H>
#include "Delay.h"
/**
  * @brief  获取独立按键的键码
  * @param  无
  * @param  无
  * @retval 按下按键的键码,范围:1~4;无按键按下时为0
  */
unsigned char Key()
{
	unsigned char Keynumber=0;
	
	if(P3_1==0)//K1
	{
		Delay(20);
		while(P3_1==0)
		{
			Delay(20);
		}
		Keynumber=1;	
	}
	
		if(P3_0==0)//K2
	{
		Delay(20);
		while(P3_0==0)
		{
			Delay(20);
		}
		Keynumber=2;	
	}
	
		if(P3_2==0)//K3
	{
		Delay(20);
		while(P3_2==0)
		{
			Delay(20);
		}
		Keynumber=3;	
	}
	
		if(P3_3==0)//K4
	{
		Delay(20);
		while(P3_3==0)
		{
			Delay(20);
		}
		Keynumber=4;	
	}
	
	
	
	
	return Keynumber;
	
}

8.Key.h

#ifndef __KEY_H__
#define __KEY_H__

	unsigned char Key();
	
	
#endif

9.MatrixKey.c

#include <REGX52.H>
#include "Delay.h"
/**
  * @brief 矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
  如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键的键码,没有按键按下的时候放回0
  */	
int KeyNumber=0;
int MatrixKey()
{
	//矩阵扫描,按一行或者按一列,依次输入扫描,要扫描的给0,其余给1

	
	P1=0xFF; //默认都是1(高电平)
	P1_3=0;
	//检测按键按下,就是判断是否变成0
	if(P1_7==0)//1行1列的按钮=1
{
	Delay(20);
	while(P1_7==0)
	{
		Delay(20);
	}
	KeyNumber=1;
}


	if(P1_6==0)//2行1列的按钮=5
{
	Delay(20);
	while(P1_6==0)
	{
		Delay(20);
	}
	KeyNumber=5;
}


	if(P1_5==0)//3行1列的按钮=9
{
	Delay(20);
	while(P1_5==0)
	{
		Delay(20);
	}
	KeyNumber=9;
}


	if(P1_4==0)//4行1列的按钮=13
{
	Delay(20);
	while(P1_4==0)
	{
		Delay(20);
	}
	KeyNumber=13;
}

	
	P1=0xFF; //默认都是1(高电平)
	P1_2=0;
	//检测按键按下,就是判断是否变成0
	if(P1_7==0)//1行2列的按钮=2
{
	Delay(20);
	while(P1_7==0)
	{
		Delay(20);
	}
	KeyNumber=2;
}


	if(P1_6==0)//2行2列的按钮=6
{
	Delay(20);
	while(P1_6==0)
	{
		Delay(20);
	}
	KeyNumber=6;
}


	if(P1_5==0)//3行2列的按钮=10
{
	Delay(20);
	while(P1_5==0)
	{
		Delay(20);
	}
	KeyNumber=10;
}

	if(P1_4==0)//4行2列的按钮=14
{
	Delay(20);
	while(P1_4==0)
	{
		Delay(20);
	}
	KeyNumber=14;	
}
		
	
	P1=0xFF; //默认都是1(高电平)
	P1_1=0;	
	//检测按键按下,就是判断是否变成0
	if(P1_7==0)//1行3列的按钮=3
{
	Delay(20);
	while(P1_7==0)
	{
		Delay(20);
	}
	KeyNumber=3;
}


	if(P1_6==0)//2行3列的按钮=7
{
	Delay(20);
	while(P1_6==0)
	{
		Delay(20);
	}
	KeyNumber=7;
}

	if(P1_5==0)//3行3列的按钮=11
{
	Delay(20);
	while(P1_5==0)
	{
		Delay(20);
	}
	KeyNumber=11;
}

	if(P1_4==0)//4行3列的按钮=15
{
		Delay(20);
	while(P1_4==0)
	{
		Delay(20);
	}
	KeyNumber=15;
}
	

	P1=0xFF; //默认都是1(高电平)
	P1_0=0;
    //检测按键按下,就是判断是否变成0
	if(P1_7==0)//1行4列的按钮=4
{
	Delay(20);
	while(P1_7==0)
	{
		Delay(20);
	}
	KeyNumber=4;
}


	if(P1_6==0)//2行4列的按钮=8
{
	Delay(20);
	while(P1_6==0)
	{
		Delay(20);
	}
	KeyNumber=8;
}


	if(P1_5==0)//3行4列的按钮=12
{
	Delay(20);
	while(P1_5==0)
	{
		Delay(20);
	}
	KeyNumber=12;
}


	if(P1_4==0)//4行4列的按钮=16
{
	Delay(20);
	while(P1_4==0)
	{
		Delay(20);
	}
	KeyNumber=16;
}

	return KeyNumber;
}

10.MatrixKey.h

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char MatrixKey();

#endif

四、主代码:

#include <REGX52.H>
#include "Delay.h"//使用Delay函数的时候定时器仍然在工作,但是LCD1602没有刷新
#include "LCD1602.h"
#include "Timer0.h"
#include "Key.h"
#include "MatrixKey.h"


unsigned char Hou=05,Min=12,Sec=01;
unsigned char KeyNum=0;//检测独立按键
unsigned char state=0;//独立按键4可以改变state=0时可以自由更改时间,state=1时锁定不可以更改时间


/*
	此程序矩阵键盘做过改动(让声明数据类型和赋值放在花括号外)
	矩阵键盘,不按的时候数值会保留
	独立键盘,不按的时候数值会清0;
*/




unsigned char Keynum1=0;//检测矩阵按键
unsigned char a=1;//矩阵键盘改变a状态,达成不同的功能
unsigned char i=1;//使用for循环一次,避免不断刷新导致的LED屏幕高频闪烁
/*
	a==1时,显示现在的时间,定时器在后台刷新时间
	
	
	a==2时,跳转至计时模式
	a==3时,停止计时,并且显示当前累计的计时
	
	a==4时,开始设定时间并开始倒计时
	
	
	a==6时,开始设定闹钟
	a==16时,复位
*/

int Hou1=0,Min1=0,Sec1=0;//计时器调用的时间变量
int state1=0,Hou2=0,Min2=0,Sec2=0;//倒计时调用的变量
int Hou3=0,Min3=0,Sec3=0;//闹钟调用的变量




void main()
{
	LCD_Init();
	Timer0_Init();
	
	LCD_ShowString(1,1,"CLOCK SYSTEM");
 
	Delay(1000);
	LCD_ShowString(1,1,"DESINGER:MLS");
	//字符串内可以加空格,以取代刷新屏幕的作用
	Delay(1000);
	LCD_ShowString(1,1,"                 ");
	
	
	while(1)
	{

		
		KeyNum=Key();//按下独立按键,键码范围:1~4;无按键按下时为0
		Keynum1=MatrixKey();//按下矩阵按键,键码范围:1~16;此处无按键按下时候,数值不变0
		a=Keynum1;
	
		
		if(a==16)//每次切换功能的时候要先按下按键5进行复位
		{
			i=1;
			LCD_ShowString(1,1,"                   ");
			LCD_ShowString(2,1,"                    ");
			Hou1=0,Min1=0,Sec1=0;
			Hou2=0,Min2=0,Sec2=0;
		}
		
		if(a==1)//调整至时钟模式,自由调节时间,并且可以锁定时间
		{
			
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"TIME:");
				LCD_ShowString(2,1,"  :  :  ");
			}
			
			LCD_ShowNum(2,1,Hou,2);
			LCD_ShowNum(2,4,Min,2);		
			LCD_ShowNum(2,7,Sec,2);
		
			if(KeyNum==1 && state==0)//按下K1,增加1小时
			{
				Hou++;
				LCD_ShowNum(2,1,Hou,2);

				if(Hou>=24)
				{
					Hou=0;
				}							
			}
		
			if(KeyNum==2 && state==0)//按下K2,增加1分钟
			{
				Min++;
				LCD_ShowNum(2,4,Min,2);

				if(Min>=60)
				{
					Min=0;
					LCD_ShowNum(2,1,Hou,2);
					Hou++;
					if(Hou>=24)
					{
						Hou=0;
						LCD_ShowNum(2,1,Hou,2);
					}
				}								
			 }
		
		
			if(KeyNum==3 && state==0)//按下K3,增加1秒钟
			{
				Sec++;
				LCD_ShowNum(2,7,Sec,2);

				if(Sec>=60)
				{
					Sec=0;
					Min++;
					LCD_ShowNum(2,4,Min,2);
					if(Min>=60)
					{
						Min=0;
						LCD_ShowNum(2,1,Hou,2);
						Hou++;
						if(Hou>=24)
						{
							Hou=0;
							LCD_ShowNum(2,1,Hou,2);
						}
					}

				}							
			}
		
			if(KeyNum==4 )//按下K4,增加和取消锁
			{
				state++;
				if(state>=2)
				{
					state=0;
				}
				if(state==1)
				{
					LCD_ShowString(1,10,"LOCKED");

				}
				if(state==0)
				{
					LCD_ShowString(1,9,"          ");
				}
			}
							
		}
		
		
		
		if(a==2)//调整至计时器模式
		{
			
//			LCD_ShowNum(1,12,a,2);
//			LCD_ShowNum(2,12,KeyNum,2);
			
			
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"TIMER       ");
				LCD_ShowString(2,1,"00:00:00");
			}
			
			
			
			
            //延时一秒,减少按键检测的延迟			
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			Delay(100);Keynum1=MatrixKey();a=Keynum1;
			
		
			
			Sec1++;
								
		    if(Sec1>=60)
		    {
				Sec1=0;
				Min1++;
				if(Min1>=60)
				{
					Min1=0;
					Hou1++;
					if(Hou1>=24)
					{
						Hou1=0;
					}				
				}	
			}			
			LCD_ShowNum(2,1,Hou1,2);
			LCD_ShowNum(2,4,Min1,2);		
			LCD_ShowNum(2,7,Sec1,2);
						
		}
		
		
		
		if(a==3)//停止计时
		{
			LCD_ShowNum(2,1,Hou1,2);
			LCD_ShowNum(2,4,Min1,2);		
			LCD_ShowNum(2,7,Sec1,2);														
		}
		
		
		
		
		if(a==4)//调整至倒计时模式
		{
//			LCD_ShowNum(1,12,a,2);
//			LCD_ShowNum(2,12,KeyNum,2);
			
			
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"COUNTDOWN               ");
				LCD_ShowString(2,1,"00:00:00");
			}
		
			
			
			if(KeyNum==1 )//按下K1,增加1小时
			{
				Hou2++;
				LCD_ShowNum(2,1,Hou2,2);

				if(Hou2>=24)
				{
					Hou2=0;
				}							
			}
		
			if(KeyNum==2 )//按下K2,增加1分钟
			{
				Min2++;
				LCD_ShowNum(2,4,Min2,2);

				if(Min2>=60)
				{
					Min2=0;
					LCD_ShowNum(2,1,Hou2,2);
					Hou2++;
					if(Hou2>=24)
					{
						Hou2=0;
						LCD_ShowNum(2,1,Hou2,2);
					}
				}								
			 }
		
		
			if(KeyNum==3 )//按下K3,增加1秒钟
			{
				Sec2++;
				LCD_ShowNum(2,7,Sec,2);

				if(Sec2>=60)
				{
					Sec2=0;
					Min2++;
					LCD_ShowNum(2,4,Min2,2);
					if(Min2>=60)
					{
						Min2=0;
						LCD_ShowNum(2,1,Hou2,2);
						Hou2++;
						if(Hou2>=24)
						{
							Hou2=0;
							LCD_ShowNum(2,1,Hou2,2);
						}
					}

				}							
			}			
			
	
			LCD_ShowNum(2,1,Hou2,2);
			LCD_ShowNum(2,4,Min2,2);		
			LCD_ShowNum(2,7,Sec2,2);			
						
			if(KeyNum==4 )//按下K4开始倒计时
			{
				for( ;Sec2>=0 ;Sec2-- )
				{	
				
					if(a==16)
					{
						Hou2=0,Min2=0,Sec2=0;
						i=1;
						LCD_ShowString(1,1,"                    ");
						LCD_ShowString(2,1,"                    ");
						
					}
								
                    if(Sec2==0 )
					{
						if(Min2>=1)
						{
							Min2--;	
							Sec2=59;
						}
						
						if(Sec2==0 && Min2==0 && Hou2>=1)
						{
							LCD_ShowString(2,1,"01:00:00                    ");
							LCD_ShowNum(2,1,Hou2,2);
							Delay(1000);
							Hou2--;
							Min2=59;
							Sec2=59;
						}
					}
										
					LCD_ShowNum(2,1,Hou2,2);
					LCD_ShowNum(2,4,Min2,2);		
					LCD_ShowNum(2,7,Sec2,2);
					
										
					//延时一秒,减少按键检测的延迟			
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;
					Delay(100);Keynum1=MatrixKey();a=Keynum1;	
										
//					LCD_ShowNum(1,15,Sec2,2);
										
				}
				Sec2=0;
				LCD_ShowNum(2,7,Sec2,2);								
			}
			
		}
	
		
		if(a==5)//定闹钟
		{
			for(;i>0;i--)
			{
				LCD_ShowString(1,1,"CLOCK:");
				LCD_ShowString(2,1,"  :  :  ");
			}			
			
			if(KeyNum==1 )//按下K1,增加1小时
			{
				Hou3++;
				LCD_ShowNum(2,1,Hou3,2);

				if(Hou3>=24)
				{
					Hou3=0;
				}							
			}
		
			if(KeyNum==2 )//按下K2,增加1分钟
			{
				Min3++;
				LCD_ShowNum(2,4,Min3,2);

				if(Min3>=60)
				{
					Min3=0;
					LCD_ShowNum(2,1,Hou3,2);
					Hou3++;
					if(Hou3>=24)
					{
						Hou3=0;
						LCD_ShowNum(2,1,Hou3,2);
					}
				}								
			 }
		
		
			if(KeyNum==3 )//按下K3,增加1秒钟
			{
				Sec3++;
				LCD_ShowNum(2,7,Sec3,2);

				if(Sec3>=60)
				{
					Sec3=0;
					Min3++;
					LCD_ShowNum(2,4,Min3,2);
					if(Min3>=60)
					{
						Min3=0;
						LCD_ShowNum(2,1,Hou3,2);
						Hou3++;
						if(Hou3>=24)
						{
							Hou3=0;
							LCD_ShowNum(2,1,Hou3,2);
						}
					}

				}							
			}			
			
					
			LCD_ShowNum(2,1,Hou3,2);
			LCD_ShowNum(2,4,Min3,2);		
			LCD_ShowNum(2,7,Sec3,2);			
			
					
			
			
		}
		

	
	
		if(Sec==Sec3 && Hou==Hou3 && Min==Min3)
		{
				LCD_ShowString(1,1,"Time is over!    ");
			LCD_ShowString(2,1,"  :  :     ");
			
		}
			
		
	
	
	
	}
}















void Timer0_Routine() interrupt 1
{   
	static unsigned int T0Count;//退出此程序后不刷新数据,保留数据,称为局内的静态数据
	TL0 = 0x66;
	TH0 = 0xFC; 
	//计时器溢出默认为0,下一次中断会变成65倍的时间
	//将其设定为
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		Sec++;
		if(Sec>=60)
		{
			Sec=0;
			Min++;
			if(Min>=60)
			{
				Min=0;
				Hou++;
				if(Hou>=24)
				{
					Hou=0;
				}				
			}	
		}
	}

	
}

五、Keil5界面:

                                                                谢谢大家!

                                                        小白一枚,请多指教!                                                               

                                                         FROM 明月清风mls

标签:ShowNum,Keynum1,51,按下,unsigned,Delay,单片机,LCD,详解
From: https://blog.csdn.net/weixin_67341796/article/details/140185437

相关文章

  • 详解前缀码与前缀编码
    前缀编码是一种数据压缩技术,也被称为可变长度编码。它的基本原理是将频繁出现的字符或字符序列用较短的编码表示,而较少出现的字符或字符序列用较长的编码表示,从而达到压缩数据的目的。概念定义前缀码:给定一个编码序列的集合,若不存在一个序列是另一个序列的前缀,则该序列......
  • Appium+python自动化(四十二)- 寿终正寝完结篇 - 结尾有惊喜,过时不候(超详解)
    1.简介 按照上一篇的计划,今天给小伙伴们分享执行测试用例,生成测试报告,以及自动化平台。今天这篇分享讲解完。Appium自动化测试框架就要告一段落了。2.执行测试用例&报告生成 测试报告,宏哥已经讲解了testng、HTMLTestRunner、allure等等,今天就在讲解一个新的测试报告BSTest......
  • ARMv8寄存器详解
    文章目录一、ARMv8寄存器介绍二、通用寄存器三、PSTAE寄存器四、特殊寄存器五、系统寄存器一、ARMv8寄存器介绍本文我来给大家介绍一下ARMv8的寄存器部分,ARMv8中有34个寄存器,包括31个通用寄存器、一个栈指针寄存器SP(X31),一个程序计数器寄存器PC,一个处理器状态寄存......
  • scanf,getchar,gets知识详解
    1.scanf  scanf用于输入数据,它处理不了空格键和回车键(enter),两者其实都是字符,键盘上每一个键位都是一个字符,空格对对应'\0',回车对应'\n'。,scanf将处理不了的这两种键放入缓冲区。缓冲区类似数据结构中的队列,一边只负责进,一边只负责出。顺序进出。(1)当数据为单个字符时:......
  • Codeforces Round 951 (Div. 2)
    Preface这场由于下午四点约好了和祁神打乒乓球,因此两点开了一场VP,结果困得要死D题一个特判写挂了没看出来调了贼久然后E题秒出正解,但因为一个极其傻逼的地方挂了又没调出来,鉴定为纯纯的飞舞A.GuesstheMaximum签到,每次选的一定是相邻的两个#include<cstdio>#include<iost......
  • 基于51单片机的交通灯设计(含文档、源码与proteus仿真,以及系统详细介绍)
    目录引言实验环境原理图仿真图1设计任务与方案选择2 系统设计3 系统调试4 总结5 参考文献资源下载引言近年来随着科技的飞速发展,单片机的应用正在不断深入,同时带动传统控制检测技术日益更新。在实时检测和自动控制的单片机应用系统中,单片机往往作为一个核......
  • HTTP请求详解及其在嵌入式系统中的应用
    前言HTTP(HyperTextTransferProtocol,超文本传输协议)是互联网中最广泛使用的应用层协议,用于客户端和服务器之间的数据传输。了解HTTP请求的工作原理对于开发网络应用和嵌入式系统中的网络通信至关重要。本文将详细介绍HTTP请求的基本概念、类型、结构,并探讨其在嵌入式系统中的......
  • 零基础STM32单片机编程入门(八)定时器PWM输入实战含源码视频
    文章目录一.概要二.PWM输入框架图三.CubeMX配置一个PWM输入例程1.硬件准备2.创建工程3.调试四.CubeMX工程源代码下载五.讲解视频链接地址六.小结一.概要脉冲宽度调制(PWM),是英文“PulseWidthModulation”的缩写,简称脉宽调制,是利用单片机数字输出(1或0)来对外部模拟......
  • 基于Linux/ARM/单片机利用状态机对多个按键进行扫描实现短按或者长按
    1)Linux/ARM/单片机入门级按键扫描程序设计,分享给将要学习或者正在学习Linux/ARM/单片机开发的同学。2)内容属于原创,若转载,请说明出处。3)提供相关问题有偿答疑和支持。学习Linux/ARM/单片机的同学都会学习到一个知识点,就是按键扫描,本课题基于SigmaStar的平台SSC375芯片SOC详细......
  • Docker-文件分层与数据卷挂载详解(附案例)
    文章目录文件分层数据卷挂载的含义数据卷挂载实践数据卷挂载案例数据卷挂载方式数据卷常用命令容器间数据共享更多相关内容可查看文件分层例:拉取mysql5.7的镜像,在继续拉取mysql5.8的镜像,会出现一部分文件已存在的现象这种分层技术是docker强大的功能点之一......