单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:40273|回复:5
打印上一主题下一主题

PCF8563实时时钟芯片51单片机简单例程

 [复制链接]
跳转到指定楼层
楼主
ID:70941发表于 2015-1-23 04:34|只看该作者回帖奖励
做时钟显示如果用单片机做,会产生很大的累积误差,本程序采用时钟芯片PCF8563

一:芯片主要电气特性:
1)大工作电压范围:1.0~5.5V
2)400KHz 的 I2C 总线接口(VDD=1.8~5.5V 时)。


时钟频率最大400KH

3)i2C 总线从地址:读,0A3H;写,0A2H .

二:管脚



电路接线图:


单片机和PCF8563通信采用IIC协议,单片机读取时钟芯片内寄存器数据或者时钟芯片输出时间信息给单片机.
本程序知识简单的显示时间,也没有加入芯片损坏延时判断应答子函数.,只是了解芯片使用方法

IIC总线和LCD1602函数包属于标准代码。

IIC协议子函数包

#include< reg52.h>
#include< intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit SDA=P2^2;   //SDA口设置
sbit SCL=P2^3;   //SCL口设置


void delay()   //略微延时  6us约>4.7us
{
_nop_();
   _nop_();
   _nop_();
   _nop_();
       _nop_();
       _nop_();
}

void iic_start()   //启动信号
{
   SDA=1;
   SCL=1;
   delay();
   SDA=0;
   delay();
   SCL=0;

}

void iic_stop()  //停止信号
{
SDA=0;
SCL=1;
delay();
SDA=1;
delay();
SCL=0;
}

void iic_ack()   //应答信号
{
uchar i=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
i++;
SCL=0;
delay();
}

void iic_send_byte(uchar bat)  //发送数据
{
uchar i,temp;
temp=bat;
for(i=0;i<=7;i++)
{
   temp=temp<<1;
   SCL=0;
   SDA=CY;
   delay();
   SCL=1;
   delay();
}
SCL=0;
delay();
SDA=1;
delay();
}

uchar iic_rev()  //接受数据
{
   uchar temp,i;
   SCL=0;
   delay();
   SDA=1;
   for(i=0;i<=7;i++)
   {
   SCL=1;
   delay();
   temp=(temp<<1)|SDA;
   SCL=0;
   delay();
   }
   delay();
   return temp;
}

void iic_send_add_byte(uchar add,uchar bat) //向某个地址发送某数据
{
iic_start();
iic_send_byte(0xa2);
iic_ack();
iic_send_byte(add);
iic_ack();
iic_send_byte(bat);
iic_ack();
iic_stop();
}

uchar iic_rec_add_byte(uchar add) //从某个地址读出数据
{
   uchar temp;
   iic_start();
   iic_send_byte(0xa2);
   iic_ack();
   iic_send_byte(add);
   iic_ack();
   iic_start();
   iic_send_byte(0xa3);
   iic_ack();
   temp=iic_rev();
   iic_stop();
   return temp;
}


LCD1602函数包:

**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;


void Delay1us(uint a)
{    
uint b,c;
for(c=a;c>0;c--)        
for(b=110;b>0;b--);
}

void LCD1602_WriteCom(uchar com)       //写入命令
{
     LCD1602_E=0;
     LCD1602_RS=0;
     LCD1602_RW=0;
     LCD1602_DATAPINS=com;     //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
     Delay1us(10);
     LCD1602_E=1;
     Delay1us(10);
     LCD1602_E=0;
     Delay1us(10);
     LCD1602_DATAPINS=com<<4;
     Delay1us(10);
     LCD1602_E=1;
     Delay1us(10);
     LCD1602_E=0;
}

void LCD1602_WriteData(uchar dat)             //写入数据
{
     LCD1602_E=0;
     LCD1602_RS=1;
     LCD1602_RW=0;
     LCD1602_DATAPINS=dat;     //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
     Delay1us(10);
     LCD1602_E=1;
     Delay1us(10);
     LCD1602_E=0;
     LCD1602_DATAPINS=dat<<4;
     Delay1us(10);
     LCD1602_E=1;
     Delay1us(10);
     LCD1602_E=0;
}

void LCD1602_Init()                           //LCD初始化子程序
{
     LCD1602_WriteCom(0x32);       //将8位总线转为4位总线
     LCD1602_WriteCom(0x28);       //在四位线下的初始化
     LCD1602_WriteCom(0x0c);  //开显示不显示光标
     LCD1602_WriteCom(0x06);  //写一个指针加1
     LCD1602_WriteCom(0x01);  //清屏
     LCD1602_WriteCom(0x80);  //设置数据指针起点
}

