一、基本功能介绍:
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