您的位置:首页技术文栏毕业课程设计
内容搜索:
阅读内容
背景:#EDF0F5 #FAFBE6 #FFF2E2 #FDE6E0 #F3FFE1 #DAFAF3 #EAEAEF 默认  

[课程设计]可设置8个闹钟时间的智能时钟(C)

[日期:2008-02-14 ] [来源:东哥单片机学习网(www.picavr.com) 作者:佚名] [字体: (投递新闻)
可设置8个闹钟时间的智能时钟
1.功能简介
该时钟以24小时制显示时间,并可显示2000年至2049年之间的任何日期及星期,日期与时间经按键可相互切换,可输入8个闹钟时间设置,每个闹钟设置包括响铃的时间(小时与分钟)、对工作日有效还是对周末有效的标志,以及本项设置是否启用的标志等三部分。这8个闹钟设置均保存在EEPROM中,即使掉电也不用重新输入。当然使用者可通过按钮对任何一个设置作修改。数码管可经按钮关闭显示,避免夜间刺眼、影响睡眠。调节LM317输出电压,可改变数码管亮度,但电压不能低于后备电池的电压,否则后备电池供电。用四节1.5V电池串联作后备电源,保证市电停电时时钟继续走时。时钟的精度取决于晶振频率的精度。原理图见下:


程序清单
本程序用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
bit led_on
unsigned char display[8]
unsigned char attr
bit flash
unsigned char show_status
        // 0:设置闹钟数据
// 1:显示当前日期及星期
                                                 // 2:显示当前时间
// 3:设置当前日期
// 4:设置当前时间
bit km
bit kp
bit sound
bit alarm_stop
struct  { unsigned char h
        unsigned char m
       } alarm[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
sbit SDA_PIN   = P1^6
sbit SCL_PIN   = P1^7
void I2cDelay()               //EEPROM操作时需要的延时函数
{ _nop_()
  _nop_()
}
void DelayX1ms(unsigned char count)        //延迟函数,参数为毫秒数
{unsigned char i,j
  for(i=0
    for(j=0
}
void Start()                                        //I2C启动,24C08使用I2C方式
{ SDA_PIN=1
  SCL_PIN=1
  SDA_PIN=0
  SCL_PIN=0
}
void Stop()                         //I2C停止
{ I2cDelay()
  I2cDelay()
  I2cDelay()
  I2cDelay()
}
bit SendByte(unsigned char value)               //发送1字节数据给EEPROM
{unsigned char i
 bit no_ack=0
  for(i=0
  { I2cDelay()
if(value&0x80)   SDA_PIN=1
else            SDA_PIN=0
    value=value<<1
       I2cDelay()
       I2cDelay()
       I2cDelay()
   }
  I2cDelay()
  I2cDelay()
  I2cDelay()
  if(SDA_PIN==1)   no_ack=1
  I2cDelay()
  return no_ack
}
void mywrite(unsigned char address,unsigned char value)         //向EEPROM写1字节
{ Start()
  SendByte(value)
}
unsigned char ReadByte()                    //从EEPROM接收1字节
{unsigned char i,bval
  bval=0
  for(i=0
   { I2cDelay()
     SDA_PIN=1
     I2cDelay()
     I2cDelay()
     I2cDelay()
    }
       I2cDelay()
       I2cDelay()
       I2cDelay()
       I2cDelay()
    return(bval)
}
unsigned char myread(unsigned char address)            //从EEPROM读入1字节数据
{unsigned char tmp
  Start()
  Start()
  Stop()
  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
    else { tmp=(year-1)/4+1
         weekday=(tmp+5)%7
        }
     tmp_days=0
     for(tmp=1
       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
        return
       }
  if(count_down==5000)
  { if((alarm_stop || sound) && alarm[cur_alarm_active].m!=min) //触发后1分钟
      { alarm_stop=0
    if(sound==0 && alarm_stop==0)           //没有已触发的闹钟项
     for(tmp=0
         { 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
          }
    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
                            switch(day)
                            { case 29: if(month==2 && year%4)    { day=1
                                       break
                              case 30: if(month==2 && year%4==0) { day=1
                                       break
                              case 31: if(month==4 || month==6 || month==9 || month==11)
                                       { day=1
                                          break
                              case 32: day=1
                                     if(month==13) { month=1
                             }
               }
           }
       }
     }
}
void Timer1ISR(void) interrupt 3 using 2            //定时器2中断,用于按键扫描
{unsigned char keytmp
 char tmp
  TH1=0x15
  if(show_status==0)   //当前正在设置闹钟项
    { display[0]=cur_alarm_set
     display[2]=alarm[cur_alarm_set].h/10
        display[4]=alarm[cur_alarm_set].m/10
     display[6]=(alarm_wk>>cur_alarm_set)&1
     }
  if(show_status==1 || show_status==3)         //当前显示或设置日期
    { display[0]=year/10
         display[3]=month%10
         display[6]=0xf
     }
  if(show_status==2 || show_status==4)         //当前显示或设置时间
    { display[0]=hour/10
        display[3]=min%10
         display[6]=0xf
        }
  keytmp=~(P1) & 0x0f
  if(keytmp==0)  { km=0
  else
   { if(km==0)   km=1
        else
     { if(kp==0)
        { kp=1
                if(keytmp==1)                  //第一个按钮
                 { if(sound) { alarm_stop=1
                   else if((show_status==1 || show_status==2) && led_on)  //正显示日期或时间
                   { show_status=0
                      else if(show_status==0)                //如正在设置闹钟时间项
                      { show_status=2
                      return
                     }
                if(keytmp==2 && led_on)    //第二个按钮,仅当数码管打开时有效
                 { switch(attr)
                   { case 0xff: if(show_status==1) show_status=2
                                else if(show_status==2) show_status=1
                                      break
                        case 0x3f: if(show_status==0) cur_alarm_set=(cur_alarm_set+1)%8
                      else if(show_status==3)
                             year=(year+1)%50
                     else if(show_status==4)
                         hour=(hour+1)%24
                            break
          case 0xcf: if(show_status==0)                     //闹钟设置的“时”加1
  alarm[cur_alarm_set].h=(alarm[cur_alarm_set].h+1)%24
            else if(show_status==3)
   { month++
     if(month==13) month=1
                           else if(show_status==4)
                            min=(min+1)%60
                                 break
                case 0xf3: if(show_status==0)
                           alarm[cur_alarm_set].m=(alarm[cur_alarm_set].m+1)%60
                         else if(show_status==3)
                           {day++
                            if(day==32) day=1
                         else if(show_status==4)
                           {count_down=8000
                            sec=(sec+1)%60
                              break
            case 0xfd: if(show_status==0)
                                      alarm_wk^=0x1<<cur_alarm_set
                                            break
                         case 0xfe: if(show_status==0)
                                      alarm_en^=0x1<<cur_alarm_set
                       }       //end of switch(attr)
                      return
                     }         //end of if(keytmp==1)
 if(keytmp==4)              //第三个按钮
                 { switch(attr)
                   { case 0xff: if(show_status==1 || show_status==2)
                                   led_on=~led_on
                                            break
                        case 0x3f: if(show_status==0)         //如果正在设置闹钟
                                             { if(cur_alarm_set==0)  cur_alarm_set=7
                             else cur_alarm_set--
                        else if(show_status==3)     //当前日期的“年”减1
                                    { if(year==0)  year=49
                                 else if(show_status==4)     //当前时间的“时”减1
                                             { tmp=hour-1
                                      break
                        case 0xcf: if(show_status==0)          //闹钟设置的“时”减1
                                             { tmp=alarm[cur_alarm_set].h-1
                                               if(tmp<0)    alarm[cur_alarm_set].h=23
                                                  else         alarm[cur_alarm_set].h=tmp
                                                 }
                          else if(show_status==3)
                                    { month--
                             if(month==0)  month=12
                                            else if(show_status==4)
                           { tmp=min-1
                            if(tmp<0) min=59
                                          break
                        case 0xf3: if(show_status==0)          //闹钟设置的“分钟”减1
                                             { tmp=alarm[cur_alarm_set].m-1
                                               if(tmp<0)    alarm[cur_alarm_set].m=59
                                                  else         alarm[cur_alarm_set].m=tmp
                                                 }
                          else if(show_status==3)
                                    { day--
                             if(day==0)  day=31
                                            else if(show_status==4)
                           { tmp=sec-1
                             count_down=8000
                             if(tmp<0) sec=59
                                            break
                        case 0xfd: if(show_status==0)                       //切换周末标志
                                      alarm_wk^=0x1<<cur_alarm_set
                                            break
                        case 0xfe: if(show_status==0)                 //切换启用标志
                                      alarm_en^=0x1<<cur_alarm_set
                       }       //end of switch(attr)
                      return
                     }         //end of if(keytmp==2)
                if(keytmp==8 & led_on)    //第四个按钮,仅当数码管打开时有效
                 { switch(attr)
                      { case 0xff: if(show_status==1)               //如果当前显示日期
                         show_status=3
                               else if(show_status==2)    //如果当前显示时间
                          show_status=4
                                     attr=0x3f
                        case 0x3f: attr=0xcf
                        case 0xcf: attr=0xf3
                        case 0xf3: if(show_status==0) attr=0xfd
                        else if(show_status==3)
                           { show_status=1
                                 else if(show_status==4)
                            { show_status=2
                                          break
                        case 0xfd: if(show_status==0) attr=0xfe
                                   break
                        case 0xfe: if(show_status==0) attr=0x3f
                      }
                     }   // end of if(keytmp==4)
               }      // end of if(kp==0)
        }         // end of if(km==0)
   }            // end of if(keytmp!=0)
}
main()
{unsigned char i
  hour=23
  count_down=8000
  flash=0
  km=0
  new_alarm_info=0
  for(i=0
    { alarm[i].h=myread(i*2)
      alarm_en=myread(i*2)
  IE=0
  TMOD=0x12
  TH0=6
  TH1=0x15
  TR0=1
  ET0=1
  while(1)
  { if(led_on)
      for(i=0
          { P2=0
         if(flash || attr&(0x80>>i))
                 { P0=display[i]
              }
    else  P2=0
    if(new_alarm_info)
     { P2=0
          new_alarm_info=0
       for(i=0
          mywrite(i*2,alarm_en)
         }
  }
}

阅读:
录入:petta

推荐 】 【 打印
本文评论
      全部评论
    BJJ 于22日评论道: 查看全部评论  
怎么不给全呢
    yuyu477764028会员 于23日评论道: 查看全部评论  
还行!!!
    JETTA会员 于18日评论道: 查看全部评论  
不好意思,这个没有原理图是一个网友发的.
    西红柿 于17日评论道: 查看全部评论  
原理图呢??
    111 于25日评论道: 查看全部评论  
上面有for循环的后面一段都不见了
发表评论


点评: 字数
姓名:
赞助商广告