//----- 主函数---------
#include< reg52.h>
#include "lcd.h"
#include "iic.h"

//-----------延时用于稳定-------------
void delay_kk(uint k)
{
   while(k--);
}

//------------------------------BCD码讲解---
比如十六进制数0x56  如果代表BCD码,则其就是代表10进制的56  但是在计算机里面如果用于计算他就是86(十进制),所以后面例出BCD转10进制子函数   PCF8563显示的数都是BCD码


//-----------时间预设定值---------
void time_init()
{
   iic_send_add_byte(0x02,0x50);       //0秒
     iic_send_add_byte(0x03,0x59);       //0分钟  
   iic_send_add_byte(0x04,0x23);       //0小时        
       iic_send_add_byte(0x05,0x26);  //26号
       iic_send_add_byte(0x07,0x05);       //5月  20世纪的
       iic_send_add_byte(0x08,0x14);       //2014年
}



//----------------PCF8563初始化-----------------
void pcf_init()
{
     iic_send_add_byte(0x00,0x00);  //启动时钟
}

//----------------BCD转10进制-----------
uchar bcd_dec(uchar bat)
{
uchar temp1,temp2,tol;
temp1=bat&0x0f;
temp2=(bat&0xf0)>>4;
tol=temp2*10+temp1;
return tol;
}

//------------LCD1602显示:年,月,日,小时,分钟,秒,
void display_time(uchar sec,min,hour,dat,moom,year)
{
   LCD1602_WriteCom(0x80);
   LCD1602_WriteData('_');
LCD1602_WriteData('2');
LCD1602_WriteData('0');
LCD1602_WriteData(year/10+48);
LCD1602_WriteData(year%10+48);
LCD1602_WriteData('/');
LCD1602_WriteData(moom+48);
LCD1602_WriteData('/');
LCD1602_WriteData(dat/10+48);
LCD1602_WriteData(dat%10+48);
   LCD1602_WriteCom(0xc4);
   LCD1602_WriteData(hour/10+48);
   LCD1602_WriteData(hour%10+48);
LCD1602_WriteData(':');
LCD1602_WriteData(min/10+48);
LCD1602_WriteData(min%10+48);
LCD1602_WriteData(':');
LCD1602_WriteData(sec/10+48);
LCD1602_WriteData(sec%10+48);
}

void main()
{
   uchar sec,min,hour,dat,moom,year,sec1,min1,hour1,dat1,moom1,year1;  //PCF8563读出的变量和代转换成的十进制变量
   LCD1602_Init();
   iic_send_add_byte(0x00,0x20);  // 关闭时钟
   delay_kk(1000);
       time_init();   //时钟芯片初始时间设置
       pcf_init();
   delay_kk(1000);
   while(1)
   {
         sec=0x7f&iic_rec_add_byte(0x02);   //读取秒
       min=0x7f&iic_rec_add_byte(0x03);   //读取分钟
       hour=0x3f&iic_rec_add_byte(0x04);  //读取小时
       dat=0x3f&iic_rec_add_byte(0x05);   //读取天数
       moom=0x1f&iic_rec_add_byte(0x07);  //读取月
       year=0xff&iic_rec_add_byte(0x08);   //读取年
       sec1=bcd_dec(sec);             //将读取的BCD码秒转换成十进制秒以便运算
       min1=bcd_dec(min);
       hour1=bcd_dec(hour);
       dat1=bcd_dec(dat);
       moom1=bcd_dec(moom);
       year1=bcd_dec(year);
       display_time(sec1,min1,hour1,dat1,moom1,year1);   //LCD1602显示时间
   }                      
}












沙发
ID:110935发表于 2016-6-14 22:56|只看该作者
没得调时钟吗?
调时钟时光标如何设置走动
板凳
ID:574155发表于 2019-6-28 15:34|只看该作者
感谢楼主分享
地板
ID:190832发表于 2019-6-29 10:09|只看该作者
8563一点都不好用。如果用到PCF8563的中断的话建议用RX8025,PCF8563需要软件清中断,用起来麻烦,可能会打断IIC时序,程序处理不方便。RX8025不用软件清中断,很方便
5#
ID:538496发表于 2020-3-27 10:56|只看该作者
感谢楼主分享学习了

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网