原创 89c2051+1602 的万年历和时钟

2009-9-1 16:11 3732 6 7 分类: MCU/ 嵌入式

下图是proteus的仿真截图。2051的P1口用于1602的数据口;2051的P3.4用于1602的RS端;P3.5用于1602的RW端;P3.6用于1602的EN端;剩下的P3.2和P3.7用于调时和加一按钮。网上有些程序还有一个减一按钮,由于2051的I/O口就那么多,就省略了。如一定要加,可考虑做一个2X2的小键盘,并用扫描的方式,但是程序稍微复杂一点。


点击开大图


下面是详细的程序列表:


#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define datasend P1
//sbit  LCD_RW = P3 ^ 5; 
//sbit  LCD_RS = P3 ^ 4; 
//sbit  LCD_E  = P3 ^ 3;
sbit lcden="P3"^3;          //LCD使能端
sbit lcdrs="P3"^4;          //LCD  数据/指令(H/L)选择端
sbit lcdrw="P3"^5;          //LCD  数据/指令(H/L)选择端
sbit s1=P3^2;             //定义功能按键
sbit s2=P3^7;             //定义时分秒 +1 按键
//sbit s3=P1^2;             //定义时分秒 -1 按键


//uchar   mytable0[]="    lwxkey      ";
//uchar   mytable1[]="A handsome boy!!";
uchar code line0[]="  2001-01-01  ";    //初始化显示
uchar code line1[]="  00:00:00    ";
uchar code month0[]={31,28,31,30,31,30,31,31,30,31,30,31};  //平年月
uchar code month1[]={31,29,31,30,31,30,31,31,30,31,30,31};  //闰年月
uchar count,hour,minute,second,year=1,month=1,date=1;
uchar s1num;          //s1num:定义功能键按下次数变量


void delay(unsigned int z)      //延时子函数  z*1ms
{
 unsigned int x,y;
 for(x=z;x>0;x--)
  for(y=110;y>0;y--);
}


void write_com(unsigned char c)   //写命令子函数
{
 lcdrs=0;                //低电平选择为 写指令
 lcdrw=0;                //低电平选择为 写指令
 lcden=0;               
 datasend=c;                   //把指令写入P1口
 delay(5);               //参考时序图
 lcden=1;                //开使能
 delay(5);               //读取指令
 lcden=0;                //关闭使能 
}


void write_data(unsigned char d)  //写数据子函数
{
 lcdrs=1;             //高电平选择为 写数据
 lcdrw=0;                //低电平选择为 写指令
  datasend=d;                //把数据写入P0口
 delay(5);            //参考时序图
 lcden=1;             //开使能
 delay(5);            //读取数据
 lcden=0;          //关闭使能
}


void write_hms(uchar add,uchar dat)  //时分秒写函数  add:输入位置设置变量   dat:输入时分秒数据
{
 uchar sw,gw;               //定义十位,个位变量
 sw=dat/10;
 gw=dat%10; 
 write_com(0x80+0x40+add);  //从第二行(add)位开始写数据
 write_data(0x30+sw);       //写入十位
 write_data(0x30+gw);       //写入个位
}


void write_ymd(uchar add,uchar dat)  //年月日写函数  add:输入位置设置变量   dat:输入时分秒数据
{
 uchar sw,gw;               //定义十位,个位变量
 sw=dat/10;
 gw=dat%10; 
 write_com(0x80+add);       //从第一行(add)位开始写数据
 write_data(0x30+sw);       //写入十位
 write_data(0x30+gw);       //写入个位
}


void t0() interrupt 1          //定时器0中断子程序
{
 TH0=0x36;//(65536-50000)/256;
 TL0=0x9d;//(65536-50000)%256;
 count++;
}


void gethms()              //时分秒处理子程序
{
 second++;
 if(second==60)
 {
  second=0;
  minute++;
  if(minute==60)
  {
   minute=0;
   hour++;
   if(hour==24)
   {
    hour=0;     
    date++;
   }
   write_hms(2,hour);       //时输出显示
  }
  write_hms(5,minute);         //分输出显示
 }
 write_hms(8,second);             //秒输出显示
}


