新闻  |   论坛  |   博客  |   在线研讨会
基于AT89S51的8个闹钟时间的智能时钟
tvb2058 | 2007-09-14 10:47:23    阅读:2924   发布文章

 

普通的家用时钟一般只能设置一个闹钟时间,但很多人均需为工作日、周末、早晨、午休等不同时段设置不同的闹钟时间。如果是使用普通的闹钟,只好每次休息前重新设置,很不方便,有时甚至会出现忘记更改闹钟设置而睡过头的情况。针对这种情况,本人利用89C51单片机设计了一款有8种闹钟设置的时钟,通过一段时间的使用,情况良好。

1   元件清单

共阴极数码管                                   8
                            4511七段译码芯片                     1
ATMEL89C51单片机                  1                     
24C08EEPROM                          1

24M晶振                                   1                     
9V
变压器(3VA                     1

LM317输出可调稳压IC             1                     
整流桥堆                                          1

470uF电容                                1                     
100uF
电容                                1

10uF电容                                  1                     
0.1uF
电容                                 1

33pF电容                                  2                     
蜂鸣器                                       1

9014(或其它NPN管)             8                     
                            ksp92
(或其它PNP管)            1

二极管                                       2                     
1K
欧电阻                                  16

470欧电阻                                 1
                            10K欧可调电阻                         1
10K欧电阻                                4                     
按钮开关                                          4

可装四节电池的电池盒                     1
                     
万能板(约12CM*17CM        1

所有元件按以下的电路图焊接在一块万能板上。注意LM317的输出应由低调高,以免烧IC

 2   电路图

 

 

3   功能简介

该时钟以24小时制显示时间,并可显示2000年至2049年之间的任何日期及星期,日期与时间经按键可相互切换,可输入8个闹钟时间设置,每个闹钟设置包括响铃的时间(小时与分钟)、对工作日有效还是对周末有效的标志,以及本项设置是否启用的标志等三部分。这8个闹钟设置均保存在EEPROM中,即使掉电也不用重新输入。当然使用者可通过按钮对任何一个设置作修改。数码管可经按钮关闭显示,避免夜间刺眼、影响睡眠。调节LM317输出电压,可改变数码管亮度,但电压不能低于后备电池的电压,否则后备电池供电。用四节1.5V电池串联作后备电源,保证市电停电时时钟继续走时。时钟的精度取决于晶振频率的精度。

4   程序清单

本程序用C语言编写,经Keil C51编译成二进制码后写入89C51内的EPROM内即可。

i nclude "atmel\at89x51.h"

i nclude "intrins.h"

 

unsigned char hour,min,sec,year,month,day,weekday;   //当前时间、日期、星期

unsigned int  count_down;      //1秒钟计时用

 

bit led_on;                    //数码管是否点亮的标志

unsigned char display[8];      //8位数码管要显示的数据

unsigned char attr;                   //八个数码管的闪烁控制字节,当为0时,对应数码管闪

bit flash;                           //LED 闪烁开关,与attr共同决定数码管是否闪烁

unsigned char show_status;           //LED 显示状态标志

        // 0:设置闹钟数据

// 1:显示当前日期及星期

                                                 // 2:显示当前时间

// 3:设置当前日期

// 4:设置当前时间

 

bit km;                             //按键已去抖动标志

bit kp;                       //按键已处理标志

 

bit sound;                    //蜂鸣器响标志

bit alarm_stop;                //蜂鸣器响后用户手工按停标志

struct  { unsigned char h;         //小时

        unsigned char m;         //分钟

       } alarm[8];                           //8个闹钟项

unsigned char alarm_en;              //闹钟项启用标志

unsigned char alarm_wk;        //闹钟项周末启用标志

unsigned char cur_alarm_set;   //当前设置的闹钟项

unsigned char cur_alarm_active;  //当前到点的闹钟项

bit new_alarm_info;            //闹钟项内容已修改标志

 

sbit sound_output = P1^5;            //蜂鸣器驱动端口,输出0时蜂鸣器响

sbit SDA_PIN   = P1^6;        //EEPROM数据线端口

sbit SCL_PIN   = P1^7;         //EEPROM时钟线端口

 

void I2cDelay()                      //EEPROM操作时需要的延时函数

{ _nop_();  _nop_();  _nop_();

  _nop_();  _nop_();  _nop_();

}

 

void DelayX1ms(unsigned char count)             //延迟函数,参数为毫秒数

{unsigned char i,j;

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

    for(j=0;j<240;j++)    ;

}

 

void Start()                                       //I2C启动,24C08使用I2C方式

{ SDA_PIN=1;   I2cDelay();

  SCL_PIN=1;   I2cDelay();

  SDA_PIN=0;   I2cDelay(); 

  SCL_PIN=0;   

}

 

void Stop()                        //I2C停止

{ I2cDelay();  SDA_PIN=0;

  I2cDelay();  SCL_PIN=1;

  I2cDelay();  SDA_PIN=1;

  I2cDelay();

}

 

bit SendByte(unsigned char value)                    //发送1字节数据给EEPROM

{unsigned char i;

 bit no_ack=0;

 

  for(i=0;i<8;i++)                     //发送8位数据

  { I2cDelay();    

if(value&0x80)   SDA_PIN=1;

else            SDA_PIN=0;

    value=value<<1;        

       I2cDelay();      SCL_PIN=1;          

       I2cDelay(); 

       I2cDelay();      SCL_PIN=0;

   }

 

  I2cDelay();        SDA_PIN=1;     //确认脉冲周期,等待EEPROM的确认

  I2cDelay();        SCL_PIN=1;      

  I2cDelay();      

  if(SDA_PIN==1)   no_ack=1;

  I2cDelay();        SCL_PIN=0;

 

  return no_ack;

}

 

void mywrite(unsigned char address,unsigned char value)             //EEPROM1字节

{ Start();          SendByte(0xa0);     SendByte(address);   

  SendByte(value);  Stop();             DelayX1ms(10);

}

 

unsigned char ReadByte()                  //EEPROM接收1字节

{unsigned char i,bval;

  bval=0;

  for(i=0;i<8;i++)                              //接收8位数据

   { I2cDelay();

     SDA_PIN=1;                          //P1输入数据时,先往P1输入“1

     I2cDelay();    SCL_PIN=1;

 

     I2cDelay();    bval=bval<<1;     if(SDA_PIN)    bval=bval|0x01;

     I2cDelay();    SCL_PIN=0;

    }

   

       I2cDelay();     SDA_PIN=1;    //确认脉冲周期,不送出确认

       I2cDelay();     SCL_PIN=1;    

       I2cDelay();     

       I2cDelay();

 

    return(bval);

}

 

unsigned char myread(unsigned char address)         //EEPROM读入1字节数据

{unsigned char tmp;

  Start();        SendByte(0xa0);     SendByte(address);   

  Start();        SendByte(0xa1);     tmp=ReadByte();

  Stop();         DelayX1ms(2);

  return(tmp);

}

 

void Timer0ISR(void) interrupt 1 using 3 //定时器0中断程序,用于走时,1/8000秒一次

{unsigned char tmp,tmp_days;

 

  count_down--;

  if(count_down==1 || count_down==2001 || count_down==4001 || count_down==6001)

   { flash=~flash;                                  //数码管闪烁的开关量

     if(sound && flash) sound_output=0;              //驱动蜂鸣器

     else             sound_output=1;         //关闭蜂鸣器

        return;

       }

 

                     /*** 计算当前日期为星期几***/ 

  if(count_down==3000)

   { if(year==0)       weekday=5;           //200011日为星期六

    else { tmp=(year-1)/4+1;   tmp=(year-tmp)+tmp*2;

         weekday=(tmp+5)%7;           //计算出当前年的11日为星期几

        }

     tmp_days=0;

     for(tmp=1;tmp<month;tmp++)

       if(tmp==1 || tmp==3 || tmp==5 || tmp==7 || tmp==8 || tmp==10)

          tmp_days=tmp_days+31;

       else if(tmp==4 || tmp==6 || tmp==9 || tmp==11)

             tmp_days=tmp_days+30;

       else if(tmp==2)

             { if(year%4==0) tmp_days=tmp_days+29;

            else         tmp_days=tmp_days+28;

           }

     tmp_days=tmp_days+day-1;    weekday=(weekday+tmp_days%7)%7+1;

        return;

       }

 

                  /***  查询是否有闹钟时间项符合触发条件 ***/

  if(count_down==5000)

  { if((alarm_stop || sound) && alarm[cur_alarm_active].m!=min)      //触发后1分钟

      { alarm_stop=0; sound=0; }                                             //自动关蜂鸣器

 

    if(sound==0 && alarm_stop==0)           //没有已触发的闹钟项

     for(tmp=0;tmp<8;tmp++)                           //则查询8个闹钟项内是否有符合条件的

         { if(((alarm_en>>tmp)&1)==0) continue;    //该闹钟项不启用

           if(((alarm_wk>>tmp)&1)==1)           //该闹钟项周末有效

                { if(weekday!=6 && weekday!=7) continue;  }  //当前不是星期六或星期天

              else

                { if(weekday==6 || weekday==7) continue;  }

 

        if(alarm[tmp].h==hour && alarm[tmp].m==min)           //比较当前时间与该

          { sound=1;  cur_alarm_active=tmp; break; }              //闹钟项的时间

          }

    return;

   }

 

  if(count_down==0)                              //过了一秒钟

   { count_down=8000;

     sec++;

     if(sec==60)

      { sec=0;

        min++;

        if(min==60)

          { min=0;

            hour++;

            if(hour==24)

              { hour=0;   day++;

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
xueguo  2010-04-02 23:20:35 

好像程序不全

[ 匿名]  2008-07-22 21:55:04 

谢谢相告!

nop [ 匿名]  2008-07-22 21:54:36 

请问 1片 74hc4511怎么和 8个 数码管接

推荐文章
最近访客