BB101 发表于 2009-11-15 16:24:58

[求助]PC8563驱动求教

马老师:
   你好,最近在搞PCF8563的驱动,但不能把芯片驱动起来,程序是参考网上的资料略微修改的。程序看起来也都可以解释得通,但我对8563的读与写都好像没反应。我对时钟芯片初始化,然后再读出里面的数据放eeprom,发现根本没有写入或没有读出。现把这一块贴出来,希望马老师有时间帮忙看看,谢谢!

希望解决问题:能对时钟芯片写入初值,然后能读出来。

http://cache.amobbs.com/bbs_upload782111/files_22/ourdev_503443.JPG
(原文件名:时钟电路.JPG)

MCU:m48
#define SDA          PORTB.1
#define SCL          PORTB.0

//8563.c

uchar TAB_T={0x55,0x30,0x20,//秒,分,时
0x13,0x01,0x07,0x08};//日,星期,月,年.

uchar *pTime=TAB_T;

eeprom char t0; //测试用
eeprom char t1;
eeprom char t2;
eeprom char t3;
eeprom char t4;
eeprom char t5;
eeprom char t6;


//起动后数据线与时钟线均为低电平,准备接收数据
void Start(void)   
{
    SDA=1;   //数据线为高电平;
    SCL=1;   //时钟线为高电平;
    delay_us(5);
    SDA=0;   //SDA=1 --> SDA=0,在数据线下降沿起动
    delay_us(5);
    SCL=0;
}

//结束后数据线与时钟线均为高电平,准备下一次的起动
void Stop(void)
{
    SDA=0;    //数据线为低电平
    SCL=1;    //时钟线为高电平
    delay_us(5);
    SDA=1;    //SDA=0 --> SDA=1,在数据线上升沿结束
    delay_us(5);
}

//怀疑是此处出问题,但以下这样写:等待SDA=0好像也可以。
void Reack(void)
{
    uchar i=0;
    SCL=1; //准备检测SDA
    delay_us(5);
    while((SDA==1)&&(i<100))i++;//SDA=0为应答信号,SDA=1为非应答
    SCL=0; //准备下一变化数据
}


void WriteByte(uchar ucByte)
{
    uchar i;
    SCL=0;
    for(i=0;i<8;i++)
    {
      if(ucByte&0x80)   //先写入高位
            SDA=1;
      else SDA=0;   
      SCL=1;
      delay_us(5);
      SCL=0;
      ucByte<<=1;
    }
    SDA=1; //释放数据线
}


uchar ReadByte(void)
{
    uchar i,ucByte=0;
    SCL=0;
    for(i=0;i<8;i++)
    {
      ucByte<<=1;
      if(SDA) ucByte++;
      SCL=1;
      delay_us(5);
      SCL=0;
    }
    return ucByte;
}




void Write8563(uchar ucAddr,uchar ucData)
{
    Start();
    WriteByte(0xa2);
    Reack();
    WriteByte(ucAddr);
    Reack();
    WriteByte(ucData);
    Reack();
    Stop();
}

uchar Read8563(uchar ucAddr)
{
    uchar ucData;
    Start();
    WriteByte(0xa2); //写器件地址
    Reack();
    WriteByte(ucAddr); //写字节地址
    Reack();
    Start();
    WriteByte(0xa3); //写器件地址,最低为1表示读
    Reack();
    ucData=ReadByte(); //写字节地址
    Stop();
    return ucData; //读数据
}



void Init8563(void)
{
    uchar i,ucAddr=0x02;
    Write8563(0x00,0x20);
    for(i=0;i<7;i++)
    {
      Write8563(ucAddr,TAB_T);
      ucAddr++;
    }
    Write8563(0x00,0x00);
    Write8563(0x01,0x11);
}


void GetTime(void)
{
    uchar i,ucData1,ucData2,ucAddr=0x02;
    for(i=0;i<7;i++)
    {
      pTime=Read8563(ucAddr);
      ucAddr++;      
    }
    pTime&=0x7f; //屏蔽无效位
    pTime&=0x7f;
    pTime&=0x3f;
    pTime&=0x3f;
    pTime&=0x07;
    pTime&=0x1f;
    for(i=0;i<7;i++)
    {
      ucData1=pTime/16; //BCD码转十六进制
      ucData2=pTime%16;
      pTime=ucData1*10+ucData2;
    }
}

//main.c

#include <mega48.h>
#include <delay.h>
#include "8563.c"

void main(void)
{

// Crystal Oscillator division factor: 8
//熔丝位为8M内部振荡源,8分频后得1M系统时钟
#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

PORTB=0x03;
DDRB=0x03;

Init8563();
GetTime();    //读出时间值,并送到eeprom保存起来
t0=pTime;//7f t0-t6读出的值与GetTime()里相与的值相同,证时没有写入或者没有读出.
t1=pTime;//7f
t2=pTime;//3f
t3=pTime;//3f
t4=pTime;//07
t5=pTime;//1f
t6=pTime;//ff

while (1);
}

BB101 发表于 2009-11-16 11:29:19

从PCF8563资料上有这么一句话:
从接收器必须在接收到每个字节后产生一个标志位,主接收器也必须在接收从传送器传送的每个字节后产生一个标志位。在标志位时钟脉冲出现时,SDA 线应保持低电平(应考虑起动和保持时间)。传送器应在从设备接收最后一个字节时变为低电平,使接收器产生标志位,这时主设备可产生停止条件。

是否可以这样理解。单片机送完一个字节后,把SDA的输出方式转为输入方式,等待时钟芯片的应答信号。当应答信号来了(SDA=1),那么再次把SDA转为输出方式,再出一个SDA=0的标志位,再进行第二个字节的传送。

不知道上面的理解对不对!?

BB101 发表于 2009-11-19 15:28:38

问题的确是在应答这里。
如果以后有朋友用AVR进行IIC,在发一个字节后必须把SDA转换成输入口。然后等待从机的应答。
当然。。能用AVR的TWI还是用TWI好搞些。
由于某种原因,我没用TWI。
页: [1]
查看完整版本: [求助]PC8563驱动求教