void getymd()                        //年月日处理子程序
{
 if(year%4==0)
 {
  if(date==month1[month-1]+1)
  {
   date=1;
   month++;
   if(month==13)
   {
    month=1;
    year++;
    if(year==100)
    {
     year=1;
    }
    write_ymd(4,year);
   }
   write_ymd(7,month);
  }
  write_ymd(10,date); 
 }
    else
 {
  if(date==month0[month-1]+1)
  {
   date=1;
   month++;
   if(month==13)
   {
    month=1;
    year++;
    if(year==100)
    {
     year=1;
    }
    write_ymd(4,year);
   }
   write_ymd(7,month);
  }
  write_ymd(10,date); 
 }  
}


void  keyscan()                          //按键扫描子程序
{
 if(s1==0)                            //功能键 S1 功能设置 
 {
  delay(5);
  if(s1==0)                           //功能键按下
  {
   while(s1==0);                   //松手检测
   s1num++;                        //功能键按下计数
   TR0=0;                          //T0定时停止,进入时间调整   
            switch(s1num)
      {
        case 1: write_com(0x80+0x40+0x09);   break;   //光标闪烁位定为秒个位
        case 2: write_com(0x80+0x40+0x06);   break;   //光标闪烁位定为分个位 
        case 3: write_com(0x80+0x40+0x03);   break;   //光标闪烁位定为时个位   
        case 4: write_com(0x80+0x0b);        break;   //光标闪烁位定为日个位   
        case 5: write_com(0x80+0x08);        break;   //光标闪烁位定为月个位   
        case 6: write_com(0x80+0x05);        break;   //光标闪烁位定为年个位 
      }       
   write_com(0x0f);                    //光标闪烁   
   if(s1num==7)
      {
    s1num=0;                        //按键计数复位
    write_com(0x0c);                //光标停止闪烁 
    TR0=1;                          //重新启动定时器
   }    
  }   
 }
 
 if(s2==0)                            //S2键   时分秒 +1 模块
 {
  delay(5);
  if(s2==0)
  {
   while(s2==0);
   switch(s1num)
      {
        case 1:  second++;                       //秒+
                if(second==60) second="0";        //复位
                write_hms(8,second);            //秒输出显示
                write_com(0x80+0x40+0x09);      //光标闪烁位定为秒个位
                      break; 
         case 2:  minute++;
       if(minute==60) minute="0";        //复位
       write_hms(5,minute);            //分输出显示
       write_com(0x80+0x40+0x06);      //光标闪烁位定为分个位 
          break;    
        case 3:  hour++;
       if(hour==24) hour="0";            //复位
       write_hms(2,hour);              //时输出显示
       write_com(0x80+0x40+0x03);      //光标闪烁位定为时个位
          break;     
        case 4:  date++;                          //日+
       if(year%4==0)                   //平闰年判断
       {
        if(date==month1[month-1]+1)
        {
         date=1;
        }
       }
       else
       {
        if(date==month0[month-1]+1)
        {
         date=1;
        }
       }
       write_ymd(10,date);              //日输出显示
       write_com(0x80+0x0b);          //光标闪烁位定为日个位
             break;     
        case 5:  month++;                     //月+
         if(month==13)  month="1";
         if(year%4==0)                //判断日和月的配对关系
       {
        if(date>month1[month-1]) date="month1"[month-1];
       }
       else
       {
        if(date>month0[month-1]) date="month0"[month-1];
       }
       write_ymd(10,date);              //日输出显示
       write_ymd(7,month);            //月输出显示
       write_com(0x80+0x08);          //光标闪烁位定为月个位
          break;   
        case 6:  year++;                        //年+
         if(year==100)  year="1";         //复位
       write_ymd(4,year);             //年输出显示
       write_com(0x80+0x05);          //光标闪烁位定为年个位
            break;   
      }            
  }
 }
/********************************************************************************* 
 if(s3==0)                       //时分秒 -1 模块
 {
  delay(5);
  if(s3==0)
  {
   while(s3==0);
   switch(s1num)
      {
        case 1:  second--;                       //秒-
                if(second==255) second="59";      //复位
                write_hms(8,second);            //秒输出显示
                write_com(0x80+0x40+0x09);      //光标闪烁位定为秒个位
                      break; 
         case 2:  minute--;
       if(minute==255) minute="59";      //复位
       write_hms(5,minute);            //分输出显示
       write_com(0x80+0x40+0x06);      //光标闪烁位定为分个位 
          break;    
        case 3:  hour--;
       if(hour==255) hour="23";          //复位
       write_hms(2,hour);              //时输出显示
       write_com(0x80+0x40+0x03);      //光标闪烁位定为时个位
          break;     
        case 4:  date--;                          //日-
       if(year%4==0)
       {
        if(date==0)
        {
         date=month1[month-1];
        }
       }
       else
       {
        if(date==0)
        {
         date=month0[month-1];
        }
       }
       write_ymd(10,date);            //日输出显示
       write_com(0x80+0x0b);        //光标闪烁位定为日个位
             break;     
        case 5:  month--;                     //月-
         if(month==0)  month="12";
         if(year%4==0)                //判断日和月的配对关系
       {
        if(date>month1[month-1]) date="month1"[month-1];
       }
       else
       {
        if(date>month0[month-1]) date="month0"[month-1];
       }
       write_ymd(10,date);              //日输出显示
       write_ymd(7,month);            //月输出显示
       write_com(0x80+0x08);          //光标闪烁位定为月个位
          break;   
        case 6:  year--;                        //年-
         if(year==0)  year="99";          //复位
       write_ymd(4,year);             //年输出显示
       write_com(0x80+0x05);          //光标闪烁位定为年个位
            break;   
      }                
  }
 }
*********************************************************************************/ 
}


