/******************************************************
时钟模块
时钟由FPC8563产生,程序如下:
作者:sjx 2008-7-27 QQ:307870154
*********************************************************/
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit scl1=P2^0;//定义数码管时钟线
sbit sda1=P2^1;//定义数码管数据线
sbit scl3=P2^4;//定义数码管时钟线
sbit sda3=P2^5;//定义数码管数据线
sbit scl4=P2^6;//定义数码管时钟线
sbit sda4=P2^7;//定义数码管数据线
sbit scl=P0^6;//定义8563 I2C的时钟线
sbit sda=P0^7; //定义8563 I2C的数据线
uchar a,miao,shi,fen,number, b;
uint day,week,month,year;
uchar code tab[]={0x11,0x7d,0x23,0x29,0x4d, // 0 1 2 3 4 //
0x89,0x81,0x3d,0x01,0x09, // 5 6 7 8 9 //
0x05,0xc1,0x93,0x61,0x83,0x87 }; // A B C D E F
void delay()
{ ;; }
//=========8563起始信号子程序===============
void start()
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
//==========8563终止信号子程序================
void stop()
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
//===========8563应答信号子程序====================
void respons()
{
uchar i;
scl=1;
delay();
while((sda==1)&&(i<250))i++; //若无应答,重新开始发送地址
scl=0;
delay();
}
//===========8563总线初始化子程序=======================
void init()
{
sda=1;
delay();
scl=1;
delay();
}
//===========写入1字节子程序======================
void write_byte(uchar date)
{
uchar i,temp;
temp=date; //写入数据date
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delay();
sda=CY; //往数据线送date最高位,循环8次送完date
delay();
scl=1;
delay();
scl=0;
delay();
}
sda=1; //释放数据总线,以便读取应答信号
delay();
}
//===========读取1字节子程序============================
uchar read_byte()
{
uchar i,k;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++) //读回时是一位一位的所以要读8次
{
scl=1; // scl置1数据才稳定才可以读取数据
delay();
k=(k<<1)|sda; //sda送过来的数据送到k的最底位,循环8次从最高位读完sda上的数据
scl=0;
delay();
}
return k; //程序执行完返回k的值
}
//============延时子程序=====================================
void delay1(uchar x)
{
uchar a,b;
for(a=x;a>0;a--)
for(b=100;b>0;b--);
}
//===========写一8位数据子程序===================================
void write_add(uchar address,uchar date)
{
start(); //调用起始信号子程序,开始写入信号
write_byte(0xa2); //找芯片所在地址
respons(); //调用应答信号
write_byte(address);//找芯片内部存储器地址
respons();
write_byte(date);// 写入数据,写进芯片内部存储器
respons();
stop(); //调用终止信号子程序,终止信号写入
}
//===========读一8位数据子程序 ================================
uchar read_add(uchar address)
{
uchar date;
start(); //调用起始信号子程序
write_byte(0xa2); //取芯片地址
respons();
write_byte(address);//取芯片内部存储器地址
respons();
start(); //调用起始信号子程序,开始读取信号
write_byte(0xa3);//芯片读地址
respons();
date=read_byte();//把读取字节子程序的返回值给date
stop();
return date; // 程序执行完返回date的值
}
//===============写时间子程序=============
void write_8563(uchar w_miao,uchar w_fen,uchar w_shi,uchar w_day,uchar w_week,uchar w_month,uchar w_year)
{ init();
start();
write_add(0x00,0x00);
write_add(0x01,0x00);
write_add(0x02, w_miao);
delay1(100);
write_add(0x03,w_fen);
delay1(100);
write_add(0x4,w_shi);
delay1(100);
write_add(0x05,w_day);
delay1(100);
write_add(0x06,w_week);
delay1(100);
write_add(0x7,w_month);
delay1(100);
write_add(0x8,w_year);
delay1(100);
}
//===============读时间子程序============
void read_8563()
{
miao=read_add(0x02)&0x7f;//获取秒数据
miao=((miao&0xf0)>>4&0x0f)*10+(miao&0x0f);//BCD码转换成10进制数
if(miao>=60){miao=0;}
fen=read_add(0x03)&0x7f;//获取分钟
fen=((fen&0xf0)>>4&0x0f)*10+(fen&0x0f);//BCD码转换成10进制数
if(fen>=60){fen=0;}
shi=read_add(0x04)&0x3f;//获取小时
shi=((shi&0xf0)>>4&0x0f)*10+(shi&0x0f);//BCD码转换成10进制数
if(shi>=24){shi=0;}
day=read_add(0x05)&0x3f;//获取日数据
day=(( day&0xf0)>>4&0x0f)*10+( day&0x0f);//BCD码转换成10进制数
if( day>=31){ day=0;}
week=read_add(0x06)&0x07;//获取星期
if(week>6){week=0;}
month=read_add(0x07)&0x1f;//获取月
month=((month&0xf0)>>4&0x0f)*10+(month&0x0f);//BCD码转换成10进制数
if(month>=24){month=0;}
year=read_add(0x08)&0xff;//获取年
shi=((year&0xf0)>>4&0x0f)*10+(year&0x0f);//BCD码转换成10进制数
delay1(100);
}
/********************************************************
********************************************************/
//============数码管移位子程序===================
void shift1()
{
uchar i,t;
number=tab;
scl1=0;
for(i=0;i<8;i++)
{
t=number&0x80; //与、判断,0 1, 0x80为二进制数10000000
sda1=t; // 往数据线送最高位
scl1=1; //上跳
number=number<<1; //左移一位
scl1=0; //下跳
}
}
void shift3()
{
uchar i,t;
number=tab;
scl3=0;
for(i=0;i<8;i++)
{
t=number&0x80; //与、判断,0 1, 0x80为二进制数10000000
sda3=t; // 往数据线送最高位
scl3=1; //上跳
number=number<<1; //左移一位
scl3=0; //下跳
}
}
void shift4()
{
uchar i,t;
number=tab;
scl4=0;
for(i=0;i<8;i++)
{
t=number&0x80; //与、判断,0 1, 0x80为二进制数10000000
sda4=t; // 往数据线送最高位
scl4=1; //上跳
number=number<<1; //左移一位
scl4=0; //下跳
}
}
//============数码管显示程序========================
void dispaly()
{
b=miao%10;//秒个位
shift3();
b=miao/10;//秒十位
shift3();
b=fen%10;
shift4();
b=fen/10;
shift4();
b=shi%10;
shift4();
b=shi/10;
shift4();
b=week%10;//秒个位
shift1();
b=day%10;
shift1();
b=day/10;
shift1();
b=month%10;
shift1();
b=month/10;
shift1();
b=year%10; //年个位
shift1();
b=(year%100)/10;//年十位
shift1();
b=(year%1000)/100;//年百位
shift1();
b=year/1000;
shift1();
delay1(500);
}
//===========主程序=======================================================
void main()
{
init();
delay1(500);
write_8563(0x50,0x59,0x23,0x11,0x01,0x09,0x2008);//初始化秒 分 时,日,星期,月,年
delay1(500); //调用延时函数
while(1)
{
read_8563(); //读取秒 时 分
dispaly(); //显示秒 分 时
}
}
此程序显示读取年和小时那里出错了。单独读取时 分 秒是没有错 但是同时读取年月日星期时分秒时,读不出小时。而且年的千位也是一直读不出请高手帮忙改正谢拉
至于你说年的千位你读不出来那是正常的.因为你认真看一下PCF8563的PDF,年的专用寄存器08H的描述,此位寄存器存放的是BCD形式的年的值,范围是0~99啊.所以你再读也是读不出年的百位千位啊..
现实中制作东西的时候年的百位和千位都是大家默认给出来的啊.也就是说大家根本没有去读它的值,20**年.那两位直接写20不就可以了吗.因为它两们的变动要经历100年呢,到时你的产品可能早就跟不上时代了.
当然如果你要读年也可以,你再仔细看一下8563的PDF,年的百位千位的读取可以通过07H 月/世纪寄存器来读值计算.也就是最高位第7位,有个标志C,你可以读取它来判断百位和千位的值的.当年寄存器由99变化为00时,C就有变化了.这样你软件上稍作处理就可以了.
至于你说同时读取年月日星期时分秒时时小时读不出来,你仔细看一下你的程序:
shi=read_add(0x04)&0x3f;//获取小时
shi=((shi&0xf0)>>4&0x0f)*10+(shi&0x0f);//BCD码转换成10进制数
if(shi>=24){shi=0;}
year=read_add(0x08)&0xff;//获取年
shi=((year&0xf0)>>4&0x0f)*10+(year&0x0f);//BCD码转换成10进制数
delay1(100);
"shi"这个变量你在读取小时的时候已经用到了,为什么读取年的时候还要用它呢,按程序执行的顺序那你不是把以前读取的小时值给覆盖了吗.所以你应该重新定义一个变量来存放年的10进制值 啊.所以你一起读的时候不会出来小时也就正常了.
太感谢你拉 "shi=((year&0xf0)>>4&0x0f)*10+(year&0x0f);//BCD码转换成10进制数"中的"shi"应该是"year"
是我写错了 查的时候太粗心没有看出 哈哈
还有我不知道怎么设置他的闹钟功能程序,不知你是否还能帮忙教下我不胜感激啊
你可能是因为笔误写成了shi.查错误的时候没有想到罢了,这种问题我也遇到过的.出来了就好.
至于闹钟问题,我给你发一个PCF8563的PDF吧.讲的很清楚.
你通过其中的控制/状态寄存器2 和报警寄存器 里边所讲的就能合理的置入闹钟程序了.你所设定的时间值写在报警寄存器里就可以了.
给好各控制位的值后,合理的利用3号管脚/INT在报警发生时输出的信号,或者AF位判断是否到了你所设定的时间.
但是有一点让人也可以理解为它是可写的,因为有个VL位啊.VL=0,保证准确的时钟.VL=1不保证准确的时钟.所谓时钟芯片我想大家都是用它的时间功能吧.所以默认值应该是零.而现实中也不应该去管它的吧.
一周热门 更多>