[求助]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);
} 从PCF8563资料上有这么一句话:
从接收器必须在接收到每个字节后产生一个标志位,主接收器也必须在接收从传送器传送的每个字节后产生一个标志位。在标志位时钟脉冲出现时,SDA 线应保持低电平(应考虑起动和保持时间)。传送器应在从设备接收最后一个字节时变为低电平,使接收器产生标志位,这时主设备可产生停止条件。
是否可以这样理解。单片机送完一个字节后,把SDA的输出方式转为输入方式,等待时钟芯片的应答信号。当应答信号来了(SDA=1),那么再次把SDA转为输出方式,再出一个SDA=0的标志位,再进行第二个字节的传送。
不知道上面的理解对不对!? 问题的确是在应答这里。
如果以后有朋友用AVR进行IIC,在发一个字节后必须把SDA转换成输入口。然后等待从机的应答。
当然。。能用AVR的TWI还是用TWI好搞些。
由于某种原因,我没用TWI。
页:
[1]