[!--tag.name--]

DS1302时钟芯片程序

标签:DS1302   

《DS1302时钟芯片程序》这篇文章中存在错误,具体如下:

*错误描述:
*联系邮箱:

注意那个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(); 
      
   } 
         


编写这个时间模块程序,可是费了不少周折
 
使用的时候,S7偏上的两个脚要连起来,S8也是。这个不难,看wangjin博客上面有电路图,不过WILL66上面S7、S8那个接口图把ps2和时钟标反了。

如果你的还是不能正常显示,显示什么85呀,??呀,o(∩_∩)o...,那就在时钟芯片的IO脚与VCC之间接个上拉电阻吧。1K或者4.7K的都行(我自己是接的一个滑动变阻器)

还有那个备用电源VCC1可以不接,只是每次开机了上次的时间不会保持,如果要接的话,从资料上面看,要接那种可以充电的电池,因为资料上面说平时VCC2对VCC1充电,当VCC2电压比较低了就用VCC1的电源,就是类似于电脑主板上面的那个电池一样的。

下面是引用一个网友的资料,就是外接电源后,为什么时间还是没有保持的问题,o(∩_∩)o...,因为你每次开机都把时钟芯片初始化了呀。

关于DS1302的初始化也是有技巧的,这是一个可以带备用电池的芯片,放上电池,即使把电源关了,它的时间还是在走的,呵呵,和电脑一样呀!这样的话,如果它的备用电池不断电,就不用再对它初始化啦,也就是说一辈子不断电,这一辈子它只要初始化一次就行了,但是单片机如果断电再通电,程序又会从头开始执行,又会执行它的初始化程序,我开始以为只要不破坏它的时钟数据就行,单片机开机时先读一次时钟数据,然后把控制字叠加进去,再写回去就好了,可试验了好几次都不行,每次都是小时的数据不对了。于是在DS1302暂存RAM中设立一个标志位,只要备用电池不断电,标志就不会消失,每次通电开机时,单片机检测到这个标志就不再对其初始化,呵呵,一切正常。