zyn10101010 发表于 2012-2-22 15:13:54

PCF8563 能读时间,不能设置时间

PCF8563 是用在手持设备中,
有时候会出现能读时间,但是不能设置时间,
只有复位PCF8563后(切断后备电池)才能再次设置时间。
迷惑中,不知道有谁碰到过。
还请多指教。

lvyunzeng 发表于 2012-2-22 15:16:33

// ===============================================================================================                                               
// 文件名称:PCF8563.c
// 芯片类型: MSP430F149                                                                                                             
// 开发软件: IAR Embedded Workbench V3.2 , Windows XP                                                                                    
// 开发时间:2007年07月08日 ---2007年07月10日                                                               
// 程序功能:使用M430的P4.6、P4.7对外部的IIC时钟进行读写操作
// 编写人员:吕云曾                                                                     
// 联系方式:13845052176lvyunzeng@163.com
//=================================================================================================                                             
//==连接芯片的管脚连接==
//                         --- --- --- VCC
//               PCF8563    |10k 10k   MSP430               
//            |--------||   |   | |----------|   
//32.768KHz---|OSIVDD|---   |   | |          |
//       |------|OSOCLK|      |   | |          |
// P1.7-+-------|INTSCL|<-----+---|-|P4.7      |   
//      |    |--|VSSSDA|<---------+>|P4.6      |
//   10K   ||--------|            |----------|
//VCC---\|/ GND                  
//========================================= 头文件 ================================================
#include<msp430x14x.h>

//========================================== 宏定义 ===============================================
//========================== 宏定义 =================================
#define Uchar unsigned char
#define uchar unsigned char
#define Uintunsigned int
#define Ulong unsigned long
//==PCF8563 定义 ==   
#define SCL0 ClrP2(2)
#define SCL1 SetP2(2)
#define SDA0 ClrP2(1)
#define SDA1 SetP2(1)
#define DIR_IN      P2DIR &=~ BIT1             //I/O口为输入
#define DIR_OUT   P2DIR |=BIT1            //I/0口为输出
#define SDA_IN      ((P2IN >> 1) & 0x01)      //Read SDA

#define ClrP2(n) P2OUT&=(~(1<<n))
#define SetP2(n) P2OUT|=(1<<n)


//======================================= 变量定义 =================================================
uchar g8563_Store;    //== 时间交换区,全局变量声明 ==
/*
PCF8563_time --- 秒   ;
PCF8563_time --- 分   ;
PCF8563_time --- 小时 ;
PCF8563_time --- 日   ;
PCF8563_time --- 星期 ;
PCF8563_time --- 月   ;
PCF8563_time --- 年   ;
*/
uchar PCF8563_time;   
//uchar c8563_Store={0x00,0x59,0x07,0x01};//== 写入时间初值:星期一07:59:00 ==
uchar Set8563_time={0x00,0x59,0x07,0x0A,0x02,0x07,0x07}; //==写入时间初值:2007年07月星期二 10日 07:59:00 ==
//======================================== 函数声明 ================================================
void InitMain (void);         //=== 系统初始化函数===
void delayX10ms(int count);   //===延迟===   
void Delay();
void Start();
void Stop();
void WriteACK();
void writenoack();
void WaitACK();
void writebyte(uchar wdata);
uchar Readbyte();
void writeData(uchar address,uchar mdata);
uchar ReadData(uchar address);             /*单字节*/
void ReadData1(uchar address,uchar count,uchar * buff);   /*多字节*/
void P8563_Read();
void P8563_gettime();
void P8563_settime();
void P8563_init();               //== 初始化时间 ==
//=================================================================================================
//========================================== 主函数==============================================
//=================================================================================================
void main(void)
{
WDTCTL= WDTPW + WDTHOLD;   //=== Stop watchdog timer===
InitMain ();               //=== 系统初始化函数===
P8563_init();                //== 初始化时间 ==
   _EINT();                     //== Enable interrupts ===   
while (1)
{

       P8563_gettime();
       P1OUT ^= BIT6;         //===P4.0取反输出===
       delayX10ms(50);
       P1OUT ^= BIT7;         //===P4.0取反输出===
       delayX10ms(50);
      
   
}

}

