基于单片机的液晶日历时钟

发布者:gamma14最新更新时间:2016-09-12 来源: eefocus关键字:单片机  液晶日历时钟 手机看文章 扫描二维码
随时随地手机看文章
一、简介

本设计利用单片机AT89S52和1602液晶,实现日历(年月日)、星期和时间的显示。具体效果为:

2011-11-11 FRI

     11:11:11

二、设计图纸

1、电路原理图

基于单片机的液晶日历时钟 - 残缺的明镜 - 残缺的明镜

 2、PCB图

基于单片机的液晶日历时钟 - 残缺的明镜 - 残缺的明镜

 3、三维模型

基于单片机的液晶日历时钟 - 残缺的明镜 - 残缺的明镜

 三、相关程序

程序简介:程序启动后,先初始化液晶和两个定时器,时钟开始工作,再进入扫描检测调整时钟函数中,根据是否有KEY1长按来决定是否调整时钟。定时器T0用来产生时钟计时,T1用来中断显示液晶,按键KEY1为多功能按键,在时钟工作时,长按时进入时钟调整,依次调整年、月、日、星期、时、分,KEY2和KEY3分别为上下调整,每次调整完毕后短按KEY1返回,进入下一个调整。

1、主程序文件

#include "reg51.h"
#include "adjust.h"
#include "lcm.h"
#include "key.h"
//定时器初始化函数
void Timer_Start()
{
 TMOD=0x11;
 TH1=0xfc;
 TL1=0x18;
 TH0=0xfc;
 TL0=0x60; 
 EA=1;
 ET1=1;
 ET0=1;
 TR1=1;
 TR0=1;
}
//主函数
void main()
{
 unsigned char Key_Code;
 //初始化LCM
 LCM_START();
 //初始化定时器
 Timer_Start();
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_M:Adjust();break;
   default:break;
  }
 }
}

2、延时程序文件

(1)头文件

#ifndef __DELAY_H__
#define __DELAY_H__
extern void Delay_ms(unsigned int ms);
#endif

(2)程序文件

#include "delay.h"

//延时1毫秒函数
void Delay_ms(unsigned int ms)
{
 unsigned char Temp;
 while(ms--)
 for(Temp=0;Temp<120;Temp++);
}

2、时钟程序文件

(1)头文件

#ifndef __CLOCK_H__
#define __CLOCK_H__
extern unsigned int Second_Count;
extern char Second;
extern char Minute;
extern char Hour;
extern char Day;
extern char Month;
extern int  Year;
extern char Week;
extern char Month_Day[12];
extern bit Leap_Year(int Temp_Year);
#endif

(2)程序文件

#include "reg51.h"
//秒计数变量
unsigned int Second_Count=0;
//时分秒变量
char Second=53;
char Minute=20;
char Hour  =5;
char Day   =18;
char Month =4;
int  Year  =2011;
char Week  =1;
//每月天数数组
char Month_Day[12]={31,28,31,30,31,30,31,31,30,31,30,31};

//闰年判断函数
bit Leap_Year(int Temp_Year)
{
 bit Temp;
 if(((Temp_Year%4==0)&&(Temp_Year%100!=0))||(Temp_Year%400==0))
 {
  Temp=1;
 }
 else 
 {
  Temp=0;
 }
 return Temp;
}
//定时器0中断服务函数
void Timer0_Serve()interrupt 1
{
 TH0=0xfc;
 TL0=0x60;
 Second_Count++;
 if(Second_Count>1000)
 {
  Second_Count=0;
  Second++;
  if(Second>=60)
  {
   Second=0;
   Minute++;
   if(Minute>=60)
   {
    Minute=0;
 Hour++;
 if(Hour>=24)
 {
  Hour=0;
  Week++;if(Week>=7)Week=0;
  Day++;
  if(Day>Month_Day[Month-1])
  {
   if((Month!=2)||(!Leap_Year(Year))||(Day>29))
   {
    Day=1;
    Month++;
    if(Month>12)
    {
     Month=1;
     Year++;
    }
   }
  }
 }
   }
  }
 }
}

3、液晶程序文件

(1)头文件

