1. 程式人生 > >51微控制器實時時鐘 PCF8563時鐘晶片

51微控制器實時時鐘 PCF8563時鐘晶片

實現實時時鐘,電源拔插時間不重置(內建電池供電維持時間變化)。功能有檢視日期,檢視星期,檢視鬧鐘和分別的調整時間,調整日期,調整鬧鐘,調整星期。且預設情況下不可以調整,當按下可調控鍵之後才可以調整、再次按可調控鍵關閉變為不可調整狀態。還有整點報時功能(有個小瑕疵就是鬧鐘正好是整點的時候和這個整點報時同時間的時候不會報時和鬧鐘,這個很容易改好,因為下午3點要答辯了,懶得改了機子老是寫不進去,學校窮便宜機子沒辦法)。然後這個鬧鐘可以設定星期幾幾點鬧也可以設定為普通的每天的這個時間點鬧鈴,這些都是可以調控的。時鐘所有的功能都有,只差一個秒錶,,這個很簡單,,,外部中斷來一個或者定時器T1中斷來一個都可以,我沒弄,因為我這個已經程式碼很長了,頭疼、加中斷還得加顯示函式和秒錶變化函式if分大於60 時++啥的,但因為這個採用的顯示是低四位高四位控制的,我強行加一個也比較麻煩所有就沒加了。歡迎下載乾貨,難看懂的都有備註,寫了斷斷續續一週+時間左右(恕在下才疏學淺,因為書上上課的時候沒學過I2C匯流排和pcf8563所以寫的比較久。)部分程式碼如下:

#define MAIN_Fosc             22118400L     //定義主時鐘  頻率也是計數計時週期一秒的計數值

#include "STC15Fxxxx.H" 

/***********************************************************/

#define DIS_DOT         0x20

#define DIS_BLACK      0x10

#define DIS_         0x11

/****************************** 使用者定義巨集***********************************/

#define   Timer0_Reload      (65536UL -(MAIN_Fosc / 1000))         //Timer 0 中斷頻率,1000次/秒 頻率倍數計數即週期 週期為1秒 除以一千就是1000次每秒

/*****************************************************************************/

/************* 本地常量宣告       **************/

u8 code t_display[]={                                       //標準字型檔

       //     0   1    2    3   4    5    6   7    8    9   A    B    C   D    E    F //共陰

       0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,

              //black    -    H    J     K     L     N      o   P     U     t   G    Q    r  M    y

              0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,

              0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1

       u8code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};             //位碼 取反就是書上213面   0從低位到高位

       /************* IO口定義      **************/

       sbit  P_HC595_SER  = P4^0;     //pin 14  SER         datainput

       sbit  P_HC595_RCLK = P5^4;    //pin 12  RCLk      store(latch) clock

       sbit  P_HC595_SRCLK = P4^3;     //pin 11  SRCLK    Shift data clock

       sbit    led=P1^7;

       sbit    led1=P4^7;

       sbit    key=P3^2;

       /************* 本地變數宣告       **************/

       u8  LED8[8];         //顯示緩衝

       u8   display_index; //顯示位索引

       bit   B_1ms;                  //1ms標誌

       u8IO_KeyState, IO_KeyState1, IO_KeyHoldCnt; //行列鍵盤變數

       u8   KeyHoldCnt;  //鍵按下計時

       u8   KeyCode;       //給使用者使用的鍵碼, 1~16有效

       u8   cnt50ms;

       u8hello;

       u8nao;

       u8minute2;

       u8KeyCode0;

       u8   hour,hour1,minute,minute1,second,day,week,week1,month,year;  //RTC變數

       u16  msecond;

       u16msecond1;

       u8hello;

       u8naofu;

       u8zhuangtai;

       u8xunhuan;

       u8tuinao; //鬧鐘控制開啟退出

       u8xinqinao;//星期·鬧鐘

       /************* 本地函式宣告       **************/

       void CalculateAdcKey(u16 adc);

       void IO_KeyScan(void); //50ms call

       void WriteNbyte(u8 addr, u8 *p, u8 number);

       void ReadNbyte( u8 addr, u8 *p, u8 number);

       void DisplayRTC(void);

       void DisplayRTC1(void);

       void DisplayRTC2(void);

       void ReadRTC(void);//讀取時鐘

       void ReadRTC1(void);

       void ReadRTC2(void);

       void ReadRTC3(void);

       void WriteRTC(void);

       void WriteRTC1(void);

       void WriteRTC2(void);

       void WriteRTC3(void);

       void      DisplayRTC3(void);

       void      DisplayRTC4(void);

       void    DisplayRTC5(void);

       /****************  外部函式宣告和外部變數宣告*****************/

       /**********************************************/

       voidmain(void)

       {

              u8   i;

              P0M1= 0;      P0M0 = 0;      //設定為準雙向口

              P1M1= 0;      P1M0 = 0;      //設定為準雙向口

              P2M1= 0;      P2M0 = 0;      //設定為準雙向口

              P3M1= 0;      P3M0 = 0;      //設定為準雙向口

              P4M1= 0;      P4M0 = 0;      //設定為準雙向口

              P5M1= 0;      P5M0 = 0;      //設定為準雙向口

              P6M1= 0;      P6M0 = 0;      //設定為準雙向口

              P7M1= 0;      P7M0 = 0;      //設定為準雙向口

              display_index= 0;              

              AUXR= 0x80;//T0時鐘無分頻

              TMOD=0x00; //Timer0 set as 1T, 16 bits timer auto-reload,T0時鐘無分頻,16位自動重灌

              TH0= (u8)(Timer0_Reload / 256);      //定時器取其高低8位為狀態值

              TL0= (u8)(Timer0_Reload % 256);

              ET0= 1;  //Timer0 interrupt enable  T0中斷允許

              TR0= 1;  //Tiner0 run   T0啟動

              EA= 1;          //開啟總中斷 ,總中斷允許

              hello=0;

              if(nao==1){}//斷電重置

              elseif(nao==2){}

              else

              {

              nao=0;

              }

              for(i=0;i<8; i++)   LED8[i] = 0x10;      //上電消隱     dp高位 防止極短時間內出現兩個數字的重疊

              ReadRTC();//讀取時鐘

              ReadRTC1();

              F0= 0;

              if(second>= 60)   F0 = 1;    //錯誤

              if(minute>= 60)    F0 = 1;    //錯誤

              if(hour   >= 24)   F0= 1;    //錯誤

              if(F0==1) //有錯誤, 預設12:00:00

              {

                     second= 0;

                     minute= 0;

                     hour  = 12;

                     WriteRTC();

              }

              if(day>=32)    F0=2;

              if(week>=8)   F0=2;

              if(month>=13)F0=2;

              if(year>=100)F0=2;

              if(F0==2) //有錯誤, 預設12:00:00

              {

                     day=6;

                     week=3;

                     month=6;

                     year=18;

                     WriteRTC1();

              }

              if(minute1>= 60)  F0 = 3;    //錯誤

              if(hour1   >= 24) F0= 3;    //錯誤

              if(F0==3)

              {

                     minute1=30;

                     hour1=7;

                     WriteRTC2();

              }

              if(week1>=8)

              {

                     WriteRTC3();

              }

              DisplayRTC();

              KeyHoldCnt= 0;    //鍵按下計時

              KeyCode= 0; //給使用者使用的鍵碼,1~16有效

              IO_KeyState= 0;

              IO_KeyState1= 0;

              IO_KeyHoldCnt= 0;

              cnt50ms= 0;

              zhuangtai=0;

              KeyCode0=0;

              tuinao=0;

              minute2=61;

              naofu=0;//控制鬧鐘加1加5與分鐘同步

              xunhuan=0;//控制迴圈鬧鐘

              xinqinao=0;//星期鬧鐘控制

              if(msecond1==0){}

              else

              {

              msecond1=0;

              }

              while(1)

              {

                            if(B_1ms) //1ms到

                            {

                                   B_1ms= 0;

                                   if(++msecond>= 500) //1秒到 重新整理時鐘

                                   {

                                          if(hello==0)

                                          {

                                                 ReadRTC();

                                                 DisplayRTC();

                                                 if(minute==0)  //整點報時

                                                        {

                                                               if(hour==hour1)

                                                               {

                                                               if(minute==minute1)

                                                               {}else{

                                                               led1=0;

                                                               }

                                                               }else

                                                               {

                                                                      led1=0;

                                                               }

                                                        }

                                                        else{

                                                               led1=1;

                                                 }

                                                 if(hour==hour1)    //鬧鐘實現塊

                                                 {                   

                                                        if(second==0)//保證和時鐘分鐘同步++乘其下一分鐘前進行+5 +1操作

                                                        {

                                                               msecond1=0;

                                                               naofu=1;

                                                        }

                                                        else

                                                        {

                                                        if(naofu==1)

                                                        {

                                                               if(++msecond1>=60)

                                                               {msecond1=0;

                                                               naofu=0;

                                                               }

                                                        }

                                                        }

                                                        if(minute==minute1-1)//取出鬧鐘分鐘值

                                                        {      ReadRTC2();

                                                               minute2=minute1;

                                                        }