能给做一个用单片机at89c51的简易电子时钟吗?要有程序,流程图proteus仿真图,元器件清单

与要求不符! 只要时间 不要日期 用的是数码管
2024-12-17 14:21:20
推荐回答(2个)
回答1:

/*

模块名:学校实时时钟

创建人:XIAORUILAI 日期:2010-12-3

修改人:

功能描述:设计基于51单片机的实时时钟;具备调整日期\时间\星期功能;LCD(LM016L)显示

其它说明:

版    本:V1。0

*/

#include

#include

#include

#define HOME  0        //屏幕左上角

#define YEAR  1        //定义年在显示缓冲区位置指针

#define MONTH 2

#define DAY   3

#define WEAK  4

#define HOUR  5

#define MIN   6

#define SEC   7

#define OFF   0        //关

#define ON    1        //开

#define DISP_BUSY 0x80     //LCD忙命令

#define DISP_FUNC 0x38     //功能设置

#define DISP_ENTRY 0x06     //

#define DISP_CNTL 0x08     //显示控制

#define DISP_ON  0x04     //开显示

#define DISP_CURSOR 0x02     //光标开关

#define DISP_CLEAR 0x01     //清缓冲

#define DISP_HOME 0x02     //光标左上角

#define DISP_POS 0x80     //显示缓冲区地址设置

#define DISP_LINE2 0x40     //第二行控制

#define NUM_BEEL 5      //作息时间表记录个数

unsigned char t=0,sec=58,min=59,hour=9,year=0,year1,mon=2,day=28,weak=1;

unsigned char code *weak1[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};

unsigned char days_of_month[12]={31,28,31,30,31,30,31,31,30,31,30,31};

unsigned int code table_of_time[NUM_BEEL]={360,420,480,600,720};     

           //作息时间表,折合(单位)为分钟

unsigned char code field_pos[7]={0x82,0x85,0x88,0x8b,0xc0,0xc3,0xc6};

           //显示缓冲区地址

unsigned char delaytime=0,bell_on=OFF,no;

#define REG0 XBYTE[0X0000]     //LCD写命令地址

#define REG1 XBYTE[0X0001]     //LCD读命令(状态)地址

#define REG2 XBYTE[0X0002]     //LCD写数据地址

#define REG3 XBYTE[0X0003]     //LCD读数据地址

unsigned char bdata busyflag;             //LCD忙标志

unsigned char dat,datn,disp_updata=1,cur_field,set_mode;

unsigned char word1[16]={"2010-11-25 Thu"}; //显示缓冲区

unsigned char word2[16]={"09:59:58"};  //显示缓冲区

sbit busyflag_7=busyflag^7;

sbit SET=P1^0;           //调整方式切换键

sbit SELECT=P1^1;               //日期时间调整键

sbit BELL_CNTL=P1^7;            //控制响铃

void busy()         //测试LCD忙?

    do

    {

       busyflag=REG1;

    }while(busyflag_7);

}

void wrc(unsigned char wcon)            //LCD写命令

{

   busy();

   REG0=wcon;

}

void wrd(unsigned char wdat)            //LCD写数据

{

   busy();

   REG2=wdat;

}

void rdd()                             //LCD读数据

{

   busy();

   dat=REG3;

}

void lcdint()                          //LCD初始化

{

   wrc(0x38);

   wrc(0x01);

   wrc(0x06);

   wrc(0x0c);

}

void wrn(unsigned char word[])           //向LCD连续写N个数据

{

   unsigned char i;

   for(i=0;i<16;i++)

   {

      wrd(word[i]);

   }

}

void time0() interrupt 1 

{

    TR0=OFF;

 TH0=(65536-10000)/256;            //装定时器0初值 20MS中断时间常数装截  晶振频率6MHZ

 TL0=(65536-10000)%256;

 TR0=ON;

 if(++t==50)

 {

  t=0;

     disp_updata=1;      //刷新显示标志置位

  if(++sec==60)                     //生成当前万年历(年、月、日、星期和时刻(时、分、秒)

  {

   sec=0;

      if(++min==60)

   {

     min=0;

     if(++hour==24)

     {

      hour=0;

      if(++weak>6)

         weak=0;

      if(++day>days_of_month[mon-1])

      {

        day=1;

     if(++mon==13)

     {

      mon=1;

      year++;

        }

      }

     }

    }

  }

 }

}

void time1() interrupt 3                    //响铃控制定时中断(响铃10秒)

{

 TR1=OFF;

 TH1=(65536-50000)/256;

 TL1=(65536-50000)%256;

 TR1=ON;

 if(++delaytime==50)

 {

  delaytime=0;

  bell_on=OFF;

  BELL_CNTL=OFF;                      //延时到,关闭铃

  ET1=OFF;

  TR1=OFF;

    }

}

void disp_time()

