数码之家

 找回密码
 立即注册
搜索
查看: 5368|回复: 15

[C51] 求助!!!DS1302时钟掉电不能保存时间

[复制链接]
发表于 2019-10-17 00:38:02 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
请大神帮助谢谢啧啧啧!!!!

//#include <at89c52.h>          
#include <intrins.h>
#include <reg52.H>

#define DataPort P0

unsigned char code one[] = "20  /  /  ";                 //固定字符
unsigned char code two[] = "  :  :  ";                //固定字符
unsigned char code wendu[] = {0x18, 0x1a, 0x05, 0x04, 0x04, 0x05, 0x02, 0x00};//温度符号
unsigned char code week_char[] = "MON TUE WED THU FRI STA SUN"; //星期字符串
unsigned char miao, fen, shi, ri, yue, nian, week;
unsigned int tp;
bit time_flag, temp_flag;

/******************************
LCD1602
4PIN----RS
5PIN----RW
6PIN----EN
*****************************/
sbit beep = P1^0;                //蜂鸣器
sbit DQ = P2^3;                        //18B20端口
sbit RS = P2^5;                        //1602寄存器选择
sbit RW = P2^6;                        //1602读写控制
sbit EN = P2^7;                        //1602使能端
sbit key1 = P1^5;                //菜单键
sbit key2 = P1^6;                //加
sbit key3 = P1^7;                //减
sbit RST = P3^2;                //1302复位
sbit SDA = P3^3;                //1302数据
sbit SCK = P3^4;                //1302时钟                  

void delay_us(unsigned char t)
{
  while(--t);
}

/***********ms延时程序***********/
void delay_ms(unsigned int ms)
{
        unsigned int a, b;
        for(a = ms; a > 0; a--)
                for(b = 110; b > 0; b--);
}

/********蜂鸣器响一声**********/
void beepplay()
{
        beep = 0;
        delay_ms(60);
        beep = 1;
}

/*********LCD判忙*************/
void lcd_busy()
{
        DataPort = 0xff;
        RS = 0;
        RW = 1;
        EN = 1;
        delay_ms(1);
        while(DataPort & 0x80);
        EN = 0;
}

/**********LCD写数据************/
void write_date(unsigned char dat)
{
        lcd_busy();
        RS = 1;
        RW = 0;
        DataPort = dat;
        delay_ms(2);
        EN = 1;
        delay_ms(2);
        EN = 0;
}

/*********LCD写指令***********/
void write_com(unsigned char com)
{
        lcd_busy();
        RS = 0;
        RW = 0;
        DataPort = com;
        delay_ms(2);
        EN = 1;
        delay_ms(2);
        EN = 0;
}

/*********LCD初始化*************/
void initLCD()
{
        unsigned char i;
        delay_ms(5);                //延时启动,等待电压稳定
        write_com(0x38);        //设置16*2显示,5*7点阵,8位数据口
        write_com(0x0c);        //设置开显示,不显示光标
        write_com(0x06);        //写一个字符地址指针加1
        write_com(0x01);        //清屏
        delay_ms(1);                //第一行起始地址0x80,第二行起始地址0xc0
        write_com(0x81);          //第一行首空一个字符,开始写入第一行固定字符
       
        for(i = 0; i < 10; i++)
                write_date(one[i]);
        delay_ms(1);
        write_com(0xc2);        //第二行首空两个字符,开始写入第二行的固定字符
       
        for(i = 0; i < 8; i++)
                write_date(two[i]);

        write_com(0xcd);        //显示地址
        write_date('.');         //显示"."
        write_date(0x20);         //0x20显示就是空  
//        write_date('C');         //显示C
       
        write_com(0x40);
        for(i = 0; i < 8; i++)
                write_date(wendu[i]);
        write_com(0xcf);
        write_date(0x00);
}

/*********10转BCD**********/                   
unsigned char toBCD(unsigned char dat)
{
        unsigned char tmp;
        tmp=(((dat / 10) * 16)+(dat % 10));
        return(tmp);       
}

/**********DS1302写一个字节*********/          
void writebyte(unsigned char dat)
{
        unsigned char i;
        for(i = 0; i < 8; i++)
        {
                SDA = dat & 0x01;
                SCK = 1;
                _nop_();_nop_();
                SCK = 0;
                dat >>= 1;          
        }
}

