📄 lcd_clock.c
字号:
//=============================================
// 基于1602液晶显示可调时钟 //
//作者:万迅 2008年11月02日 //
//QQ:373179882 //
//E-mail:wanxunpcmo@163.com //
//使用AT89C51单片机 12MHz晶振 精确到毫秒 //
//=============================================
//库与数据缩写定义
#include <AT89X51.h> //包含AT89X51库
#define uc unsigned char //定义数据格式缩写
#define ui unsigned int //定义数据整形缩写
#define control_number 2 //定义可供调节的数据数
//=============================================
//与1602液晶显示模块(LCM)的接口定义
#define DB_BUS P2 //定义数据总线
sbit RS=P3^0; //定义:数据(1)/指令(0)使能引脚
sbit RW=P3^1; //定义:读(1)/写(0)使能信号
sbit E=P3^2; //定义执行操作使能信号,下降沿有效
sbit busy=DB_BUS^7; //定义忙信号
//=============================================
//定义按键接口
sbit FUN_KEY=P1^0; //定义功能键
sbit INC_KEY=P1^1; //定义增加键
sbit DEC_KEY=P1^2; //定义减少键
//=============================================
//定义相关数据
uc hou,min,sec,mil; //定义:小时(hou),分钟(min),秒(sec),毫秒(mil)
uc connum; //定义数据可调允许位,为0时不可调
bit k0,k1,k2; //定义按键状态位,防止因长按按键引起多次操作
//=============================================
//函数预定义
void writcode(uc cd); //写指令函数
void writdata(uc dat); //写数据函数
//=============================================
//液晶显示模块(LCM)初始化
void init_lcm()
{ writcode(0x38); //设置功能:8位通信;两行显示;5x7显示单元
writcode(0x38); //重写一次防止因1602通电时的假就绪而引起的功能设置失败
writcode(0x08); //关闭显示屏
writcode(0x01); //清屏
writcode(0x0c); //开显示屏并置光标不可见,光标所在字符不闪烁
writcode(0x06); //设置输入模式
}
//单片机基本初始化
void uart_init() //定义初始化定时函数
{ hou=min=sec=mil=0; //时,分,秒初始化
connum=0; //置数据可调允许位为0,即数据不可调节
k0=k1=k2=1; //按键状态初始化
TMOD=0x01; //定时计数工作方式1
IE=0x82; //允许定时计数中断0
TH0=0xd8; //
TL0=0xf0; //定时10ms
TR0=1; //开启定时计数器0
}
//每10ms中断一次的定时中断
//实现毫秒100进1,秒60进1,分钟60进1,小时24清零时钟功能
void timer0() interrupt 1 using 2
{ TH0=0xd8; //
TL0=0xf0; //定时10ms
if(mil>=99)
{ mil=0;
if(sec>=59)
{ sec=0;
if(min>=59)
{ min=0;
hou=hou>=23?0:++hou;
}
else ++min;
}
else ++sec;
}
else ++mil;
}
//等待空闲函数
//检查忙状态,等待空闲
void chkbusy()
{ RS=0; //定义数据类型为指令
E=1; //置E为1
RW=1; //RW为“1”,使能信号E为“1”表示从总线读数据
DB_BUS=0xff; //置数据总线为0xff以便正确读出忙信号
while(!busy); //等待直到不忙为止
}
void writcode(uc cd)
{ chkbusy(); //等待空闲
RW=0; //数据操作为写
RS=0; //数据类型为指令
E=1;
DB_BUS=cd; //将指令写到数据总线端口
E=0; //E产生下跳沿将总线上的数据写入1602
}
void writdata(uc dat)
{ chkbusy(); //等待空闲
RW=0; //数据操作为写
E=1;
RS=1; //数据类型为数据
DB_BUS=dat; //将数据写到数据总线端口
E=0; //E产生下跳沿将总线上的数据写入1602
}
//屏幕显示函数
//注:指定DDRAM地址后每写一次数据DDRAM地址自动加一
void display()
{ writcode(0x80); //置DD RAM地址为0x00(0x80-0x80=0x00)
switch(connum) //屏幕显示的数据与DD RAM地数据相对应,初始时0x00对应屏幕上的第一行第一个字符
{ case 1:writdata('h');break; //数据可调允许位为1,即允许调节小时则写第一行第一个字符为‘h’
case 2:writdata('m');break; //数据可调允许位为2,即允许调节分钟则写第一行第一个字符为‘m’
default:writdata(' '); //数据不可调则清空第一行第一个字符
}
writdata(' '); //空出一格
writdata(hou/10+48); //取小时的十位并将其加48转换成其ASCII后写数据到DDRAM
writdata(hou%10+48); //取小时的个位并将其加48转换成其ASCII后写数据到DDRAM
writdata(':'); //编译器会自动将‘:’转换为ASCII码
writdata(min/10+48); //以下同理
writdata(min%10+48);
writdata(':');
writdata(sec/10+48);
writdata(sec%10+48);
writdata('-');;
writdata(mil/10+48);
writdata(mil%10+48);
writdata(' ');
hou>12?writdata('P'):writdata('A'); //小时大于12则显示‘P’小于则显示‘A’
writdata('M');
}
//按键检测函数
//
void chkkey()
{ if(k0==1&&FUN_KEY==0) //与标志位结合起来可判断按键的下跳沿
{ k0=0; //按键按下将标志位清零表示按键处于按下状态
connum=connum>=control_number? 0:++connum; //改变数据可调允许位的值
}
if(k1==1&&INC_KEY==0)
{ k1=0;
if(connum==1)hou=hou>=23?0:++hou; //按下加键根据数据可调允许位的值对数据进行操作
if(connum==2)min=min>=59?0:++min;
}
if(k2==1&&DEC_KEY==0)
{ k2=0;
if(connum==1)hou=hou==0?23:--hou; //按下减键根据数据可调允许位的值对数据进行操作
if(connum==2)min=min==0?59:--min;
}
k0=FUN_KEY?1:0; //一下操作使按键状态与标志位处以同一状态
k1=INC_KEY?1:0;
k2=DEC_KEY?1:0;
}
void main(void)
{ uart_init(); //对单片机进行基本初始化
init_lcm(); //初始化1602液晶显示模块
while(1)
{ display(); //屏幕显示
chkkey(); //按键检
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -