用 LCD1602 显示的时钟

时间:2022-12-15 04:44:31

有这样一个题目:求一个为 51 单片机编写的 LCD 电子时钟的设计,简单就好 !
希望说一下怎么设计这个时钟,都需要些什么东西,最重要的——把这个设计需要的程序写出来。

设计的任务:
  以单片机控制的时钟,在 LCD 显示器上显示当前的时间。
设计的基本要求:
  1.使用文字型 LCD 显示器显示当前时间。
  2.显示格式为“时时:分分:秒秒”。
  3.用4个功能键操作来设置当前时间。各个功能键的功能如下:
    K1:进入设置现在的时间。
    K2:设置小时。
    K3:设置分钟。
    K4:确认完成设置。
  4. 程序执行后工作指示灯 LED 闪烁,表示程序开始执行,LCD 显示“00:00:00”,然后开始计时。

题目链接:http://zhidao.baidu.com/question/416705477.html

//==================================================

提到设计时钟,很多人都想到了时钟芯片 DS1302,都说它简单、准确。其实,这是个误区。

仅仅使用一般的单片机,简单的编程,达到相同 DS1302 的准确度,并不是难事。

如果不要求计算平闰年、不要求分清大小月、不要求计算星期几,只是要求一个简单的时钟(及日历),用 DS1302,就是自寻烦恼。

大家可以打开题目链接,看看其中的一些答案,就可以看出使用 DS1302 是多么的繁琐了,简直就是一场噩梦。

做而论道以前就使用普通的单片机和 LCD1602 设计过《时钟与日历》,程序设计的非常合理,时间精度就完全取决于晶振的精度。设计出来的时钟,几个月都差不上一秒。

针对这个题目,做而论道翻出了以前的设计,删节了一些不需要的功能,设计出了符合题目要求的时钟,用 PROTEUS 仿真截图如下:

用 LCD1602 显示的时钟

图片链接:http://xiangce.baidu.com/picture/detail/7235024812c232e78811f4e34e5b9dd3d1ed5882


程序用 C 语言编写,全部代码如下:
//---------------------------------------------------
#include<reg52.h>
#define uchar unsigned char 
#define uint unsigned int

#define KEY_IO P3
#define LCD_IO P0

sbit LCD_RS = P2^0;
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;

sbit SPK = P1^2;
sbit LED = P2^4;

bit new_s, modify = 0;
char t0, sec = 50, min = 59, hour = 23;

char code LCD_line1[] = "Designed by ZELD";
char code LCD_line2[] = "Timer: 00:00:00 ";
char Timer_buf[] = "23:59:50";
//---------------------------------------------------
void delay(uint z)
{
    uint  x, y;
    for(x = z; x > 0; x--)  for(y = 100; y > 0; y--);
}
//---------------------------------------------------
void W_LCD_Com(uchar com)      //写指令
{
    LCD_RS = 0;  LCD_IO = com; // LCD_RS和R/W都为低电平时,写入指令
    LCD_EN = 1;  delay(5); LCD_EN = 0; //用EN输入一个高脉冲 
}
//---------------------------------------------------
void W_LCD_Dat(uchar dat)      //写数据
{
    LCD_RS = 1;  LCD_IO = dat; // LCD_RS为高、R/W为低时,写入数据
    LCD_EN = 1;  delay(5); LCD_EN = 0; //用EN输入一个高脉冲 
}
//---------------------------------------------------
void W_LCD_STR(uchar *s)       //写字符串
{
    while(*s)  W_LCD_Dat(*s++);
}
//---------------------------------------------------
void W_BUFF(void)              //填写显示缓冲区
{
    Timer_buf[7] = sec % 10 + 48; Timer_buf[6] = sec / 10 + 48;
    Timer_buf[4] = min % 10 + 48; Timer_buf[3] = min / 10 + 48;
    Timer_buf[1] = hour % 10 + 48;Timer_buf[0] = hour / 10 + 48;
    W_LCD_Com(0xc0 + 7); W_LCD_STR(Timer_buf);
}
//---------------------------------------------------
uchar read_key(void)
{
    uchar  x1, x2;
    KEY_IO = 255;
    x1 = KEY_IO;
    if (x1 != 255) {
      delay(100);
      x2 = KEY_IO;
      if (x1 != x2)  return 255;
      while(x2 != 255) x2 = KEY_IO;
      if      (x1 == 0x7f)  return 0;
      else if (x1 == 0xbf)  return 1;
      else if (x1 == 0xdf)  return 2;
      else if (x1 == 0xef)  return 3;
      else if (x1 == 0xf7)  return 4;
    }
    return 255;
}
//---------------------------------------------------
void Init()
{
    LCD_RW = 0;
    W_LCD_Com(0x38); delay(50); 
    W_LCD_Com(0x0c);
    W_LCD_Com(0x06);
    W_LCD_Com(0x01);
    W_LCD_Com(0x80); W_LCD_STR(LCD_line1);
    W_LCD_Com(0xC0); W_LCD_STR(LCD_line2);

    TMOD = 0x01;   //T0定时方式1
    TH0 = 0x4c; 
    TR0 = 1;       //启动T0
    PT0 = 1;       //高优先级, 以保证定时精度
    ET0 = 1;
    EA = 1;
}
//---------------------------------------------------
void main()
{
    uint i, j;
    uchar Key;
    Init();
    while(1)  {
//-------------------------------
      if (new_s) { //如果出现了新的一秒, 修改时间
        new_s = 0;    sec++;  sec %= 60;
        if(!sec)  {   min++;  min %= 60;
          if(!min)  { hour++; hour %= 24;}
        }
        W_BUFF();  //写显示
//-------------------------------
        if (!sec && !min) { //整点报时
          for (i = 0; i < 200; i++) {
            SPK = 0; for (j = 0; j < 100; j++);
            SPK = 1; for (j = 0; j < 100; j++);
        } }
      }
//-------------------------------
      Key = read_key();  //读出按键
      switch(Key) {      //分别处理四个按键
      case  0: modify = 1; break;
      case  1: if(modify) {min++;  min %= 60;  W_BUFF(); break;}
      case  2: if(modify) {hour++; hour %= 24; W_BUFF(); break;}
      case  3: modify = 0; break;
    } }
}
//---------------------------------------------------
void timer0(void) interrupt 1  //T0中断函数, 50ms执行一次
{
    TH0 = 0x4c; 
    t0++; t0 %= 20;   //20, 一秒钟
    if(t0 == 0)  {new_s = 1; LED = ~LED;}
    if(modify)  LED = 0;
}
//===================================================

呵呵,全部程序,也不过 120 行左右。不知道还能不能找到更简明的程序。