欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5859|回復: 1
打印 上一主題 下一主題
收起左側

可設置8個鬧鐘時間的單片機智能時鐘

[復制鏈接]
跳轉到指定樓層
樓主
                        普通的家用時鐘一般只能設置一個鬧鐘時間,但很多人均需為工作日、周末、早晨、午休等不同時段設置不同的鬧鐘時間。如果是使用普通的鬧鐘,只好每次休息前重新設置,很不方便,有時甚至會出現忘記更改鬧鐘設置而睡過頭的情況。
        
        
        針對這種情況,本人利用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。
        
        
        1、                          電路圖
        
        
        
        
        1、                          功能簡介
        
        該時鐘以24小時制顯示時間,并可顯示2000年至2049年之間的任何日期及星期,日期與時間經按鍵可相互切換,可輸入8個鬧鐘時間設置,每個鬧鐘設置包括響鈴的時間(小時與分鐘)、對工作日有效還是對周末有效的標志,以及本項設置是否啟用的標志等三部分。這8個鬧鐘設置均保存在EEPROM中,即使掉電也不用重新輸入。當然使用者可通過按鈕對任何一個設置作修改。數碼管可經按鈕關閉顯示,避免夜間刺眼、影響睡眠。調節LM317輸出電壓,可改變數碼管亮度,但電壓不能低于后備電池的電壓,否則后備電池供電。用四節1.5V電池串聯作后備電源,保證市電停電時時鐘繼續走時。時鐘的精度取決于晶振頻率的精度。
        
        
        2、                          程序清單
        
        本程序用C語言編寫,經Keil                         C51編譯成二進制碼后寫入89C51內的EPROM內即可。
  1. #include "atmelat89x51.h"

  2. #include "intrins.h"



  3. unsigned char hour,min,sec,year,month,day,weekday;   //當前時間、日期、星期

  4. unsigned int  count_down;      //1秒鐘計時用



  5. bit led_on;                    //數碼管是否點亮的標志

  6. unsigned char display[8];         //8位數碼管要顯示的數據

  7. unsigned char attr;              //八個數碼管的閃爍控制字節,當為0時,對應數碼管閃

  8. bit flash;                            //LED 閃爍開關,與attr共同決定數碼管是否閃爍

  9. unsigned char show_status;     //LED 顯示狀態標志

  10.         // 0:設置鬧鐘數據

  11. // 1:顯示當前日期及星期

  12.                                                  // 2:顯示當前時間

  13. // 3:設置當前日期

  14. // 4:設置當前時間



  15. bit km;                      //按鍵已去抖動標志

  16. bit kp;                       //按鍵已處理標志



  17. bit sound;                    //蜂鳴器響標志

  18. bit alarm_stop;                //蜂鳴器響后用戶手工按停標志

  19. struct  { unsigned char h;           //小時

  20.         unsigned char m;           //分鐘

  21.        } alarm[8];                            //8個鬧鐘項

  22. unsigned char alarm_en;        //鬧鐘項啟用標志

  23. unsigned char alarm_wk;        //鬧鐘項周末啟用標志

  24. unsigned char cur_alarm_set;     //當前設置的鬧鐘項

  25. unsigned char cur_alarm_active;   //當前到點的鬧鐘項

  26. bit new_alarm_info;            //鬧鐘項內容已修改標志



  27. sbit sound_output = P1^5;      //蜂鳴器驅動端口,輸出0時蜂鳴器響

  28. sbit SDA_PIN   = P1^6;          //EEPROM數據線端口

  29. sbit SCL_PIN   = P1^7;          //EEPROM時鐘線端口



  30. void I2cDelay()               //EEPROM操作時需要的延時函數

  31. { _nop_();  _nop_();  _nop_();

  32.   _nop_();  _nop_();  _nop_();

  33. }

  34. void DelayX1ms(unsigned char count)        //延遲函數,參數為毫秒數

  35. {unsigned char i,j;

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

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

  38. }

  39. void Start()                                        //I2C啟動,24C08使用I2C方式

  40. { SDA_PIN=1;   I2cDelay();

  41.   SCL_PIN=1;   I2cDelay();

  42.   SDA_PIN=0;   I2cDelay();

  43.   SCL_PIN=0;   

  44. }

  45. void Stop()                         //I2C停止

  46. { I2cDelay();  SDA_PIN=0;

  47.   I2cDelay();  SCL_PIN=1;

  48.   I2cDelay();  SDA_PIN=1;

  49.   I2cDelay();

  50. }

  51. bit SendByte(unsigned char value)               //發送1字節數據給EEPROM

  52. {unsigned char i;

  53. bit no_ack=0;

  54.   for(i=0;i<8;i++)                     //發送8位數據

  55.   { I2cDelay();   

  56. if(value&0x80)   SDA_PIN=1;

  57. else            SDA_PIN=0;

  58.     value=value<<1;        

  59.        I2cDelay();      SCL_PIN=1;         

  60.        I2cDelay();

  61.        I2cDelay();      SCL_PIN=0;

  62.    }

  63.   I2cDelay();        SDA_PIN=1;     //確認脈沖周期,等待EEPROM的確認

  64.   I2cDelay();        SCL_PIN=1;      

  65.   I2cDelay();      

  66.   if(SDA_PIN==1)   no_ack=1;

  67.   I2cDelay();        SCL_PIN=0;

  68.   return no_ack;

  69. }

  70. void mywrite(unsigned char address,unsigned char value)         //向EEPROM寫1字節

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

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

  73. }

  74. unsigned char ReadByte()                    //從EEPROM接收1字節

  75. {unsigned char i,bval;

  76.   bval=0;

  77.   for(i=0;i<8;i++)                              //接收8位數據

  78.    { I2cDelay();

  79.      SDA_PIN=1;                          //從P1輸入數據時,先往P1輸入“1”

  80.      I2cDelay();    SCL_PIN=1;



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

  82.      I2cDelay();    SCL_PIN=0;

  83.     }

  84.        I2cDelay();     SDA_PIN=1;    //確認脈沖周期,不送出確認

  85.        I2cDelay();     SCL_PIN=1;   

  86.        I2cDelay();     

  87.        I2cDelay();



  88.     return(bval);

  89. }

  90. unsigned char myread(unsigned char address)            //從EEPROM讀入1字節數據

  91. {unsigned char tmp;

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

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

  94.   Stop();         DelayX1ms(2);

  95.   return(tmp);

  96. }

  97. void Timer0ISR(void) interrupt 1 using 3     //定時器0中斷程序,用于走時,1/8000秒一次

  98. {unsigned char tmp,tmp_days;

  99.   count_down--;

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

  101.    { flash=~flash;                                   //數碼管閃爍的開關量

  102.      if(sound && flash) sound_output=0;         //驅動蜂鳴器

  103.      else             sound_output=1;         //關閉蜂鳴器

  104.         return;

  105.        }

  106.                      /*** 計算當前日期為星期幾***/

  107.   if(count_down==3000)

  108.    { if(year==0)       weekday=5;           //2000年1月1日為星期六

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

  110.          weekday=(tmp+5)%7;           //計算出當前年的1月1日為星期幾

  111.         }

  112.      tmp_days=0;

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

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

  115.           tmp_days=tmp_days+31;

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

  117.              tmp_days=tmp_days+30;

  118.        else if(tmp==2)

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

  120.             else         tmp_days=tmp_days+28;

  121.            }

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

  123.         return;

  124.        }

  125.                   /***  查詢是否有鬧鐘時間項符合觸發條件 ***/

  126.   if(count_down==5000)

  127.   { if((alarm_stop || sound) && alarm[cur_alarm_active].m!=min) //觸發后1分鐘

  128.       { alarm_stop=0; sound=0; }                                                //自動關蜂鳴器



  129.     if(sound==0 && alarm_stop==0)           //沒有已觸發的鬧鐘項

  130.      for(tmp=0;tmp<8;tmp++)                           //則查詢8個鬧鐘項內是否有符合條件的

  131.          { if(((alarm_en>>tmp)&1)==0) continue;    //該鬧鐘項不啟用

  132.            if(((alarm_wk>>tmp)&1)==1)           //該鬧鐘項周末有效

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

  134.               else

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



  136.         if(alarm[tmp].h==hour && alarm[tmp].m==min)             //比較當前時間與該

  137.           { sound=1;  cur_alarm_active=tmp; break; }         //鬧鐘項的時間

  138.           }

  139.     return;

  140.    }



  141.   if(count_down==0)                              //過了一秒鐘

  142.    { count_down=8000;

  143.      sec++;

  144.      if(sec==60)

  145.       { sec=0;

  146.         min++;

  147.         if(min==60)

  148.           { min=0;

  149.             hour++;

  150.             if(hour==24)

  151.               { hour=0;   day++;

  152.                             switch(day)

  153.                             { case 29: if(month==2 && year%4)    { day=1; month=3; }

  154.                                        break;

  155.                               case 30: if(month==2 && year%4==0) { day=1; month=3; }

  156.                                        break;

  157.                               case 31: if(month==4 || month==6 || month==9 || month==11)

  158.                                        { day=1; month++; }

  159.                                           break;

  160.                               case 32: day=1;          month++;

  161.                                      if(month==13) { month=1; year++; }

  162.                              }

  163.                }

  164.            }

  165.        }

  166.      }

  167. }



  168. void Timer1ISR(void) interrupt 3 using 2            //定時器2中斷,用于按鍵掃描

  169. {unsigned char keytmp;

  170. char tmp;



  171.   TH1=0x15; TL1=0xa0;      // 每30ms中斷一次



  172.                  /***  當前顯示的內容 ***/

  173.   if(show_status==0)   //當前正在設置鬧鐘項

  174.     { display[0]=cur_alarm_set;               display[1]=0xf;

  175.      display[2]=alarm[cur_alarm_set].h/10;      display[3]=alarm[cur_alarm_set].h%10;

  176.         display[4]=alarm[cur_alarm_set].m/10;      display[5]=alarm[cur_alarm_set].m%10;

  177.      display[6]=(alarm_wk>>cur_alarm_set)&1;  display[7]=(alarm_en>>cur_alarm_set)&1;

  178.      }



  179.   if(show_status==1 || show_status==3)         //當前顯示或設置日期

  180.     { display[0]=year/10;       display[1]=year%10;    display[2]=month/10;  

  181.          display[3]=month%10;    display[4]=day/10;   display[5]=day%10;

  182.          display[6]=0xf;         display[7]=weekday;

  183.      }



  184.   if(show_status==2 || show_status==4)         //當前顯示或設置時間

  185.     { display[0]=hour/10;      display[1]=hour%10;    display[2]=min/10;

  186.         display[3]=min%10;     display[4]=sec/10;       display[5]=sec%10;

  187.          display[6]=0xf;         display[7]=0xf;   //最后兩后無顯示

  188.         }



  189.                     /***  按鍵掃描及處理  ***/

  190.   keytmp=~(P1) & 0x0f;

  191.   if(keytmp==0)  { km=0;  kp=0; }  

  192.   else

  193.    { if(km==0)   km=1;  

  194.         else

  195.      { if(kp==0)

  196.         { kp=1;

  197.                 if(keytmp==1)                  //第一個按鈕

  198.                  { if(sound) { alarm_stop=1; sound=0; }      //如果鬧鐘正響,按此鍵停止

  199.                    else if((show_status==1 || show_status==2) && led_on)  //正顯示日期或時間

  200.                    { show_status=0;  cur_alarm_set=0;  attr=0x3f; }  //進入鬧鐘設置

  201.                       else if(show_status==0)                //如正在設置鬧鐘時間項

  202.                       { show_status=2;  new_alarm_info=1; attr=0xff; }  //返回當前時間顯示

  203.                       return;

  204.                      }

  205.                   

  206.                 if(keytmp==2 && led_on)    //第二個按鈕,僅當數碼管打開時有效

  207.                  { switch(attr)

  208.                    { case 0xff: if(show_status==1) show_status=2;   //在顯示時間與日期間切換

  209.                                 else if(show_status==2) show_status=1;

  210.                                       break;

  211.                         case 0x3f: if(show_status==0) cur_alarm_set=(cur_alarm_set+1)%8;

  212.                       else if(show_status==3)

  213.                              year=(year+1)%50;       //當前日期的“年”加1

  214.                      else if(show_status==4)

  215.                          hour=(hour+1)%24;       //當前時間的“時”加1

  216.                             break;   

  217.           case 0xcf: if(show_status==0)                     //鬧鐘設置的“時”加1

  218.   alarm[cur_alarm_set].h=(alarm[cur_alarm_set].h+1)%24;

  219.             else if(show_status==3)

  220.    { month++;                //當前日期的“月”加1

  221.      if(month==13) month=1; }

  222.                            else if(show_status==4)

  223.                             min=(min+1)%60;         //當前時間的“分”加1

  224.                                  break;

  225.                 case 0xf3: if(show_status==0)

  226.                            alarm[cur_alarm_set].m=(alarm[cur_alarm_set].m+1)%60;

  227.                          else if(show_status==3)

  228.                            {day++;                  //當前日期的“日”加1

  229.                             if(day==32) day=1; }

  230.                          else if(show_status==4)

  231.                            {count_down=8000;

  232.                             sec=(sec+1)%60; }        //當前時間的“秒”加1

  233.                               break;               

  234.             case 0xfd: if(show_status==0)

  235.                                       alarm_wk^=0x1<<cur_alarm_set; 周末標志位切換

  236.                                             break;

  237.                          case 0xfe: if(show_status==0)

  238.                                       alarm_en^=0x1<<cur_alarm_set; 啟用標志位切換

  239.                        }       //end of switch(attr)

  240.                       return;

  241.                      }         //end of if(keytmp==1)



  242.                 if(keytmp==4)           //第三個按鈕

  243.                  { switch(attr)

  244.                    { case 0xff: if(show_status==1 || show_status==2)

  245.                                    led_on=~led_on;        //打開或關閉數碼管顯示

  246.                                             break;

  247.                         case 0x3f: if(show_status==0)         //如果正在設置鬧鐘

  248.                                              { if(cur_alarm_set==0)  cur_alarm_set=7;

  249.                              else cur_alarm_set--;}

  250.                         else if(show_status==3)     //當前日期的“年”減1

  251.                                     { if(year==0)  year=49;  else year--; }

  252.                                  else if(show_status==4)     //當前時間的“時”減1

  253.                                              { tmp=hour-1;  if(tmp<0) hour=23;  else  hour=tmp;  }

  254.                                       break;

  255.                         case 0xcf: if(show_status==0)          //鬧鐘設置的“時”減1

  256.                                              { tmp=alarm[cur_alarm_set].h-1;

  257.                                                if(tmp<0)    alarm[cur_alarm_set].h=23;

  258.                                                   else         alarm[cur_alarm_set].h=tmp;

  259.                                                  }

  260.                           else if(show_status==3)         

  261.                                     { month--;             //當前日期的“月”減1

  262.                              if(month==0)  month=12; }

  263.                                             else if(show_status==4)         

  264.                            { tmp=min-1;           //當前時間的“分”減1

  265.                             if(tmp<0) min=59;   else  min=tmp;   }

  266.                                           break;

  267.                         case 0xf3: if(show_status==0)          //鬧鐘設置的“分鐘”減1

  268.                                              { tmp=alarm[cur_alarm_set].m-1;

  269.                                                if(tmp<0)    alarm[cur_alarm_set].m=59;

  270.                                                   else         alarm[cur_alarm_set].m=tmp;

  271.                                                  }

  272.                           else if(show_status==3)     

  273.                                     { day--;                 //當前日期的“日”減1

  274.                              if(day==0)  day=31; }

  275.                                             else if(show_status==4)        

  276.                            { tmp=sec-1;             //當前時間的“秒”減1

  277.                              count_down=8000;

  278.                              if(tmp<0) sec=59;   else  sec=tmp; }

  279.                                             break;

  280.                         case 0xfd: if(show_status==0)                       //切換周末標志

  281.                                       alarm_wk^=0x1<<cur_alarm_set;

  282.                                             break;

  283.                         case 0xfe: if(show_status==0)                 //切換啟用標志

  284.                                       alarm_en^=0x1<<cur_alarm_set;

  285.                        }       //end of switch(attr)

  286.                       return;

  287.                      }         //end of if(keytmp==2)



  288.                 if(keytmp==8 & led_on)    //第四個按鈕,僅當數碼管打開時有效

  289.                  { switch(attr)

  290.                       { case 0xff: if(show_status==1)               //如果當前顯示日期

  291.                          show_status=3;       //切換到調準日期狀態

  292.                                else if(show_status==2)    //如果當前顯示時間

  293.                           show_status=4;      //切換到調準時間狀態

  294.                                      attr=0x3f; break;               //第一、二個數碼管閃爍

  295.                         case 0x3f: attr=0xcf; break;           //第三、四個數碼管閃爍

  296.                         case 0xcf: attr=0xf3; break;           //第五、六個數碼管閃爍

  297.                         case 0xf3: if(show_status==0) attr=0xfd;   //第七個數碼管閃爍

  298.                         else if(show_status==3)

  299.                            { show_status=1; attr=0xff; }  //恢復正常顯示日期

  300.                                  else if(show_status==4)

  301.                             { show_status=2; attr=0xff; }  //恢復正常顯示時間

  302.                                           break;

  303.                         case 0xfd: if(show_status==0) attr=0xfe;     //第八個數碼管閃爍

  304.                                    break;

  305.                         case 0xfe: if(show_status==0) attr=0x3f;     //第一、二個數碼管閃爍

  306.                       }

  307.                      }   // end of if(keytmp==4)

  308.                }      // end of if(kp==0)

  309.         }         // end of if(km==0)

  310.    }            // end of if(keytmp!=0)

  311. }



  312. main()

  313. {unsigned char i;



  314.   hour=23;  min=58;  sec=30;  year=2;  month=4;  day=25;

  315.   count_down=8000;



  316.   flash=0;    attr=0xff;      led_on=1;

  317.   km=0;     kp=0;          show_status=2;     //加電后顯示當前時間



  318.   new_alarm_info=0;  sound=0;   alarm_stop=0;  



  319.   for(i=0;i<8;i++)           //從EEPROM中讀入8個鬧鐘設置

  320.     { alarm[i].h=myread(i*2);  alarm[i].m=myread(i*2+1); }

  321.       alarm_en=myread(i*2);        alarm_wk=myread(i*2+1);



  322.   IE=0;  IP=0;             //disable all interrupt and lower priority

  323.   TMOD=0x12;             //timer 0 is set to mode 2,auto_reloading,timer1,mode 1

  324.   TH0=6;    TL0=6;        //timer0 parameters for 0.125ms

  325.   TH1=0x15; TL1=0xa0;      //timer1 parameters for 30ms

  326.   TR0=1;    TR1=1;        //timer0 interrupt most important

  327.   ET0=1;    ET1=1;    EA=1;     //enable interrupt function



  328.   while(1)

  329.   { if(led_on)

  330.       for(i=0;i<8;i++)

  331.           { P2=0;

  332.          if(flash || attr&(0x80>>i))

  333.                  { P0=display[i];  P2=0x80>>i; DelayX1ms(1); }

  334.               }

  335.     else  P2=0;  



  336.     if(new_alarm_info)

  337.      { P2=0;                  //暫時關閉數碼管

  338.           new_alarm_info=0;      //寫入EEPROM

  339.        for(i=0;i<8;i++)  { mywrite(i*2,alarm[i].h);  mywrite(i*2+1,alarm[i].m); }

  340.           mywrite(i*2,alarm_en);   mywrite(i*2+1,alarm_wk);

  341.          }

  342.   }  

  343. }

  344.  
復制代碼



</cur_alarm_set;
</cur_alarm_set;
</month;tmp++)
</count;i++)
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:105494 發表于 2016-2-19 15:15 | 只看該作者
嘿嘿嘿嘿呵呵嘿嘿
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表