- #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++);
- }
- }
请问高手,哪里有错?谢谢