/********写DS1302寄存器********/         
void write1302(unsigned char dizhi,shuju)
{
        RST = 0;
        SCK = 0;
        RST = 1;
        writebyte(dizhi);        //写入的地址
        writebyte(shuju);        //写入的数据
        SCK = 1;
        RST = 0;
}

/*******读取DS1302寄存器********/
unsigned char read1302(unsigned char dizhi)
{
        unsigned char i, dat, tmp;
        RST = 0;
        SCK = 0;
        RST = 1;
        writebyte(dizhi | 0x01);
        for(i = 8; i > 0; i--)
        {
                dat >>= 1;
                if(SDA)
                        dat |= 0x80;
                SCK=1;
                _nop_();_nop_();
                SCK=0;
        }
        RST = 0;
        tmp = dat >> 4;
        tmp = ((tmp * 10)+(dat &= 0x0f));
        return(tmp);
}

/*******DS18B20初始化*********/
void init1820()
{
        DQ = 1;
        _nop_();_nop_();
        DQ = 0;
        delay_us(200);
        delay_us(200);
        DQ = 1;
        delay_us(80);
        DQ = 1;
}

/*******向DS18B20中读出一个字节*********/
unsigned char readonebyte_18b20()
{
        unsigned char i=0, dat=0;
        for(i = 8; i > 0; i--)
        {
                DQ = 0;
                dat >>= 1;
                DQ = 1;
                if(DQ)
                        dat |= 0x80;
                delay_us(25);
        }
        return(dat);
}

/******向DS18B20中写入一个字节*******/
void writeonebyte_18b20(unsigned char dat)
{
        unsigned char i=0;   
        for(i = 8; i > 0; i--)   
        {
                DQ = 0;  
                DQ = dat & 0x01;
                delay_us(25);
                DQ = 1;
                dat >>= 1;
        }
        delay_us(25);
}

/*********读取温度*********/
unsigned int readtemp(void)
{
        unsigned int xx, tempL=0, tempH=0;
        init1820();
        writeonebyte_18b20(0xcc);
        writeonebyte_18b20(0x44);
        delay_us(100);
        init1820();
        writeonebyte_18b20(0xcc);
        writeonebyte_18b20(0xbe);
        tempL = readonebyte_18b20();
        tempH = readonebyte_18b20();
        tempH <<= 8;
        xx = tempL | tempH;
        return(xx);       
}

/********显示函数*********/
void display(unsigned char dizhi, dat)
{
        unsigned char a, b;
        a = dat / 10;         //取得十位数字
        b = dat % 10;                                        //取得个位数字
        write_com(dizhi);                        //设定显示的地址
        write_date(a + 0x30);        //数字+0x30得到该数字的LCD1602显示码
        write_date(b + 0x30);
}

/***********温度显示函数**************/
void display_wendu(unsigned char dizhi, dat)
{
         write_com(dizhi);
         write_date(dat);
}

/**********显示周字符**********/
void display_week(unsigned char week)
{
        unsigned char i;
        write_com(0x8d);        //设置星期显示地址
        switch(week)
        {
                case 1:        for(i = 0; i < 3; i++)
                                write_date(week_char[i]);break;
                case 2: for(i = 4; i < 7; i++)
                                write_date(week_char[i]);break;
                case 3: for(i = 8; i < 11; i++)
                                write_date(week_char[i]);break;
                case 4: for(i = 12; i < 15; i++)
                                write_date(week_char[i]);break;
                case 5: for(i = 16; i < 19; i++)
                                write_date(week_char[i]);break;
                case 6: for(i = 20; i < 23; i++)
                                write_date(week_char[i]);break;
                case 7: for(i = 24; i < 27; i++)
                                write_date(week_char[i]);break;
        }
}

