HC89S105AC8读写PCF8563不正常
代码PCF8563.C
#include "HC89S105AC8.h"
#include "PCF8563.h"
void _nop1_(void)
{
int i;
for(i=0;i<5;i++);
}
//----------------------------------------------------------------------------
void PCF8563_INIT()//初始化
{
Delay8ms(); //IIC总线从通电到开始操作要求8ms延时
Register_INIT(); //寄存器初始化
Time_INIT(); //时间初始化
}
//----------------------------------------------------------------------------
void Register_INIT()//寄存器初始化
{
CS1_Set(); //设置控制/状态寄存器1
CS2_Set(); //设置控制/状态寄存器1
DayA_Set(); //设置天闹铃寄存器
WeekdayA_Set(); //设置周闹铃寄存器
CO_Set(); //设置时钟输出寄存器
}
//----------------------------------------------------------------------------
void CS1_Set(){ Write(CS1, 0x00);}//CS1:寄存器地址,0x00:全部设为正常模式
void CS2_Set(){ Write(CS2, 0x02);}//0x02:开闹铃中断,关定时器中断
void DayA_Set(){ Write(DayA, 0x00);} //关天闹铃
void WeekdayA_Set(){ Write(WeekdayA, 0x00);}//关周闹铃
void CO_Set(){Write(CO, 0x00);} //关时钟输出
//----------------------------------------------------------------------------
void Time_INIT()//时间初始化,2015-05-01 Fri 12:30:00,压缩型BCD码格式
{
Write(Year, 0x23);
Write(Month, 0x12);//最高位表示世纪:0-20xx,1-19xx
Write(Weekday, 0x31);//周不会自动生成,需要自己确认并写入
Write(Day, 0x07);
Write(Hour, 0x23);
Write(Minute, 0x59);
Write(Second, 0x50);
}
//----------------------------------------------------------------------------
uchar Sec_Read()
{
uchar sec = Read(Second);
sec &= 0x7F;
return sec;
}
//----------------------------------------------------------------------------
/*void Time_Read(uchar *buff)//采用多字节连续读取方式,功能与下面函数一样,但两个只能存在一个
{
Read_Sequence(Second, 7, buff);//从sec单元开始,连续读取7字节,分别为:sec min hour day weekday month year
Time_Adjust(buff);
}*/
//----------------------------------------------------------------------------
void Time_Read(uchar *buff)//采用单字节读取方式,每次读取1字节,分多次读取,功能与上面函数一样,但两个只能存在一个
{
uchar base_addr = Second;
uchar i, dat;
for (i=0; i<7; i++)
{
dat = Read(base_addr + i);
buff = dat;
}
Time_Adjust(buff);
}
//----------------------------------------------------------------------------
/*void Time_Write(uchar *buff)//采用多字节连续读取方式,功能与下面函数一样,但两个只能存在一个
{ //时间写入,将缓冲区buff内的sec min hour day weekday month year写入PCF8563
Write_Sequence(Second, 7, buff);
}*/
//----------------------------------------------------------------------------
void Time_Write(uchar *buff)//采用单字节写入方式,每次写入1字节,分多次写入,功能与上面函数一样,但两个只能存在一个
{ //时间写入,将缓冲区buff内的sec min hour day weekday month year写入PCF8563
uchar base_addr = Second;
uchar i, dat;
for (i=0; i<7; i++)
{
dat = buff;
Write(base_addr + i, dat);
}
}
//----------------------------------------------------------------------------
void Time_Adjust(uchar *buff)//时间调整,去除不必要的位,固定处理7字节
{
buff &= 0x7F;//调整秒
buff &= 0x7F;//调整分
buff &= 0x3F;//调整时
buff &= 0x3F;//调整日
buff &= 0x07;//调整周
buff &= 0x1F;//调整月,年不用调整
}
//----------------------------------------------------------------------------
void Alarm_Read(uchar *buff)//闹钟时间读取,只开启了时,分闹铃
{
Read_Sequence(MinuteA, 2, buff);//从MinuteA单元开始,连续读取2字节,分别为分,时的闹钟时间值
}
//----------------------------------------------------------------------------
void Alarm_Stop()//停止闹铃
{
uchar dat = Read(CS2);//读取当前控制/状态寄存器2的值
dat &= 0xF7; //清AF闹铃标志,AF在CS2第3位
Write(CS2, dat);
}
//----------------------------------------------------------------------------
void Write(uchar RegAddr, uchar dat)//向目标寄存器写入1字节数据
{
Start(); //开始信号
Write_8bits(PCF8563_WRITE); //IIC写入8位,将写操作指令写入
Acknowledge();
Write_8bits(RegAddr); //写入目标写入寄存器的地址
Acknowledge();
Write_8bits(dat); //将数值写入
Acknowledge();
Stop(); //停止信号
}
//----------------------------------------------------------------------------
uchar Read(uchar RegAddr)//字节读取
{
uchar dat;
Start();
Write_8bits(PCF8563_WRITE); //IIC写入8位,将写操作指令写入
Acknowledge();
Write_8bits(RegAddr); //写入目标读取寄存器的地址
Acknowledge();
Start();
Write_8bits(PCF8563_READ); //IIC写入8位,将读操作指令写入
Acknowledge();
dat = Read_8bits(); //读取数据1字节
MasterNoACK();
Stop();
return dat;
}
//----------------------------------------------------------------------------
void Read_Sequence(uchar RegAddr, uchar n, uchar *buff)//连续读取多字节,n<=16(pdf:P15of30fig14)
{
uchar i;
Start();
Write_8bits(PCF8563_WRITE);
Acknowledge();
Write_8bits(RegAddr); //写入目标读取寄存器的地址
Acknowledge();
Start();
Write_8bits(PCF8563_READ); //IIC写入8位,将读操作指令写入
Acknowledge();
for (i=0; i<n; i++)
{
buff = Read_8bits();
if (i!=n-1) //除最后一个字节外,主机需给从机ACK
MasterACK();
else
MasterNoACK(); //最后一个字节读取完毕,主机需给从机NoACK,再给stop信号
}
Stop();
}
//----------------------------------------------------------------------------
void Write_Sequence(uchar RegAddr, uchar n, uchar *buff)//连续写入多字节(pdf:P15of30fig13)
{
uchar i;
Start();
Write_8bits(PCF8563_WRITE);
Acknowledge();
Write_8bits(RegAddr);
Acknowledge();
for (i=0; i<n; i++)
{
Write_8bits(buff);
Acknowledge();
}
Stop();
}
//----------------------------------------------------------------------------
void Write_8bits(uchar dat)//写入8位
{
uchar i, m = 0x80;
for (i=0; i<8; i++)
{
SCL = 0; //在SCL低电平期间将数据送上SDA
_nop1_();
SDA = (dat&m)==0?0:1;
_nop1_();
SCL = 1;
_nop1_();
_nop1_();
m /= 2;
}
SCL = 0;
}
//----------------------------------------------------------------------------
uchar Read_8bits()//读取8位
{
uchar i, dat=0;
P0M0=0X0E;
for(i=0;i<10;i++);
for (i=0; i<8; i++)
{
SCL = 0;
_nop1_();
SCL = 1;//SCL高电平时,读取SDA数据
_nop1_();
_nop1_();
dat *= 2;
dat += (SDA==1?1:0);
}
SCL = 0;
P0M0=0XAA;
for(i=0;i<10;i++);
return dat;
}
//----------------------------------------------------------------------------
void Start()
{
SDA = 1;
SCL = 1;
_nop1_();
_nop1_();
SDA = 0;
_nop1_();
SCL = 0;
}
//----------------------------------------------------------------------------
void Stop()
{
_nop1_();
SDA = 0;
SCL = 1;
_nop1_();
SDA = 1;
}
//----------------------------------------------------------------------------
void Acknowledge()//从机应答查询
{
uchar i;
_nop1_();
SDA = 1; //要查询应答信号,要先释放总线
SCL = 1;
_nop1_();
_nop1_();
P0M0=0X0E;
for(i=0;i<10;i++);
while(SDA==1){}; //对方以拉低SDA来表示应答
SCL = 0;
P0M0=0XAA;
for(i=0;i<10;i++);
}
//----------------------------------------------------------------------------
void MasterACK()//主机应答,见 PCF8563 pdf p14 fig.11
{
_nop1_();
SDA = 0;
_nop1_();
SCL = 1;
_nop1_();
_nop1_();
SCL = 0;
SDA = 1;
}
//----------------------------------------------------------------------------
void MasterNoACK()//主机无应答,见 PCF8563 pdf p14 fig.11
{
_nop1_();
SDA = 1;
_nop1_();
SCL = 1;
_nop1_();
_nop1_();
SCL = 0;
SDA = 1;
}
//----------------------------------------------------------------------------
void Delay8ms()
{
uint i;
for (i=0; i<20000; i++);//实际器件1000可运行,Proteus仿真是否太严格要求时间达标?
}
//----------------------------------------------------------------------------
PCF8563.H
#define uchar unsigned char
#define uintunsigned int
#define SCL P0_1//时钟
#defineSDA P0_0 //数据
//PCF8563内部寄存器地址
#define CS1 0x00 //控制/状态寄存器1
#define CS2 0x01 //控制/状态寄存器2
#define Second 0x02 //秒寄存器
#define Minute 0x03 //分寄存器
#define Hour 0x04 //时寄存器
#define Day 0x05 //天寄存器
#define Weekday 0x06 //周寄存器
#define Month 0x07 //月寄存器
#define Year 0x08 //年寄存器
#define MinuteA 0x09 //分闹铃寄存器
#define HourA 0x0A //时闹铃寄存器
#define DayA 0x0B //天闹铃寄存器
#define WeekdayA 0x0C //周闹铃寄存器
#define CO 0x0D //时钟输出控制寄存器
#define TimerCtrl 0x0E //定时控制寄存器
#define Timer 0x0F //定时设置寄存器
#define PCF8563_WRITE 0xA2 //写指令
#define PCF8563_READ 0xA3 //读指令
//----------------------------------------------------------------------------
void PCF8563_INIT(); //初始化
void Register_INIT();//寄存器初始化
void CS1_Set();
void CS2_Set();
void DayA_Set();
void WeekdayA_Set();
void CO_Set();
void Time_INIT();
uchar Sec_Read();
void Time_Read(uchar *buff);
void Time_Write(uchar *buff);
void Alarm_Read(uchar *buff);
void Time_Adjust(uchar *buff);
void Alarm_Stop();
void Write(uchar RegAddr, uchar dat);
uchar Read(uchar RegAddr);
void Read_Sequence(uchar RegAddr, uchar n, uchar *buff);
void Write_Sequence(uchar RegAddr, uchar n, uchar *buff);
void Write_8bits(uchar dat);
uchar Read_8bits();
void Start();
void Stop();
void Acknowledge();
void MasterACK();
void MasterNoACK();
void Delay8ms();
//----------------------------------------------------------------------------
主程序
#define ALLOCATE_EXTERN
#include "HC89S105AC8.h"
#include "OLED.h"
#include "pcf8563.h"
#define LCD_SCL_0P3_0=0 //_pc5
#define LCD_SCL_1P3_0=1 //_pc5
#define LCD_SDA_0P3_6=0
#define LCD_SDA_1P3_6=1
#define LCD_RST_0P3_4=0//_pc3
#define LCD_RST_1P3_4=1//_pc3
#define LCD_DC_0 P3_2=0
#define LCD_DC_1 P3_2=1
#define XLevelL 0x00
#define XLevelH 0x10
#define XLevel ((XLevelH&0x0F)*16+XLevelL)
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xCF
#define X_WIDTH 128
#define Y_WIDTH 64
unsigned char i,j;
uchar buff;
/***************************************************************************************
* @实现效果 设置各个IO口的工作状态
***************************************************************************************/
void main(void)
{
int k;
unsigned char shi,ge;
/********************************系统初始化*******************************************/
WDTCCR = 0x00; //关闭看门狗
//本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
CLKCON = 0x02; //选择内部高频RC为系统时钟, Fosc=32MHz
CLKDIV = 0x02; //Fosc 2分频得到Fcpu,Fcpu=16MHz
/***********************************设置IO口模式***************************************/
//P0M0=0XAA; //开漏带上拉输出
LCD_Init();
LCD_CLS();
LCD_P8x16Str(20,4,(u8*)"20--");
LCD_P8x16Str(20,6,(u8*)"::");
PCF8563_INIT();
//LCD_Rectangle(0,0,10,10,0);
//LCD_P8x16Str(10,10,'0');
while(1)
{
// SCL=0;
// SDA=0;
// for(k=0;k<2000;k++);
// SCL=1;
// SDA=1;
// for(k=0;k<2000;k++);
Time_Read(buff);
shi=(buff>>4)+0x30;
ge=(buff&0x0f)+0x30;
LCD_P8x16Char(68,6,shi);
LCD_P8x16Char(76,6,ge);
for(k=0;k<20000;k++);
}
}
请问高手,哪里有错?谢谢
检查是否有连接不良或短路的情况。 调整I2C总线时序 用示波器检查是否存在时序错误或数据错误。 起始条件、停止条件、数据位发送和接收的时序是否正确。 检查HC89S105AC8的读写代码是否正确实现了I2C通信协议。 既然是I2C,建议你严重关注时钟周期。逻辑本身没问题的话,时钟频率会是最可能的因素。 你可以先用能正常访问的,用示波器、逻辑分析仪、或者自制简单的计数器,获得SCL的周期;然后对比不正常,看看差多少。
页:
[1]