//=============================================================================
//函 数 名: void InitMain (void)
//功 能:系统初始化
//入口参数:NO
//返 回 值:NO
//=============================================================================
//----------------------- 系统初始化函数 ----------------------------
void InitMain (void)
{
    unsigned int i;
    WDTCTL=WDTPW+WDTHOLD; //停止看门狗
    //--- 系统时钟配置 ---
    BCSCTL2 |= SELS;//SMCLK = XT2 -----
                      //MCLK = DCOCLK
    do
    {
      IFG1 &= ~OFIFG;                           // Clear OSCFault flag
      for (i = 0xFF; i > 0; i--);               // Time for flag to set
    }
    while ((IFG1 & OFIFG));                   // OSCFault flag still set?
    BCSCTL2 |= SELM_2 + SELS;               // MCLK = SMCLK = XT2 (safe)
    BCSCTL2 |= DIVM1 + DIVM0;               // MCLK = XT2/8
    //-----PCF8563 INT中断 ----
    P2DIR &= ~BIT0;
    P2DIR &= ~BIT3;
   
    P2DIR |= BIT1;
    P2DIR |= BIT2;
   
    P1DIR = 0xff;
/*
    //--- 4X4按键I/O配置 ---
    P2DIR = 0;      //== 将P2口所有的管脚在初始化的时候设置为输入方式 ==
    P2SEL = 0;      //== 将P2口所有的管脚设置为一般I/O口 ==
    P2DIR |= BIT4;    //== 将P2.4 P2.5 P2.6 P2.7设置为输出方向 ==
    P2DIR |= BIT5;
    P2DIR |= BIT6;
    P2DIR |= BIT7;
    P2OUT = 0xF0;   //== 先输出低电平 ==
    //-----PCF8563 INT中断 ----
    P1DIR = 0x00;
    P1IES = 0Xff;
    P1IE= 0x80;    //列线上升沿允许P1中断
    //--- LED 测试端口 ---
    //P4DIR|= 0x01;             //== Set P4.0 to output direction ==
   //--- 液晶数据线接口 ---
    P5DIR=0xff;         //== 设置IO口的方向为输出 ==
    P4DIR=0xff;         //== 设置IO口的方向为输出 ==
*/
}

//=============================================================================
//函 数 名: delayX10ms(int count)
//功 能:延时子函数
//入口参数:int count
//返 回 值:NO
//=============================================================================
void delayX10ms(int count)   //===延迟===
{
unsigned int i,j,k;
for (i=0; i<count; i++)
for(j=0; j<10; j++)
    for(k=0; k<120; k++);
}      

//===================================================================
//=============内部函数,延时1 ====================================
//===================================================================
void Delay()
{
   int i ;                        //== IIC的读写速度小于400KHz ==
    for(i=0;i<20;i++);            //== 根据晶振频率制定延时时间 ==
}                                 //== 此程序采用 8MHz 系统时钟 ==
//===================================================================
//=============内部函数,I2C开始=================================
//===================================================================
void Start()
{   
   SDA1 ;
   SCL1 ;
   Delay();
   SDA0 ;
   Delay();
   SCL0 ;
}

//===================================================================
//=============   内部函数,I2C结束   ===============================
//===================================================================
void Stop()
{
    SDA0 ;
    SCL0 ;
    Delay();
    SCL1 ;
    Delay();
    SDA1 ;
    Delay();
   
}

//===================================================================
//=============   内部函数,输出ACK=0    ============================
//===================================================================
void WriteACK()
{
    SDA0 ;
    Delay();
    SCL1 ;
    Delay();
    SCL0 ;
}

//===================================================================
//=============   内部函数,输出ACK=1    ============================
//===================================================================
void writenoack()
{
    SDA1 ;
    Delay();
    SCL1 ;
    Delay();
    SCL0 ;
}