/*********按键扫描********/
void keyscan()
{
        unsigned char num;
        if(key1 == 0)                                //判断key1是不是按下
        {
                delay_ms(20);                //按键消抖
                if(key1 == 0)                         //再次检测key1是否按下
                {
                        beepplay();                       
                        while(!key1);        //等待key1释放
                        num++;
                        switch(num)
                        {
                                case 1: TR0 = 0;                                                                                //关闭中断
                                                temp_flag = 0;
                                                time_flag = 0;
                                                write1302(0x8e, 0x00);                                                //允许写入DS1302
                                                write1302(0x80, 0x80);                                                //时间暂停
                                                write_com(0x0f);                                                                        //设置光标闪烁
                                                write_com(0xc9);break;                                                //秒钟闪烁地址
                                case 2: write_com(0xc6);break;                                //分闪烁地址
                                case 3: write_com(0xc3);break;                                //时闪烁地址
                                case 4: write_com(0x8f);break;                                //星期闪烁地址
                                case 5: write_com(0x8a);break;                                //日闪烁地址
                                case 6: write_com(0x87);break;                                //月闪烁地址
                                case 7: write_com(0x84);break;                                //年闪烁地址
                                case 8: write_com(0x0c);                                                        //设置光标不闪烁
                                                write1302(0x90,0xa9);                                                        //充电
                                                write1302(0x8c, toBCD(nian));
                                                write1302(0x86, toBCD(ri));
                                                write1302(0x88, toBCD(yue));
                                                write1302(0x8a, toBCD(week));
                                                write1302(0x84, toBCD(shi));
                                                write1302(0x82, toBCD(fen));
                                                write1302(0x80, toBCD(miao));                         //写入秒
                                                write1302(0x8e, 0x80);                                                        //禁止写入DS1302
                                                num = 0;TR0 = 1;break;                                                                //定时器打开计数清零
                        }
                }
        }
   if(num != 0)           //i>0,按键key2,key3无效
   {
                if(key2 == 0)
                {
                        delay_ms(20);
                        if(key2 == 0)
                        {
                                beepplay();
                                while(!key2);  //等待释放
                                switch(num)
                                {
                                        case 1: miao++;if(miao >= 60)miao = 0;        //秒++
                                                        display(0xc8, miao);                        //显示秒
                                                        write_com(0xc9);break;                //因为显示地址指针自动加1,重新定义秒的地址
                                        case 2: fen++;if(fen == 60)fen = 0;                //分++
                                                        display(0xc5, fen);                        //显示当前调入分数据
                                                        write_com(0xc6);break;
                                        case 3: shi++;if(shi == 24)shi = 0;
                                                        display(0xc2, shi);
                                                        write_com(0xc3);break;
                                        case 4: week++;if(week == 8)week = 1;
                                                        display_week(week);
                                                        write_com(0x8f);break;
                                        case 5: ri++;if(ri == 32)ri = 1;
                                                        display(0x89, ri);
                                                        write_com(0x8a);break;
                                        case 6: yue++;if(yue == 13)yue = 1;
                                                        display(0x86, yue);
                                                        write_com(0x87);break;
                                        case 7: nian++;if(nian == 100)nian = 0;
                                                        display(0x83, nian);
                                                        write_com(0x84);break;
                                }
                        }
                }
                if(key3==0)                           //按键0有效,判断key3按下是不是0
                {
                        delay_ms(20);           //按键消抖
                        if(key3==0)
                        {
                                beepplay();           //调用蜂鸣器响一声
                                while(!key3);  //等待释放key3
                                switch(num)
                                {
                                        case 1: miao--;if(miao == 255 | miao > 60)miao = 59;        //减1,减到0再减1就是255
                                                        display(0xc8, miao);
                                                        write_com(0xc9);break;
                                        case 2: fen--;if(fen == 255)fen = 59;
                                                        display(0xc5, fen);
                                                        write_com(0xc6);break;
                                        case 3: shi--;if(shi == 255)shi = 23;
                                                        display(0xc2, shi);
                                                        write_com(0xc3);break;
                                        case 4: week--;if(week == 0)week = 7;
                                                        display_week(week);
                                                        write_com(0x8f);break;
                                        case 5: ri--;if(ri == 0)ri = 31;
                                                        display(0x89, ri);
                                                        write_com(0x8a);break;
                                        case 6: yue--;if(yue == 0)yue = 12;
                                                        display(0x86, yue);
                                                        write_com(0x87);break;
                                        case 7: nian--;if(nian == 255)nian = 99;
                                                        display(0x83, nian);
                                                        write_com(0x84);break;
                                }
                        }
                }
        }                       
}