#ifndef __LCM_SHOW_H__
#define __LCM_SHOW_H__  
extern void LCM_START();
extern void LCM_CMD (unsigned char Temp_Data);
extern void LCM_DATA(unsigned char Temp_Data);
extern void LCM_POS (unsigned char Temp_Data);
#endif

(2)程序

#include "reg51.h"
#include "delay.h"
#include "intrins.h"
//LCM控制端口定义
sbit RS=P2^5;//数据/命令选择端口
sbit RW=P2^6;//读写控制端口
sbit EN=P2^7;//使能端口

//定义商标字符
char code Logo1[]="WELCOME TO";
char code Logo2[]="MY MCU WORKSHOP!"; 

//LCM状态读取函数
bit LCM_Status()
{
 bit Temp_Status;
 RS=0;
 RW=1;
 EN=1;
 _nop_();
 Temp_Status=(bit)(P0&0x80);
 _nop_();
 EN=0;
 return Temp_Status;
}
//LCM写初始化命令函数
void LCM_INIT(unsigned char Temp_Data)
{
 RS=0;
 RW=0;
 EN=0;
 _nop_();
 P0=Temp_Data;
 _nop_();
 EN=1;
 _nop_();
 _nop_();
 EN=0;
}
//LCM写命令函数
void LCM_CMD(unsigned char Temp_Data)
{
 while(LCM_Status());
 RS=0;
 RW=0;
 EN=0;
 _nop_();
 P0=Temp_Data;
 _nop_();
 EN=1;
 _nop_();
 _nop_();
 EN=0;
}
//LCM写数据函数
void LCM_DATA(unsigned char Temp_Data)
{
 while(LCM_Status());
 RS=1;
 RW=0;
 EN=0;
 _nop_();
 P0=Temp_Data;
 _nop_();
 EN=1;
 _nop_();
 _nop_();
 EN=0;
}
//LCM显示位置设定函数
void LCM_POS(unsigned char Temp_Data)
{
 LCM_CMD(Temp_Data|0x80);

//LCM初始化函数
void LCM_START()
{
 unsigned char Temp;
 //写初始化指令三次但不检测忙信号
 LCM_INIT(0x38);
 Delay_ms(5);
 LCM_INIT(0x38);
 Delay_ms(5);
 LCM_INIT(0x38);
 Delay_ms(5);
 //写初始化命令字
 LCM_CMD(0x38);
 Delay_ms(1);
 //写清屏命令字
 LCM_CMD(0x01);
 Delay_ms(1);
 //写地址指针及光标自动移位命令字
 LCM_CMD(0x06);
 Delay_ms(1);
 //写开显示命令字
 LCM_CMD(0x0c);
 Delay_ms(1);

 Temp=0;
 //设定显示位置为第行4列
 LCM_POS(0x03);
 Delay_ms(1);
 //显示Logo第一行
 while(Logo1[Temp]!='\0')
 {
  LCM_DATA(Logo1[Temp]);
  Delay_ms(200);
  Temp++;
 }
 Temp=0;
 //设定显示位置为第二行1列
 LCM_POS(0x40);
 Delay_ms(1);
 //显示Logo第二行
 while(Logo2[Temp]!='\0')
 {
  LCM_DATA(Logo2[Temp]);
  Delay_ms(200);
  Temp++;
 }
 Delay_ms(2000);
 //Logo显示完了之后清屏
 LCM_CMD(0x01);
 Delay_ms(1);
}

4、时钟显示文件

(1)头文件

#ifndef __SHOW_H__
#define __SHOW_H__
extern unsigned char Show_Mark;
#endif

(2)程序文件

#include "reg51.h"
#include "lcm.h"
#include "clock.h"
#include "delay.h"
#include "adjust.h"
//显示计数
unsigned int Show_Count=0;
unsigned char Show_Mark=0;
//定义时钟显示字符串
char Date[]="2011-04-17 SUN";
char Time[]="12:30:30    ";
//定义二维周字符数组
char Week_Name[7][3]={"SUN","MON","TUE","WED","THU","FRI","SAT"};
char Adjust_Mark[7][2]={"  ","YY","MM","DD","WW","HH","MM"};
//LCM显示函数
void LCM_SHOW()
{
 unsigned char Temp;
 //显示之前转化日期为显示字符
 Date[0]=Year/1000+0x30;
 Date[1]=Year/100%10+0x30;
 Date[2]=Year/10%10+0x30;
 Date[3]=Year%10+0x30;
 Date[5]=Month/10+0x30;
 Date[6]=Month%10+0x30;
 Date[8]=Day/10+0x30;
 Date[9]=Day%10+0x30;
 Date[11]=Week_Name[Week][0];
 Date[12]=Week_Name[Week][1];
 Date[13]=Week_Name[Week][2];
 //显示之前转化时间为显示字符
 Time[0]=Hour/10+0x30;
 Time[1]=Hour%10+0x30;
 Time[3]=Minute/10+0x30;
 Time[4]=Minute%10+0x30;
 Time[6]=Second/10+0x30;
 Time[7]=Second%10+0x30;
 //显示设定标记
 Time[10]=Adjust_Mark[Show_Mark][0];
 Time[11]=Adjust_Mark[Show_Mark][1];
 Temp=0;
 //设定显示位置为第一行1列
 LCM_POS(0x01);
 Delay_ms(1);
 //显示日期和星期
 while(Date[Temp]!='\0')
 {
  LCM_DATA(Date[Temp]);
  Temp++;
 }
 Temp=0;
 //设定显示位置为第二行4列
 LCM_POS(0x44);
 Delay_ms(1);
 //显示时间
 while(Time[Temp]!='\0')
 {
  LCM_DATA(Time[Temp]);
  Temp++;
 }
}
//中断方式显示LCM
void Timer1_Serve()interrupt 3
{
 TH1=0xfc;
 TL1=0x18;
 Show_Count++;
 if(Show_Count>100)
 {
  Show_Count=0;
  LCM_SHOW();
 }
}

5、按键扫描文件

(1)头文件

#ifndef __KEY_SCAN_H__
#define __KEY_SCAN_H__
#define Key_M 0x10
#define Key_R 0x00
#define Key_U 0x01
#define Key_D 0x02
extern unsigned char Key_Scan();
#endif

(2)程序文件

#include "reg51.h"
#include "delay.h"
#include "key.h"
//按键端口定义
sbit Key1=P3^4;
sbit Key2=P3^5;
sbit Key3=P3^6;
//键盘扫描程序
unsigned char Key_Scan()
{
 //先扫描模式选择按键
 if(Key1==0)
 {
  Delay_ms(500); //延时0.5秒,一则为一次短按的最长时间,另则为延时去抖动
  if(Key1==0) //判断长短按键
  {
   while(!Key1);//等待按键释放
   Delay_ms(100);//消去释放抖动
   return Key_M;
  }
  else 
  {
   return Key_R;
  }
 }
 else 
 if(Key2==0)  //扫描加一键,有长按不断调整功能
 {
  Delay_ms(300);
  return Key_U;
 }
 else 
 if(Key3==0)
 {
  Delay_ms(300); //扫描减一键,有长按不断调整功能
  return Key_D;
 }
 else return 0xff;
}

6、时钟调整文件

(1)头文件

#ifndef __ADJUST_H__
#define __ADJUST_H__
extern void Adjust();
#endif

(2)程序文件

#include "reg51.h" 
#include "Clock.h"
#include "adjust.h"
#include "show.h"
#include "Key.h"

//调整年函数
void Adjust_Year()
{
 unsigned char Key_Code;
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_R:return;
   case Key_U:Year++;break;
   case Key_D:Year--;break;
   default   :break;
  }
 }
}
//调整月函数
void Adjust_Month()
{
 unsigned char Key_Code;
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_R:return;
   case Key_U:Month++;if(Month>12)Month=1;break;
   case Key_D:Month--;if(Month<1)Month=12;break;
   default:break;
  }
 }
}
//调整日函数
void Adjust_Day()
{
 unsigned char Key_Code; 
 //调整日期之前先根据已经调整的月份修改日期
 if(Day>Month_Day[Month-1])     
 {
  if((Month!=2)||(!Leap_Year(Year))||(Day>29))Day=1;
 }
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_R:return;
   case Key_U:Day++;
              if(Day>Month_Day[Month-1])
     { 
      if((Month!=2)||(!Leap_Year(Year))||(Day>29))Day=1; 
     }
     break;
   case Key_D:Day--;
              if(Day<1)
     {
      if((Month==2)&&(Leap_Year(Year)))Day=29;       
      else Day = Month_Day[Month-1];
     }
              break;
   default   :break;
  }
 }
}
//调整星期函数
void Adjust_Week()
{
 unsigned char Key_Code;
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_R:return;
   case Key_U:Week++;if(Week>=7)Week=0;break;
   case Key_D:Week--;if(Week<0) Week=6;break;
   default   :break;
  }
 }
}
//调整小时函数
void Adjust_Hour()
{
 unsigned char Key_Code;
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_R:return;
   case Key_U:Hour++;if(Hour>=24)Hour= 0;break;
   case Key_D:Hour--;if(Hour<0)  Hour=23;break;
   default:break;
  }
 }
}