void initialize()      //LCD初始化函数
{
 uchar num;
 lcden=0;
 write_com(0x38);   //设置16x2显示,5x7点阵显示,8位数据接口
 write_com(0x0c);   //00001DCB,D(开关显示),C(是否显示光标),B(光标闪烁,光标不显示)
 write_com(0x06);   //000001N0,N(地址指针+-1)
 write_com(0x01);      //清屏指令  每次显示下一屏内容时,必须清屏
 
/*********************************************************************************
write_com(0x80+0x10);           //第一行,前头空5格显示
 for(num=0;num<11;num++)       //显示6个字符
 {
  write_data(mytable0[num]);
  delay(10);
 }
 write_com(0x80+0x50);           //第二行,从第一格开始显示
 for(num=0;num<16;num++)      //显示16个字符
 {
  write_data(mytable1[num]);
  delay(10);
 }
 for(num=0;num<16;num++)
 {
  write_com(0x1c);   //0001(S/C)(R/L)**;  S/C:高电平移动字符,低电平移动光标;  R/L:高电平左移,低电平右移
  delay(300);
 }
    delay(1000);          
*********************************************************************************/ 
  write_com(0x01);      //清屏指令  每次显示下一屏内容时,必须清屏


 write_com(0x80);           //第一行,顶格显示     
 for(num=0;num<12;num++)    //初始化第一行显示  2009-01-01
 {
  write_data(line0[num]);
  delay(10);
 }


 write_com(0x80+0x40);         //第二行,顶格显示
 for(num=0;num<10;num++)        //初始化第二行显示  00:00:00
 {
  write_data(line1[num]);
  delay(10);
 }
 
 TMOD=0x01;                 //定时器0中断初值设置
 TH0=0x36;//(65536-50000)/256;
 TL0=0x9d;//(65536-50000)%256;
 EA=1;
 ET0=1;
 TR0=1; 
}


void main()
{
 initialize();        //初始化
 while(1)
 {
  keyscan();   //按键扫描
  if(count==20)          //定时1s 运行模块
  {
   count=0;
   gethms();          //时分秒数据处理
   getymd();          //年月日数据处理
  } 
 }
}

文章评论1条评论)

登录后参与讨论

用户507162 2010-1-13 07:27

把你做的压缩 上传 才能看嘛
相关推荐阅读
用户212727 2009-09-10 19:41
TLC1543 十位AD转换和1620液晶显示
调试时有两个地方要注意:1.如等待AD转换的时间不够,proteus会提示还未转换结束,CS就变高了.此时需要加上几个NOP.具体加几个,可通过调试确定.2.开始时液晶数据通过P0口送出,可能是P0口...
用户212727 2009-08-26 20:13
89C2051+1602 的滚动字幕机
程序的关键是一个从输入的字符串中截取从起始位置开始的长度为16的部分字符串的子程序,然后把截取的字符串送到1602的指定行中显示。下图为Proteus仿真结果。下面是程序列表:/***********...
用户212727 2009-08-18 08:00
89s52 datasheet
89s52 datasheet...
用户212727 2009-08-18 07:58
89c2051 datasheet
89c2051 datasheet...
我要评论
1
6
关闭 站长推荐上一条 /2 下一条