/***********更新时间***********/
void update_time()
{
        if(time_flag == 1)
        {
                time_flag = 0;
                miao = read1302(0x81);                //读秒
                fen = read1302(0x83);                        //读分  
                shi = read1302(0x85);                        //读时  
                ri = read1302(0x87);                        //读日  
                yue = read1302(0x89);                        //读月  
                week = read1302(0x8b);                //读周  
                nian = read1302(0x8d);                //读年

                display(0xc8, miao);                        //更新秒
                display(0xc5, fen);                        //更新分
                display(0xc2, shi);                        //更新时
                display(0x89, ri);                        //更新日
                display(0x86, yue);                        //更新月
                display(0x83, nian);                        //更新年
                display_week(week);                 //更新周
        }
}

/**********更新温度*********/
void update_temp()
{
        unsigned int temp;
        if(temp_flag == 1)
        {       
                temp_flag = 0;
                temp = readtemp();
                tp = temp;
                if(tp & 0x8000)
                        tp = (~tp)+1;
                tp = ((tp * 5) >> 3);
                if(temp & 0x8000)
                {
                        display_wendu(0xcb, '-');
                        display_wendu(0xcc, (tp % 100 / 10) + 0x30);
                        display_wendu(0xce, (tp % 10) + 0x30);
                }
                else
                {
                        if((tp / 100 % 10) == 0)
                                display_wendu(0xcb, 0x20);
                        else
                                display_wendu(0xcb, (tp / 100 % 10) + 0x30);
                        display_wendu(0xcc, (tp % 100 / 10) + 0x30);
                        display_wendu(0xce, (tp % 10) + 0x30);
                }          
        }
}

/********定时器初始化************/
void init_Time0()
{
        TMOD = 0x01;        //设置定时器工作模式
        TH0 = 0;
  TL0 = 0;
        EA = 1;                //开总中断
        ET0 = 1;                //开定时器0中断
        TR0 = 1;                //启动定时器
}

/**********主函数*************/
void main()
{
        initLCD();                         //初始化LCD
        init_Time0();                //初始化定时器          
        while(1)
        {
                keyscan();                //键盘扫描
                update_time();         //更新时间
                update_temp();        //更新温度
        }                                                                  
}                                               

/************中断程序***************/
void Time0()interrupt 1                                 //中断程序不易过多
{
        static unsigned char x, y;
        TH0 = (65536-10000) / 256;                         //赋值10ms
        TL0 = (65536-10000) % 256;                 
        x++;
        if(x == 10)
        {
                x = 0; y++;
                time_flag = 1;
                if(y == 5)
                {
                        y = 0;
                        temp_flag = 1;       
                }
        }       
}

发表于 2019-10-17 08:11:30 | 显示全部楼层
是啊,看程序有用吗?
看看你的电路原理是咋样的?电池咋接的?
回复 支持 反对

使用道具 举报

发表于 2019-10-17 09:47:27 | 显示全部楼层
一定要开启时钟,DS1302的秒寄存器,在程序初始化时一定要有l类似write_ds 1302(0x80,0x00)的语句,其中0x80是秒寄存器的地址,0x00 是写入的数据,这个数据的最高位一定要是0,是0 才能开启时钟走时。
回复 支持 反对

使用道具 举报

发表于 2019-10-17 10:49:39 | 显示全部楼层
单片机系统可以掉电,但DS1302时钟不能掉电,掉电就不能保存时间!
回复 支持 反对

使用道具 举报

发表于 2019-10-17 11:37:59 | 显示全部楼层
你的1302的初始化函数我没看到。不过一般是在1302中初始化,在非RTC的REG中写入一个值,上电后先读这个值,非“0”,跳过写入时间,为“0”就写入时间,因为1302掉电后,所有REG都清0了
回复 支持 反对

使用道具 举报

发表于 2019-10-17 11:46:53 | 显示全部楼层
意思是无电还能自走的时钟???:lol:哪有卖我也想买,,居然不要电
回复 支持 反对

使用道具 举报

发表于 2019-10-17 20:21:25 | 显示全部楼层
本帖最后由 zhuls 于 2019-10-17 20:25 编辑