//调整分钟闪烁函数
void Adjust_Minute()
{
 unsigned char Key_Code;
 while(1)
 {
  Key_Code=Key_Scan();
  switch(Key_Code)
  {
   case Key_R:return;
   case Key_U:Minute++;if(Minute>=60)Minute= 0;break;
   case Key_D:Minute--;if(Minute<0)  Minute=59;break;
   default:break;
  }
 }
}
//总调整函数
void Adjust()
{
 //调整之前先暂停时钟
 TR0=0;
 //秒相关量清零
 Second=0;
 Second_Count=0;
 //调整年
 Show_Mark=1;
 Adjust_Year();
 //调整月
 Show_Mark=2;
 Adjust_Month();
 //调整日
 Show_Mark=3;
 Adjust_Day();
 //调整周
 Show_Mark=4;
 Adjust_Week();
 //调整小时
 Show_Mark=5;
 Adjust_Hour();
 //调整分钟
 Show_Mark=6;
 Adjust_Minute();
 //调整完毕重启时钟
 Show_Mark=0;
 TR0=1;
}
 四、说明

1、由于使用单片机定时产生时钟脉冲,考虑到单片机定时的不精确性,虽然多次修改定时器0初始值,还是有每天1分钟左右的误差,因此本设计只是用来模拟时钟,如果要精确时间,可以采用时钟芯片DS1302来做实验。

