DS1302

雖然程序大部分是一個網友的(我只改了3個函數),思路也是別人的。可是看在我搞了1天的份上面還是算原創吧,o(∩_∩)o...

注意那個IO口要和電源間接個電阻哦,還有我的外接電源用的手機電池,爲這個去買充電電池不划算的

 
# include <AT89x52.h>
/*****************************************
         P0------DB0~DB7         
   P1.0------RS
   P1.1------RW
   P1.2------E
*****************************************/
# define LCD_DB        P0
  sbit         LCD_RS=P1^0;
  sbit         LCD_RW=P1^1;
  sbit         LCD_E=P1^2;
  sbit         DS1302_SCLK = P3^4;
  sbit         DS1302_IO   = P3^3;
  sbit         DS1302_RST  = P3^5;
  //定義待設置的時間:秒、分、時、日、月、星期、年、控制字
  char table[]={0x00,0x58,0x12,0x8,0x3,0x06,0x06,0x00};
  char table1[]={0x11};
  char table2[]={0x22};
  unsigned char bdata time_rx ;
  sbit     time_rx7 = time_rx^7;
/******定義函數****************/
# define uchar unsigned char
# define uint unsigned int

void LCD_init(void);//初始化函數
void LCD_write_command(uchar command);//寫指令函數
void LCD_write_data(uchar dat);//寫數據函數
void LCD_disp_char(uchar x,uchar y,uchar dat);//在某個屏幕位置上顯示一個字符,X(0-16),y(1-2)
void delay_n40us(uint n);//延時函數
  //寫一個字節數據函數
void time_write_1(unsigned char time_tx)
{
     int j;                             //設置循環變量
     for(j=0;j<8;j++)                   //連續寫8bit
       {
         DS1302_IO    =  0;                         //先設置數據爲0
         DS1302_SCLK  =  0;                        //時鐘信號拉低
         if(time_tx&0x01)               //判斷待發送的數據位是0或1
         {
             DS1302_IO = 1;                     //待發送數據位是1
         }
         time_tx=time_tx>>1;            //待發送的數據右移1位
         DS1302_SCLK = 1;                        //拉高時鐘信號
        }
         DS1302_SCLK = 0;                          //寫完一個字節,拉低時鐘信號
   }
//---------------------------------------------
//讀一個字節函數
unsigned char time_read_1()
{
    int j;                             //設置循環變量
  
 
 DS1302_IO = 1;        //設置爲輸入方式
    for(j=0;j<8;j++)                   //連續讀取8bit
    {
         DS1302_SCLK  = 0;                       //拉低時鐘信號
         time_rx=time_rx>>1;           //接收寄存器右移1位
         time_rx7=DS1302_IO;          //把接收到的數據放到接收寄存器的最高位
         DS1302_SCLK = 1;                        //拉高時鐘信號
       }
     
     DS1302_SCLK = 0;                           //拉低時鐘信號
     return(time_rx);                  //返回讀取到的數據
 }
 
//DS1302初始化函數
void ds1302_init()
{
    DS1302_SCLK  =   0;                             //拉低時鐘信號
    DS1302_RST   =   0;                             //復位DS1302
    DS1302_RST   =   1;                             //使能DS1302
    time_write_1(0x8e);                              //發控制命令
    time_write_1(0);                                  //允許寫DS1302
 
    DS1302_RST   =   0;                              //復位
 }
//---------------------------------------------
 //---------------------------------------------
//設置時間函數
void set_time()
{
    int i;                              //定義循環變量
    DS1302_RST = 1;                     //使能DS1302
    time_write_1(0xbe);                 //時鐘多字節寫命令
    for(i=0;i<8;i++)                    //連續寫8個字節數據
    {
        time_write_1(table[i]);         //調用寫一個字節函數
    }
    DS1302_RST = 0;                              //復位
}
//---------------------------------------------
 

//---------------------------------------------
//設置是否初始化標誌
void set_ytime()
{
   
    DS1302_RST = 1;                              //使能DS1302
    time_write_1(0xc0);                 //時鐘多字節寫命令
   
    time_write_1(table1[0]);         //調用寫一個字節函數
    
    DS1302_RST = 0;                              //復位
}
//讀取初始化標誌函數
void get_ytime()
{
    
    DS1302_RST = 1;                              //使能DS1302
    time_write_1(0xc1);                 //發送多字節讀取命令
    
    table2[0]=time_read_1();       //調用讀取1個字節數據的函數
     
    DS1302_RST = 0;                             //復位DS1302
}
//---------------------------------------------
 
 
//讀取時間函數
void get_time()
{
    int i;                              //設置循環變量
    DS1302_RST = 1;                              //使能DS1302
    time_write_1(0xbf);                 //發送多字節讀取命令
    for(i=0;i<7;i++)                    //連續讀取7個字節數據
      {
         table[i]=time_read_1();       //調用讀取1個字節數據的函數
      }
    DS1302_RST = 0;                             //復位DS1302
}

//*******初始化函數***************
void LCD_init(void)
{
    delay_n40us(10000);
    LCD_write_command(0x38);//設置8位格式,2行,5x7
    LCD_write_command(0x38);//設置8位格式,2行,5x7
    LCD_write_command(0x38);//設置8位格式,2行,5x7
    
 LCD_write_command(0x02);//整體顯示,關光標,不閃爍
 LCD_write_command(0x0C);//清除屏幕顯示
    LCD_write_command(0x06);//設定輸入方式,增量不移位
}
//********************************
//********寫指令函數************
void LCD_write_command(uchar dat)
{
    
    LCD_E = 0;
 
 LCD_RS=0;//指令
    LCD_RW=0;//寫入
    LCD_DB=dat;
 
 LCD_E=1;//允許
 delay_n40us(10);//實踐證明,我的LCD1602上,用for循環1次就能完成普通寫指令。
    LCD_E = 0;
}
//*******************************
//********寫數據函數*************
void LCD_write_data(uchar dat)
{
     LCD_E = 0;    
  LCD_RS=1;//數據
     LCD_RW=0;//寫入
     LCD_DB=dat;
  
  LCD_E=1;//允許
     delay_n40us(10);
     
  LCD_E = 0;
}
//********************************
//*******顯示一個字符函數*********
void LCD_disp_char(uchar x,uchar y,uchar dat)
{
  uchar address;
     if(y==1)
              address="0x80"+x;
     else
              address="0xc0"+x;
     LCD_write_command(address);
     LCD_write_data(dat);
}
 
void delay_n40us(uint n)
{    
       uint i;
      uchar j;           
        for(i=n;i>0;i--)
           for(j=0;j<15;j++)
            ;          //
}                                         //
//*******************************
void disp_time()
{
    LCD_disp_char(3,1,((table[2]&0xf0)>>4)+0x30); 
 
 LCD_disp_char(4,1,(table[2]&0x0f)+0x30);
 
 LCD_disp_char(5,1,':');
 
 LCD_disp_char(6,1,((table[1]&0xf0)>>4)+0x30); 
 
 LCD_disp_char(7,1,(table[1]&0x0f)+0x30);
 
 
 LCD_disp_char(8,1,':');
 LCD_disp_char(9,1,((table[0]&0xf0)>>4)+0x30); 
 
 LCD_disp_char(10,1,(table[0]&0x0f)+0x30);
 

}
//*********主函數*****************
void main(void)
{       
    
  get_ytime();
       
  if(table2[0]==0x11)
      {
    ;
      }
    else
   {
      ds1302_init();                    //調用DS1302初始化函數
        
         set_time();                       //調用設置時間函數 
      set_ytime();                       //調用設置標誌函數
   }
   
   
         DS1302_RST   =   1;                             //使能DS1302
        time_write_1(0x90);                 //充電命令
   
        time_write_1(0xa5);         //打開充電二級管  一個二級管串聯一個2K電阻
     DS1302_RST   =   0;                             //復位DS1302 
       
 
    
  LCD_init();
        while(1)
  {
     get_time();                  //調用取時間函數
     
     disp_time();
     
   }
        
}


這是我接觸到的第一個時鐘芯片,編寫這個時間模塊程序,可是費了不少周折,這裏will666博客裏面有芯片資料http://blog.ednchina.com/will666/49952/message.aspx

 

使用的時候,S7偏上的兩個腳要連起來,S8也是。這個不難,看wangjin博客上面有電路圖,不過WILL66上面S7、S8那個接口圖把ps2和時鐘標反了。

如果你的還是不能正常顯示,顯示什麼85呀,??呀,o(∩_∩)o...,那就在時鐘芯片的IO腳與VCC之間接個上拉電阻吧。1K或者4.7K的都行(我自己是接的一個滑動變阻器)http://group.ednchina.com/329/3374.aspx

 

調試程序就不帖了,在小組裏面找找哦。

還有那個備用電源VCC1可以不接,只是每次開機了上次的時間不會保持,如果要接的話,從資料上面看,要接那種可以充電的電池,因爲資料上面說平時VCC2對VCC1充電,當VCC2電壓比較低了就用VCC1的電源,就是類似於電腦主板上面的那個電池一樣的。

下面是引用一個網友的資料,就是外接電源後,爲什麼時間還是沒有保持的問題,o(∩_∩)o...,因爲你每次開機都把時鐘芯片初始化了呀。

關於DS1302的初始化也是有技巧的,這是一個可以帶備用電池的芯片,放上電池,即使把電源關了,它的時間還是在走的,呵呵,和電腦一樣呀!這樣的話,如果它的備用電池不斷電,就不用再對它初始化啦,也就是說一輩子不斷電,這一輩子它只要初始化一次就行了,但是單片機如果斷電再通電,程序又會從頭開始執行,又會執行它的初始化程序,我開始以爲只要不破壞它的時鐘數據就行,單片機開機時先讀一次時鐘數據,然後把控制字疊加進去,再寫回去就好了,可試驗了好幾次都不行,每次都是小時的數據不對了。於是在DS1302暫存RAM中設立一個標誌位,只要備用電池不斷電,標誌就不會消失,每次通電開機時,單片機檢測到這個標誌就不再對其初始化,呵呵,一切正常。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章