给你一个初始化的函数参考一下:
char setted;
/*****************************************************************************/
//设置1302的初始时间(自动初始化)
void Init_1302(void)
{
       setted=read_clock(0xc1);//读初始化标志
                if (setted!=0x55)//首次上电未初始化或掉电过
                {
                write_clock(0x8e,0x00);//允许写操作
                write_clock(0x80,0x30);//秒
                write_clock(0x82,0x27);//分钟
                write_clock(0x84,0x21);//小时
                write_clock(0x86,0x03);//日
                write_clock(0x88,0x03);//月
                write_clock(0x8a,0x01);//星期
                write_clock(0x8c,0x14);//年
                write_clock(0xc0,0x55);//写初始化标志
                write_clock(0x8e,0x80);//禁止写操作
                }
}
只有首次上电或掉电过才要重新写入时间。应该是你的程序中没有这一步骤,所以时间老是被重置



回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-10-18 09:22:28 | 显示全部楼层
海洋dz 发表于 2019-10-17 08:11
是啊,看程序有用吗?
看看你的电路原理是咋样的?电池咋接的?

DS1302肯定有电池的.而且也是按照图纸做的。。。但是只要断开外接供电再上电,时间还是貌似初始代状态。

制作图纸

制作图纸
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-10-18 12:09:15 | 显示全部楼层
zhuls 发表于 2019-10-17 11:37
你的1302的初始化函数我没看到。不过一般是在1302中初始化,在非RTC的REG中写入一个值,上电后先读这个值, ...

请帮我添加一份初始化代码吧!确实被弄糊涂了!谢谢,感激66666666666666666666666
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-10-18 12:11:35 | 显示全部楼层
lyy-cy 发表于 2019-10-17 09:47
一定要开启时钟,DS1302的秒寄存器,在程序初始化时一定要有l类似write_ds 1302(0x80,0x00)的语句,其中0x8 ...

语句是有的在后面!!可以帮忙写一个吗。,谢谢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-10-18 12:19:21 | 显示全部楼层
这是电路图

电路图

电路图
回复 支持 反对

使用道具 举报

发表于 2019-10-18 12:23:17 来自手机浏览器 | 显示全部楼层
leezll 发表于 2019-10-18 09:22
DS1302肯定有电池的.而且也是按照图纸做的。。。但是只要断开外接供电再上电,时间还是貌似初始代状态。 ...

设置时间的那个函数只运行一次就行了…
回复 支持 反对

使用道具 举报

发表于 2019-10-18 17:08:14 | 显示全部楼层
/**********主函数*************/
void main()
{
        initLCD();                         //初始化LCD
        init_Time0();                //初始化定时器   
        Init_1302();     //主程序加入这个  
        while(1)
        {
                keyscan();                //键盘扫描
                update_time();         //更新时间
                update_temp();        //更新温度
        }                                                                  
}                                                
///;;;;;;;;


/*****************************************************************************/
//设置1302的初始时间(自动初始化)
void Init_1302(void)//初始时间:14年3月3日21时27分30秒,星期1
{
   char setted;
       setted=read_clock(0xc1);//读初始化标志
                if (setted!=0x55)//首次上电未初始化或掉电过,这个数会清0;
                {
                write1302(0x8e,0x00);//允许写操作
                write1302(0x80,0x30);//秒
                write1302(0x82,0x27);//分钟
                write1302(0x84,0x21);//小时
                write1302(0x86,0x03);//日
                write1302(0x88,0x03);//月
                write1302(0x8a,0x01);//星期
                write1302(0x8c,0x14);//年
                write1302(0xc0,0x55);//写初始化标志,在1302的0XC0寄存器中写入0X55
                write1302(0x8e,0x80);//禁止写操作
                }
}
回复 支持 反对

使用道具 举报

发表于 2019-11-6 20:42:37 | 显示全部楼层
估计是那个3V电池的问题,以前用过,一段时间后电池就冲不进去电了,现在我用5.5V的超级电容代替那个电池,与电源正极加个二极管和1k左右的电阻限流充电,很好用。
回复 支持 反对

使用道具 举报

发表于 2019-11-13 01:43:27 来自手机浏览器 | 显示全部楼层
DS1302你用的是3V纽扣电池吧?去年我也仿制一个,用的就是3伏纽扣电池,掉电就初始化。后来替换成1500uf的电解电容,掉电可以维持十几分钟。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-4-19 05:43 , Processed in 0.265201 second(s), 11 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表