2、本设计程序和电路都经实验验证,可靠工作,符合预期,如有兴趣,可以做出来实验一下。

3、如需本设计的程序,请留下足迹哦。

关键字:单片机  液晶日历时钟 引用地址:基于单片机的液晶日历时钟

上一篇:单片机接收命令发送脉冲
下一篇:基于单片机的简易报警器

推荐阅读最新更新时间:2024-03-16 15:09

51单片机实现贪食蛇的子程序
这是从 http://www.51hei.com/bbs/dpj-20623-1.html 这个 制作 里面截取的一段子程序,调用函数请下载里面的附件. 下面是mysanke.h文件: #ifndef _MYSNAKE_H_ #define _MYSNAKE_H_ /*--------------------------------------------------------- 函数功能:检测随机落食是否压在已存在的亮点上 调用形式:Check_Food(*node); 参数:结构体指针 返回值:返回食物是否可以放置1- 可以 0- 不可以 备注:食物产生函数调用此函数用于 检测 -----------------
[单片机]
51<font color='red'>单片机</font>实现贪食蛇的子程序
AVR单片机电子钟C程序
#include iom16v.h #include macros.h #define uchar unsigned char #define uint unsigned int #define setb(val,bitn) (val|=(1 (bitn)))//设置某IO口某位为1 #define clr(val,bitn) (val&=~(1 (bitn)))//设置某IO口某位为0 #define get(val,bitn) (val&(1 (bitn)))//读取某位状态 uchar shi=20,fen=39,miao,a=0xff,num; #pragma interrupt_handler zhong:9//它所对应
[单片机]
STM8单片机实现蓝牙串口通信系统的设计
最近在淘宝逛的时候发现了一款单片机,STM8。相比之前一直使用的也是8位的AVR相比,感觉STM8更为强大,芯片特点如下: 内核:具有3级流水线的哈佛结构、扩展指令集 程序存储器:8K字节Flash;RAM:1K字节 数据存储器:640字节真正的数据EEPROM;可达30万次擦写 更重要的一点就是STM8系列若使用库编程的话,可以方便的不同芯片的程序移植。甚至可以方便的移植到STM32上面,大大减轻了更新硬件的重写程序的工作量。 ADC0832为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在0~5V之间。芯片转换时间仅为32μS,据有双数
[单片机]
STM8<font color='red'>单片机</font>实现蓝牙串口通信系统的设计
51单片机软件程序复位
51单片机软件复位汇编代码 POP ACC ; pop return address POP ACC ;弹出PC MOV SP,#30H ;复位后SP为07H ,这样就会复位椎栈 MOV PSW,#00H ;清寄存器 CLR A ; push 0 as new PUSH ACC ; return address to stack PUSH ACC ;重置PC=0并压到椎栈中 RETI ; execute return of interrupt ;程序又开始从0000H处开始运行,但寄存器内的值不确定! 用
[单片机]
澎湃微电子:国产车规MCU的挑战及思考
2023年11月30日,在“芯向亦庄”2023汽车芯片产业大会上,谈及行业“内卷”,澎湃微电子创始人、董事长兼CEO钟旭恒表示,国内没有经过激烈内卷的行业都难以做到真正的强大,在激烈的竞争之后,往往会有非常强的公司脱颖而出。 钟旭恒坦言,车规MCU面临很多挑战。第一,电子系统快速演进。 新能源 车强势来袭后,行业发生了巨大变化,尤其当特斯拉入局后,几乎把之前的车规电子系统进行了颠覆性的革新。从最早的分布式MCU传统架构过渡到域控架构,现在比较热门的是中央计算加域控的架构。第二,我们做产品定义,我们到底要做什么样的产品定义?第三,可靠性与品质的挑战。汽车电子应用环境是比工业要更苛刻、更讲究。第四,工艺及产品的积累与创新。第五,人
[汽车电子]
澎湃微电子:国产车规<font color='red'>MCU</font>的挑战及思考
一种用单片机控制的采用电话遥控的简易远程教学系统
本文介绍了一种用单片机控制的采用电话遥控的简易远程教学系统。它借助于现有的丰富的电话网络资源,具有结构简单,造价低廉,易于操作等特点,可以实现对录像机的各种远距离控制操作。非常适合于贫困地区的电化教育的普及与发展。 1 系统的总体结构 该电话遥控教学系统的总体结构如图1所示。 该系统由电话机、小型程控机、远程控制器和数台录像机、电视机组成,该系统既可以通过小型程控机构成一个局域的小系统,也可以利用电信网构成一个跨省市的远距离遥控系统。在该系统中,远程控制器的设计与制造是该系统的核心与关键。 2 远程控制器的结构及工作原理 该控制器的 CPU 采用美国Microchip 公司生产的 PIC16C54 一次性用户可编程(O
[单片机]
一种用<font color='red'>单片机</font>控制的采用电话遥控的简易远程教学系统
8051单片机(STC89C52)八灯从中间往两边亮
#include STC89C5xRC.h void delay()//提供时延 { int i,j; for(i=0;i 120;i++) for(j=0;j 120;j++) { ; } } int main() { while(1) { P2=0xFF;//八灯全灭 delay(); P2=0xE7; delay(); P2=0xC3; delay(); P2=0x81; delay(); P2=0; delay(); } } 设计思路: 1 1 1 1 1 1 1 1 //P2=0xFF 1 1 1 0 0 1 1 1 //P2=0xE
[单片机]
基于GSM模块Q2403A和8051单片机实现短消息收发系统的应用方案
基于GSM短消息的业务不需要建立拨号连接,只需把待发的消息加上目的地址发送至短消息中心,再由短消息中心转发到最终目标。GSM 短消息业务以其连接简单、费用低廉、覆盖范围广、实现方便等优点得到了广泛的应用。运用 GSM 短消息实现远程测控的可靠性较高、信号传播距离远、覆盖面积广,并且可以节省建网初期的巨额投资。 本文对基于GSM短消息收发系统的设计与实现作了具体描述,给出了系统的软硬件设计方案,对主要硬件,即GSM模块Q2403A 和8051单片机作了重点介绍。给出了系统的软件设计,包括PC与单片机通信部分和短消息收发部分。最后实现系统监控功能。 系统硬件实现 总体系统结构 该系统硬件主要由8051单片机扩展电路、Q2403
[单片机]
基于GSM模块Q2403A和8051<font color='red'>单片机</font>实现短消息收发系统的应用方案
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved