代码
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[i] = 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[i];
Write(base_addr + i, dat);
}
}
//----------------------------------------------------------------------------
void Time_Adjust(uchar *buff) //时间调整,去除不必要的位,固定处理7字节
{
buff[0] &= 0x7F; //调整秒
buff[1] &= 0x7F; //调整分
buff[2] &= 0x3F; //调整时
buff[3] &= 0x3F; //调整日
buff[4] &= 0x07; //调整周
buff[5] &= 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[i] = 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[i]);
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 uint unsigned int
#define SCL P0_1 //时钟
#define SDA 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_0 P3_0=0 //_pc5
#define LCD_SCL_1 P3_0=1 //_pc5
#define LCD_SDA_0 P3_6=0
#define LCD_SDA_1 P3_6=1
#define LCD_RST_0 P3_4=0 // _pc3
#define LCD_RST_1 P3_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[10];
/***************************************************************************************
* @实现效果 设置各个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[0]>>4)+0x30;
ge=(buff[0]&0x0f)+0x30;
LCD_P8x16Char(68,6,shi);
LCD_P8x16Char(76,6,ge);
for(k=0;k<20000;k++);
}
}
请问高手,哪里有错?谢谢
|