ds1302 芯片掉电数据归零问题 ?已经安装备用电池!
时间:10-02
整理:3721RD
点击:
ds1302 芯片,时间运行的很准,走时正常,安装备用电池也能正常工作, 当电源断电后,隔几分钟再给电 时间也正常运行!
但是发现设备一直工作 不一定哪一天(也许3天后,也许半个月后,可能跟停电有关,停电时间长短有关系)
举个例子:时间显示本应该18:00:00 变成 01:00:00 我怀疑可能什么因素导致DS1302 归位或者晶振停振了!
在设备上接有一个TT电机 通过 104电容和22uf的电解电容抗干扰 还串联了一个47亨的电感, DS1302电源供电也并联一个10uf的电解电容!
程序如下:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void delay_main(uint z);
/*******************************************************************************
以下是对液晶模块的操作程序
*******************************************************************************/
unsigned char time; //忙碌标志位,,将BF位定义为P0.7引脚
sbit LCD_RS = P1^0;
sbit LCD_RW = P1^1;
sbit LCD_EN = P1^2;
sbit BEEP = P1^3;
sbit DENG = P1^4;
sbit DENGSHI=P3^7;
//sbit lcde=P2^7;
//sbit rs=P2^6;
//sbit rw=P2^5;
sbit K1 = P3^0;
sbit K2 = P3^1;
sbit K3 = P3^2;
sbit K4 = P3^3;
sbit B1 = P2^0;
sbit B2 = P2^1;
sbit B3 = P2^2;
sbit B4 = P2^4;
sbit BEIDENG=P2^3;
sbit reset = P1^7;
sbit sclk = P1^5;
sbit io = P1^6;
//sbit SCK=P3^6; //时钟
//sbit SDA=P3^4; //数据
//sbit RST=P3^5;// DS1302复位
bit flag=1,hour=0,min=0,sec=0;
bit year=0,month=0,day=0,week=0;
bit alarm_flag=0;
uchar timecount=0,count=0;
uchar str1[]=" - - Week: ";
uchar str2[]=" ";
uchar init [] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //
uchar init1[] ={0x00,0x00};
uchar init2[] ={0x00,0x59,0x23,0x01,0x05,0x01,0x06}; //
//秒, 分, 时, 日, 月,星期,年
uchar bj_time[] ={0x00,0x57,0x22};
//秒, 分, 时
uchar code mytab[8] = {0x00,0x00,0x0E,0x04,0x0A,0xFF,0x00,0x00};//小灯 //显示右下角开灯图标
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
void Set_W1302(uchar addr);
void Set_Flash(uchar row,uchar col);
void Set_place(uchar row,uchar col);
void Play_nowtime();
void key_set(uchar num,uchar row,uchar col );
void alarm_time();
void Play_alarmtime();
void Time_compare();
/******************************************************************/
/******************************************************************/
void delay1(int ms)
{
unsigned char y;
while(ms--)
{
for(y = 0; y<250; y++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
/******************************************************************/
/* */
/*检查LCD忙状态 */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。 */
/* */
/******************************************************************/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
/*********************************************************/
/* */
/*写指令数据到LCD */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。 */
/* */
/*********************************************************/
void lcd_wcmd(uchar cmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*********************************************************/
/* */
/*写显示数据到LCD */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。 */
/* */
/*********************************************************/
void lcd_wdat(uchar dat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*********************************************************/
/* */
/* LCD初始化设定 */
/* */
/*********************************************************/
void init_lcd()
{
delay1(15);
lcd_wcmd(0x01); //清除LCD的显示内容
lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x0c); //显示开,关光标
delay1(5);
lcd_wcmd(0x06); //移动光标
delay1(5);
lcd_wcmd(0x01); //清除LCD的显示内容
delay1(5);
}
/*********************************************************/
//
/*********************************************************/
void delay()
{
uchar j;
for(j=250;j>0;j--);
}
/*********************************************************/
/* */
/* 写字符串函数 */
/* */
/*********************************************************/
void write_str(uchar addr,uchar *p)
{
uchar i=0;
lcd_wcmd(addr);
while(p!='\0')
{
lcd_wdat(p);
i++;
}
}
/*********************************************************/
/* */
/* 设定显示位置 */
/* */
/*********************************************************/
void write_position(uchar row,uchar col)
{
uchar place;
if(row==1)
{
place=0x80+col-1;
lcd_wcmd(place);
}
else
{
place=0xc0+col-1;
lcd_wcmd(place);
}
}
/*********************************************************/
/* */
/*自定义字符写入CGRAM */
/* */
/*********************************************************/
void writetab()
{
unsigned char i;
lcd_wcmd(0x40); //写CGRAM
for (i = 0; i< 16; i++)
lcd_wdat(mytab);
}
/**********************************************************/
//
/**********************************************************/
void write_byte(uchar inbyte)
{
uchar i;
for(i=0;i<8;i++)
{
sclk=0; //写的时候低电平改变数据
if(inbyte&0x01)
io=1;
else
io=0;
sclk=1; //写的时候高电平,把数据写入ds1302
_nop_();
inbyte=inbyte>>1;
}
}
/**********************************************************/
/**********************************************************/
uchar read_byte() //sclk的下跳沿读数据
{
uchar i,temp=0;
io=1; //设置为输入口
for(i=0;i<7;i++)
{
sclk=0;
if(io==1)
temp=temp|0x80;
else
temp=temp&0x7f;
sclk=1; //产生下跳沿
temp=temp>>1;
}
return (temp);
}
/**********************************************************/
// 往ds1302的某个地址写入数据
/**********************************************************/
void write_ds1302(uchar cmd,uchar indata)
{
sclk=0;
reset=1;
write_byte(cmd);
write_byte(indata);
sclk=0;
reset=0;
}
/**********************************************************/
// 读ds1302某地址的的数据
/**********************************************************/
uchar read_ds1302(uchar addr)
{
uchar backdata;
sclk=0;
reset=1;
write_byte(addr); //先写地址
backdata=read_byte(); //然后读数据
sclk=0;
reset=0;
return (backdata);
}
/**********************************************************/
// 设置初始时间
/**********************************************************/
void set_ds1302(uchar addr,uchar *p,uchar n) //写入n个数据
{
write_ds1302(0x8e,0x00); //写控制字,允许写操作
for(;n>0;n--)
{
write_ds1302(addr,*p);
p++;
addr=addr+2;
}
write_ds1302(0x8e,0x80); //写保护,不允许写
}
/**********************************************************/
// 读取当前时间
/**********************************************************/
void read_nowtime(uchar addr,uchar *p,uchar n)
{
for(;n>0;n--)
{
*p=read_ds1302(addr);
p++;
addr=addr+2;
}
}
/**********************************************************/
// 初始化DS1302
/**********************************************************/
void init_ds1302()
{
reset=0;
sclk=0;
write_ds1302(0x80,0x00);
write_ds1302(0x90,0xa8); //一个二极管+4K电阻充电
write_ds1302(0x8e,0x80); //写保护控制字,禁止写
}
/**********************************************************/
/* */
/* 蜂鸣器响一声 */
/* */
/**********************************************************/
void beep()
{
}
/*
********************************************************************************
** 函数名称 : delay(uint z)
** 函数功能 : 延时函数
********************************************************************************
*/
void delay_main(uint z)//-----------------主延时函数1毫秒
{ uint x,y; for(x=z;x>0;x--)
for(y=100;y>0;y--);
}
/**********************************************************/
/* */
/* :闪动函数 */
/* */
/**********************************************************/
void flash()
{
if(flag)
{
write_position(2,3);
lcd_wdat(':');
write_position(2,6);
lcd_wdat(':');
}
else
{
write_position(2,3);
lcd_wdat(0x20);
write_position(2,6);
lcd_wdat(0x20);
}
}
/**********************************************************/
// 主函数
/**********************************************************/
void main()
{
BEEP=1;
DENG=1;
BEIDENG=0;
TMOD=0x01;
TH0=0x4c; //50ms定时
TL0=0x00;
EA=1;
ET0=1;
TR0=1;
init_lcd(); //初始化LCD
write_str(0x80,str1); //液晶显示提示信息
write_str(0xc0,str2); //液晶显示提示信息
init_ds1302(); //初始化ds1302
writetab(); //自定义字符写入CGRAM
// delay1(5);
// write_position(2,16);
// lcd_wdat(0x00); //显示自定义字符小喇叭
while(1)
{
//---------------------------------------------------------
if(B1==0&BEEP==1) //手动喂食
{
BEEP=0;
// BEIDENG=0;
delay1(3000);
BEEP=1;
// BEIDENG=1;
}
if(B2==0&DENG==1) //手动开灯
{DENG=0;BEIDENG=0;write_position(2,16); lcd_wdat(0x00);delay1(200);}
if(B2==0&DENG==0) //手动关灯
{DENG=1;BEIDENG=0;write_position(2,16); lcd_wdat(0x20); delay1(200);}
kll:
if(B3==0&BEIDENG==1) //手动开背灯
{BEIDENG=0;delay1(200);}
if(B3==0&BEIDENG==0) //手动关背灯
{BEIDENG=1;delay1(200);}
klle:
Play_nowtime();
Time_compare();
}
}
/**********************************************************/
// Time0中断函数
/**********************************************************/
void Time0(void) interrupt 1 using 0
{
TH0=0x4c; //50ms定时
TL0=0x00;
timecount++;
if(timecount>9)
{
timecount=0;
flag=~flag;
}
}
/**********************************************************/
// 设定值写入DS1302
/**********************************************************/
void Set_W1302(uchar addr)
{
uchar temp;
write_ds1302(0x8e,0x00);
temp=(init1[0]<<4)+init1[1];
write_ds1302(addr,temp);
write_ds1302(0x8e,0x80);
beep();
}
/**********************************************************/
// 指定位置显示
/**********************************************************/
void Set_place(uchar row,uchar col)
{
write_position(row,col);
lcd_wdat(init1[0]+0x30);
write_position(row,col+1);
lcd_wdat(init1[1]+0x30);
}
/**********************************************************/
// 显示当前时间
/**********************************************************/
void Play_nowtime()
{
read_nowtime(0x81,init,7); //读出当前时间,读出7个字节
write_position(2,1);
lcd_wdat(((init[2]&0xf0)>>4)+0x30);
write_position(2,2);
lcd_wdat('0'+(init[2]&0x0f)); //读小时
// write_position(2,3);
// lcd_wdat(':');
write_position(2,4);
lcd_wdat('0'+((init[1]&0xf0)>>4));
write_position(2,5);
lcd_wdat('0'+(init[1]&0x0f)); //读分钟
// write_position(2,6);
// lcd_wdat(':');
write_position(2,7);
lcd_wdat('0'+((init[0]&0xf0)>>4));
write_position(2,8);
lcd_wdat('0'+(init[0]&0x0f)); //读秒
write_position(1,1);
lcd_wdat('0'+((init[6]&0xf0)>>4));
write_position(1,2);
lcd_wdat('0'+(init[6]&0x0f)); //读年
// write_position(1,3);
// lcd_wdat('/');
write_position(1,4);
lcd_wdat('0'+((init[4]&0xf0)>>4));
write_position(1,5);
lcd_wdat('0'+(init[4]&0x0f)); //读月
// write_position(1,6);
// lcd_wdat('/');
write_position(1,7);
lcd_wdat('0'+((init[3]&0xf0)>>4));
write_position(1,8);
lcd_wdat('0'+(init[3]&0x0f)); //读日
write_position(1,15);
lcd_wdat('0'+(init[5]&0x0f)); //读周
flash();
}
/*********************************************************/
// 时间比较
/*********************************************************/
void Time_compare()
{
//第一次喂食时间
if(init[2]==0x09) //如果时间是 09点
{
if(init[1]==0x10) // 如果时间是 10分
{
if (init[0]==0x00) // 如果时间是 00秒
{
BEEP=0; // 开启电机喂食
// BEIDENG=0;
}
}
}
if(init[2]==0x09) // 如果时间是 09点
{
if(init[1]==0x10) // 如果时间是 10分
{
if (init[0]==0x25) // 如果时间是 25秒
{
BEEP=1; //关闭电机停止喂食
//BEIDENG=1;
}
}
}
//第二次喂食时间
//开始喂食
if(init[2]==0x13) //如果时间是 13点
{
if(init[1]==0x00) // 如果时间是 00分
{
if (init[0]==0x00) // 如果时间是 00秒
{
BEEP=0; // 开启电机喂食
// BEIDENG=0;
}
}
}
//停止喂食
if(init[2]==0x13) // 如果时间是 13点
{
if(init[1]==0x00) // 如果时间是 00分
{
if (init[0]==0x25) // 如果时间是 25秒
{
BEEP=1; //关闭电机停止喂食
//BEIDENG=1;
}
}
}
//第三次喂食时间
if(init[2]==0x17) //如果时间是 17点
{
if(init[1]==0x10) // 如果时间是 10分
{
if (init[0]==0x00) // 如果时间是 00秒
{
BEEP=0; // 开启电机喂食
// BEIDENG=0;
}
}
}
if(init[2]==0x17) // 如果时间是 17点
{
if(init[1]==0x10) // 如果时间是 10分
{
if (init[0]==0x25) // 如果时间是 25秒
{
BEEP=1; //关闭电机停止喂食
//BEIDENG=1;
}
}
}
//开鱼缸灯时间
//开灯
if(init[2]==0x17) //如果时间是 17点
{
if(init[1]==0x00) // 如果时间是 00分
{
if (init[0]==0x00) // 如果时间是 00秒
{
DENG=0; // 开灯
BEIDENG=0;
write_position(2,16); lcd_wdat(0x20);
}
}
}
if(init[2]==0x21) // 如果时间是 21点
{
if(init[1]==0x00) // 如果时间是 00分
{
if (init[0]==0x00) // 如果时间是 00秒
{
DENG=1; //关灯
BEIDENG=1;
write_position(2,16); lcd_wdat(0x00);
}
}
}
}
哪位达人 看看啊?
好象DS1302的时间精度受供电电压有影响,掉电时用电池,电压低点,时钟好象是会走慢。
我估计是不是接错DS1302备用电池的引脚。注意与GND同一侧的VCC引脚【1脚】接主电源,8脚接备用电池。
我估计是不是接错DS1302备用电池的引脚。注意与GND同一侧的VCC引脚【1脚】接主电源,8脚接备用电池。
DS1302这芯片很容易产生自激,它对电压温度很高,稍微一点的波动都会出问题,我以前遇到过很多次,后来我按网上说的换成进口的芯片,就基本不出问题了。
原来如此,我也发现了。掉电后不能正常计时。我刚开始还以为是程序的问题呢
遇到同样的问题 , 看来只能通过买好点的芯片解决问题了 除了1302 还有其他选择吗
学习一下,,,,,,,,,,,,,
我也遇到同样的问题