{

   word2[6]=sec/10+0x30;                   //数字量转字符

   word2[7]=sec%10+0x30;

   word2[0]=hour/10+0x30;

   word2[1]=hour%10+0x30;

   word2[3]=min/10+0x30;

   word2[4]=min%10+0x30;

   word1[2]=year/10+0x30;

   word1[3]=year%10+0x30;

   word1[5]=mon/10+0x30;

   word1[6]=mon%10+0x30;

   word1[8]=day/10+0x30;

   word1[9]=day%10+0x30;

   word1[11]=*(weak1[weak]);

   word1[12]=*(weak1[weak]+1);

   word1[13]=*(weak1[weak]+2);

   wrc(0x80);        //显示输出

   wrn(word1);

   wrc(0xc0);

   wrn(word2);

}

void bell_cntl()

{

 if(!bell_on&&((hour*60+min)==table_of_time[no])

   &&(sec<1)&&(no++<5))            //判作息时间表到?是,开启定时器1定时10S

 { 

        ET1=ON;

  TR1=ON;        //起动定时器1,响铃10S

  BELL_CNTL=ON; 

        bell_on=ON;             

    } 

}

void incr_field()       //当前域增1(调整日期\时间\星期

{

 if(cur_field==YEAR)

 {

  if(++year>99)

    year=0;

     word1[2]=year/10+0x30;

     word1[3]=year%10+0x30;

 }

 if(cur_field==MONTH)

 {

  if(++mon>12)

    mon=1;

  word1[5]=mon/10+0x30;

     word1[6]=mon%10+0x30;

 }

 if(cur_field==DAY)

 {

  if(++day>31)

    day=1;

  word1[8]=day/10+0x30;

     word1[9]=day%10+0x30;

 }

 if(cur_field==WEAK)

 {

  if(++weak>6)

    weak=0;

  word1[11]=*(weak1[weak]);

     word1[12]=*(weak1[weak]+1);

     word1[13]=*(weak1[weak]+2);

 }

 if(cur_field==HOUR)

 {

  if(++hour>23)

    hour=0;

  word2[0]=hour/10+0x30;

     word2[1]=hour%10+0x30;

 }

 if(cur_field==MIN)

 {

  if(++min>59)

    min=0;

  word2[3]=min/10+0x30;

     word2[4]=min%10+0x30;

 }

 if(cur_field==SEC)

 {

  if(++sec>59)

    sec=0;

  word2[6]=sec/10+0x30;                 //数字量转字符

     word2[7]=sec%10+0x30;

 }

}

void set_cursor(unsigned char mode,unsigned char field)

{           //设置指定域光标显示

 unsigned char mask;

 mask=DISP_CNTL|DISP_ON;

 if(mode)

  mask|=DISP_CURSOR;

 wrc(mask);

 if(field==HOME)

  mask=DISP_HOME;

 else

  mask=DISP_POS|field_pos[field-1];

 wrc(mask);

}

unsigned char reset_belltime_pos(void)  //计算作息时间表指针

{

 unsigned char index;

 for(index=0;index

 {

  if((hour*60+min)<=table_of_time[index])

      return index;

 }

 return 0;

}

void delay()        //延时子程序

{ ET1=OFF;

 TH1=(65536-50000)/256;

 TL1=(65536-50000)%256;

 TR1=ON;

 while(!TF1);

 TR1=OFF;

}

void main()

{

    BELL_CNTL=OFF;

 lcdint();

    wrc(0x80);

    wrn(word1);

    wrc(0xc0);

    wrn(word2);

 no=reset_belltime_pos();   

    TMOD=0x11;       //设置定时器/计数器T0、T1为16位定时模式

    TH1=(65536-50000)/256;        //设置定时器1预置时间常数(100MS)

 TL1=(65536-50000)%256;

 TH0=(65536-10000)/256;    //设置定时器1预置时间常数(20MS) 晶振频率6MHZ

 TL0=(65536-10000)%256;

 EA=ON;        //开总中断

 ET0=ON;        //定时器0中断允许

 ET1=OFF;               //定时器1中断允许

 TR0=ON;               //起动定时器0

 TR1=OFF;               //关闭定时器1,适时起动

 year1=year+2000;

 if((year1%4==0)&&(year1%100!=0)||(year1%100!=0)&&(year1%400==0))

          days_of_month[1]=29;

       else     //计算闰年

         days_of_month[1]=28;

 while(1)

 {P1=P1|0x03;      

 if(!SET)       //检测设置键是否按下

  delay();      //消除键抖动

 if(!SET)       //确认键按下

 {    while(!SET);     //等待键释放

      if(!set_mode)     //测设置模式否

      {

   set_mode=1;      //置时间设置模式标志

      cur_field=YEAR;

   set_cursor(ON,YEAR);

   }

      else

      { cur_field++;

        if(cur_field>SEC)   //设置结束

        { set_mode=0;    //设置正常模式

    no=reset_belltime_pos();

          set_cursor(OFF,HOME);

     }

     else

       set_cursor(ON,cur_field);

          //当前显示域光标显示

      }

 }

 if(set_mode&&!SELECT)    //日期设置且按选择健调时

 {  

  delay();

  if(!SELECT)

     while(!SELECT);

  incr_field();

        disp_time();

     set_cursor(ON,cur_field);

    }

 if(!set_mode)      //若非设置模式\更新显示

     if(disp_updata)

        { disp_time();

         disp_updata=0;

   bell_cntl();    //测试是否响铃

        }

 }

}

回答2:

已发送