//===================================================================
//=============   内部函数,等待ACK================================
//===================================================================
void WaitACK()
{
   uchar errtime = 0 ;
    SDA1 ;
    Delay();               //== 读ACK ==
    SCL1 ;
    Delay();
    DIR_IN;
    while((SDA_IN == 0x01)&(errtime<=50))//== 防止读取信号出现死循环==
    {
   errtime++;
       if(errtime==50)
       {
      Stop();
      }
    }
    errtime = 0 ;
    DIR_OUT;
    SCL0 ;
    Delay();
   
}
//===================================================================
//=============内部函数.输出数据字节 ==============================
//===================================================================
void writebyte(uchar wdata)
{
    uchar i;
    for(i=0;i<8;i++)
    {
      if(wdata&0x80) SDA1 ;
          else SDA0 ;
          wdata<<=1;
          SCL1 ;
          Delay();
          SCL0 ;
    }
    WaitACK();
}

//===================================================================
//=============   内部函数.输入数据================================
//===================================================================
uchar Readbyte()
{
    uchar i,bytedata;
    SDA1 ;
    DIR_IN ;
    for(i=0;i<8;i++)
    {
      SCL1 ;
      bytedata<<=1;
      bytedata|=SDA_IN;
      SCL0 ;
      Delay();
    }
    DIR_OUT ;
    return(bytedata);
}

//===================================================================
//=============   输出数据->pcf8563================================
//===================================================================
void writeData(uchar address,uchar mdata)
{
    Start();
    writebyte(0xa2);          //== 写命令 ==
    writebyte(address);       //== 写地址 ==
    writebyte(mdata);         //== 写数据 ==
    Stop();
}

//===================================================================
//=============   输入数据<-pcf8563   ===============================
//===================================================================
uchar ReadData(uchar address)    //== 单字节 ==
{   uchar rdata;
    Start();
    writebyte(0xa2);             //== 写命令 ==
    writebyte(address);          //== 写地址 ==
    Start();
    writebyte(0xa3);             //== 读命令 ==
    rdata=Readbyte();
    writenoack();
    Stop();
    return(rdata);
}
void ReadData1(uchar address,uchar count,uchar * buff) //== 多字节 ==
{   uchar i;
    Start();
    writebyte(0xa2);             //== 写命令 ==
    writebyte(address);          //== 写地址 ==
    Start();
    writebyte(0xa3);             //== 读命令 ==
    for(i=0;i<count;i++)
    {
      buff=Readbyte();
      if(i<count-1) WriteACK();
    }
    writenoack();
    Stop();
}

//===================================================================
//=============   内部函数,读入时间到内部缓冲区====================
//===================================================================
void P8563_Read()
{   uchartime;
    ReadData1(0x02,0x07,time);
    //g8563_Store=time&0x7f;      //== 秒 ==
    //g8563_Store=time&0x7f;      //== 分 ==
    //g8563_Store=time&0x3f;      //== 小时 ==
    //g8563_Store=time&0x07;      //== 星期 ==
   
    PCF8563_time=time&0x7f;      //== 秒 ==
    PCF8563_time=time&0x7f;      //== 分 ==
    PCF8563_time=time&0x3f;      //== 小时 ==
    PCF8563_time=time&0x7f;      //== 日 ==
    PCF8563_time=time&0x07;      //== 星期 ==
    PCF8563_time=time&0x7f;      //== 月 ==
    PCF8563_time=time&0x7f;      //== 年 ==
   
   
}

//===================================================================
//=============   读入时间到内部缓冲区----外部调用   ================
//===================================================================
void P8563_gettime()
{
    P8563_Read();
    if(g8563_Store==0)
      P8563_Read();      //== 如果为秒=0,为防止时间变化,再读一次 ==
}

//===================================================================
//=============   写时间修改值=====================================
//===================================================================
void P8563_settime()
{
   uchar i;
   //for(i=2;i<=4;i++) {writeData(i,g8563_Store); }
   //writeData(6,g8563_Store);
   for(i=2;i<=8;i++)
   writeData(i, PCF8563_time);
}
//===================================================================
//==================== 初始化时间 ===================================
//===================================================================
void P8563_init()
{
uchar i;
// if((ReadData(0xa)&0x3f)!=0x8)                        
//== 检查是否第一次启动,是则初始化时间 ==
//{
      for(i=0;i<=6;i++)PCF8563_time=Set8563_time; //== 初始化时间 ==
      P8563_settime();
      writeData(0x0,0x00);                               //== control1=0x00 ==
      writeData(0x9,0x00);                              //== 0分 报警 ==
      //writeData(0xa,0x8);                           //== 8:00报警 ==
      writeData(0x1,0x12);                              //== control2 报警有效 ==
      //writeData(0xd,0xf0);                            //== 频率输出 ==
   //}
}

//=============================================================================
//端口1中断函数
//多中断中断源:P1IFG.0~P1IFG7
//进入中断后应首先判断中断源,退出中断前应清除中断标志,否则将再次引发中断
//=============================================================================
#pragma vector=PORT1_VECTOR
__interrupt void Port1()
{
//== 以下为参考处理程序,不使用的端口应当删除其对于中断源的判断 ==
if((P1IFG&BIT7) ==BIT7)//== 处理P1IN.7中断 ==
{
    P1IFG &= ~BIT7; //== 清除中断标志 ==
    //以下填充用户代码
    writeData(0x1,0x12);      //== 清除分中断标志位 令AF=0==
    P4OUT ^= 0x01;         //== P4.0取反输出===
   
   
}
}

lvyunzeng 发表于 2012-2-22 15:17:32

看看吧,我自己改的程序。项目中使用的,当时独立调试的程序段,完全可以用。希望对你有帮助!

zyn10101010 发表于 2012-2-22 15:35:09

谢谢,时间是可以读出来的,就是有时会不能设置时间,
对了下你的程序,跟你的差不多。
因为产品已经投产了,不方便再全部跟换驱动程序了。

要是能大概知道哪些情况会引起这种现象,就能更方便找出问题。

womenhome 发表于 2012-2-22 15:38:28

没用过这个片子,但是用过很多RTC片子。

一般寄存器会有个有个WP的位,写保护的。

软件上一般会这么处理:

初次上电时候,关闭写保护,然后写正确时间,然后往芯片自带的RAM里面写一个值。然后打开写保护。

以后上电时,会读这个RAM的值,如果是以前写进去的,说明没有掉电,时间也没有丢。就不会打开写保护,所以不能写。
如果掉电了,RAM的值被清零,所以软件判断掉电了,会关闭写保护,就可以写时间了。

所以你说拔掉电池,就可以写,应该就这样的。



估计是写保护被打开了。

zyn10101010 发表于 2012-2-22 17:13:27

回复【4楼】womenhome
-----------------------------------------------------------------------

谢谢,我又翻了一遍PCF8563的芯片手册,里面没有提到也没有跟写保护相关的寄存器。

chenlong0108 发表于 2012-2-22 18:27:09

我记得似乎电压低的时候是只读的

zyn10101010 发表于 2012-2-22 18:40:17

回复【6楼】chenlong0108
-----------------------------------------------------------------------

不是电压低的问题,
因为PCF8563的供电电压是由7V+降压下来的,也量过PCF8563的供电脚(3V),
另外,同一块电池,假如出现不能设置时间的问题,就一直是这样子,
除非复位PCF8563(切断后备电池)才能再次设置时间。
假如是电压低,那么同一块电池,也应该是一直不能设置才对。

xiaojian 发表于 2012-2-22 18:49:05

IIC 的速度问题,一楼那里有注明,小于400k,楼主看看你的程序延时吧,我估计又是延时时间不够,超过了400k

zyn10101010 发表于 2012-2-23 08:53:29

回复【8楼】xiaojian
-----------------------------------------------------------------------

谢谢,我会检查通信速率是否小于400。
只是 不能设置时间的情况 也是偶尔出来,
可能需要几天的测试,才能确认。
页: [1]
查看完整版本: PCF8563 能读时间,不能设置时间