找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12713|回复: 19
打印 上一主题 下一主题
收起左侧

DS1302掉电不丢失时间单片机程序编写问题

  [复制链接]
跳转到指定楼层
楼主
本帖最后由 jianwei2030 于 2017-9-3 21:12 编辑

自己做了一个万年历时钟,利用STC15W408AS单片机,时钟芯片采用DS1302。当前自己参考网上写了时间读取的程序,在实验板走时正常,但是断电再上电后无法保存时间,程序在首次上电后会初始化一个固定的时间,每次都得自己重新调时。看到网上有种说法是给1302写入标志位,每次系统上电后检测这个标志位,如果能够检测到就不初始化时间,直接读取;如果检测不到标志位就初始化。但是按照这种方法试过后仍然不见效果,请大家帮忙看看我这程序该怎么修改合适?

电路部分:

以下是我的程序:
1302部分:
  1. #include<STC15W.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. /*  宏定义写DS1302的地址  */
  5. #define write_sec_add            0x80        //秒数据地址    1000 0000
  6. #define write_min_add            0x82        //分数据地址    1000 0010
  7. #define write_hr_add            0x84        //时数据地址    1000 0100
  8. #define write_week_add            0x86        //星期数据地址    1000 0110
  9. #define write_month_add            0x88        //月数据地址    1000 1000
  10. #define write_day_add            0x8a        //日数据地址    1000 1010
  11. #define write_year_add            0x8c        //年数据地址    1000 1100
  12. #define write_control_add        0x8e        //控制数据地址    1000 1110
  13. #define write_charger_add        0x90         //可编程涓流充电地址 1001 0000            
  14. #define write_clkburst_add        0xbe        //时钟脉冲串地址
  15. #define write_RAM0_add            0xc0        //RAM0寄存器写地址     1100 0000
  16. /*  宏定义读DS1302的地址  */
  17. #define read_sec_add            0x81        //秒数据地址    1000 0001
  18. #define read_min_add            0x83        //分数据地址    1000 0011
  19. #define read_hr_add                0x85        //时数据地址    1000 0101
  20. #define read_week_add            0x87        //星期数据地址    1000 0111
  21. #define read_month_add            0x89        //月数据地址    1000 1001
  22. #define read_day_add            0x8b        //日数据地址    1000 1011
  23. #define read_year_add            0x8d        //年数据地址    1000 1101
  24. #define read_control_add        0x8f        //控制数据地址  1000 1111
  25. #define read_charger_add        0x91         //可编程涓流充电地址  1001 0001              
  26. #define read_clkburst_add        0xbe        //时钟脉冲串地址
  27. #define read_RAM0_add            0xc1        //RAM0寄存器读地址      1100 0001

  28. //#define P2M1 = 0x00;    //0000 0000               
  29. //#define P2M0 = 0x04;    //0000 0100
  30. uchar sec,min,hr,week,mouth,day,year,ram_data;

  31. sbit sclk=P2^1;        
  32. sbit io=P2^2;        
  33. sbit ce=P2^3;

  34. void write1302_time(uchar address,uchar dat)  //写入数据给1302
  35. {
  36.     uchar i;
  37.     ce=0;     //禁止读写数据
  38.     sclk=0;   
  39.     for(i=0;i<8;i++)    //写地址
  40.     {
  41.       ce=1;     //允许读写数据
  42.       sclk=0;
  43.       io=address&0x01;  
  44.       address>>=1;
  45.       sclk=1;
  46.     }
  47.     for(i=0;i<8;i++)    //写数据
  48.     {
  49.       ce=1;    //允许读写数据
  50.       sclk=0;
  51.       io=dat&0x01;
  52.       dat>>=1;
  53.       sclk=1;
  54.     }
  55.     ce=0;
  56. }

  57. uchar read1302_time(uchar address) //从1302读取时间数据
  58. {
  59.     uchar i,num;
  60.     ce=0;   //禁止读写数据
  61.     for(i=0;i<8;i++)
  62.     {
  63.       ce=1;
  64.       sclk=0;
  65.       io=address&0x01;
  66.       address>>=1;
  67.       sclk=1;
  68.     }
  69.     for(i=0;i<8;i++)
  70.     {
  71.       if(io==1)
  72.         num=num|0x80;
  73.       else
  74.         num=num|0x00;

  75.       sclk=1;
  76.       num>>=1;
  77.       sclk=0;
  78.     }
  79.     ce=0;
  80.     return num;
  81. }

  82. void init_1302() //初始化函数 设置时间
  83. {
  84.     read_ram_data = read1302_time(read_RAM0_add);
  85.        if(rread_ram_data!=0xf0)
  86.     {
  87.         write1302_time(0x8e,0x00);  //保护取消,可以进行读写操作
  88.         write1302_time(write_sec_add,0x00);//写入初始秒时间 0101 0110
  89.         write1302_time(write_min_add,0x35);//写入初始分时间 0101 0110
  90.         write1302_time(write_hr_add,0x22); //写入初始时时间 0101 0110
  91.         write1302_time(write_week_add,0x06); //写入初始周时间 0101 0110
  92.         write1302_time(write_month_add,0x08); //写入初始月时间 0101 0110
  93.         write1302_time(write_day_add,0x12); //写入初始日时间 0101 0110
  94.         write1302_time(write_year_add,0x17); //写入初始年时间 0101 0110
  95.         write1302_time(0x90,0xa5);    //使能涓流充电,  1010 0101
  96.         write1302_time(write_RAM0_add,0xf0); //往RAM寄存器中写入0xf0数据,因为RAM有掉电丢失特点,所以进入初始化函数的时候首先判断这个寄存器是否还有数据
  97.         write1302_time(0x8e,0x80);   //保护启动,禁止对1302写操作
  98.     }
  99. }
  100. void xianshi_data() //将从1302读出的二进制数据转换为十进制
  101. {
  102.     uchar read_sec,    read_min, read_hr, read_week, read_mouth, read_day, read_year;

  103.     read_sec = read1302_time(read_sec_add);       //从“read1302_time”函数取得返回值num的数据
  104.         sec = ((read_sec&0x70)>>4)*10+(read_sec&0x0f); //十进制“秒”

  105.     read_min = read1302_time(read_min_add);
  106.         min = ((read_min&0x70)>>4)*10+(read_min&0x0f); //十进制“分”

  107.     read_hr = read1302_time(read_hr_add);
  108.         hr = ((read_hr&0x70)>>4)*10+(read_hr&0x0f);     //十进制“时”

  109.     read_week = read1302_time(read_week_add);
  110.         week = ((read_week&0x70)>>4)*10+(read_week&0x0f);  //十进制“周”

  111.     read_day = read1302_time(read_day_add);
  112.         day = ((read_day&0x70)>>4)*10+(read_day&0x0f);    //十进制“日”

  113.     read_mouth = read1302_time(read_month_add);
  114.         mouth = ((read_mouth&0x70)>>4)*10+(read_mouth&0x0f); //十进制“月”

  115.     read_year = read1302_time(read_year_add);
  116.         year = ((read_year&0x70)>>4)*10+(read_year&0x0f);    //十进制“年”
  117. }
复制代码


主函数部分:
  1. #include<STC15W.h>
  2. #include"1302.h"
  3. #include"18B20.h"
  4. #include"display.h"
  5. #include"keyboard.h"
  6. #define uchar unsigned char
  7. #define uint unsigned int

  8. //#define  P2M1_set  0x00    //设置P2口工作模式   0000 0000
  9. //#define  P2M0_set  0x0d //设置P2口工作模式   0000 1110
  10. uchar num;
  11. /*************************延时函数*************************/
  12. void delay(uint a)         // 1ms延时程序(12MHz 10倍于51单片机速度时)
  13. {
  14.     uint i;
  15.     while(--a != 0)
  16.     {
  17.         for(i = 0;i < 600;i++);
  18.     }                           
  19. }
  20. /***************************************初始化IO口状态**************************************/
  21. //void IO_init(void)
  22. //{
  23. //P2M1 = P2M1_set;
  24. //P2M0 = P2M0_set;
  25. //}
  26. /**************************************外部中断INT2初始化函数 **************************************/
  27. void INT2_init()
  28. {      
  29.     INT_CLKO |=    0x10;
  30.     EA = 1;
  31. }

  32. void main()
  33. {   
  34.     INT2_init();
  35. //    IO_init();
  36. //    read_ram();
  37.     init_1302();
  38.     init_18b20();
  39.     while(1)
  40.     {
  41.         display_service();
  42.         display_qiehuan();
  43.     }
  44. }
复制代码

这是网上找到的别人的回答:
https://zhidao.baidu.com/question/345394758.html



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:82765 发表于 2017-9-2 21:31 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

板凳
ID:230544 发表于 2017-9-2 23:08 | 只看该作者
你可以修改一下你的初始化函数,DS1302里面不是有好多空着的寄存器嘛,你可以先检测某一个寄存器是否为0,为零就初始化,初始化完毕后给这个寄存器写1,这样就可以了

评分

参与人数 1黑币 +30 收起 理由
admin + 30 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

地板
ID:135636 发表于 2017-9-3 20:09 | 只看该作者
黑暗人才 发表于 2017-9-2 23:08
你可以修改一下你的初始化函数,DS1302里面不是有好多空着的寄存器嘛,你可以先检测某一个寄存器是否为0, ...

网上的说法也是这样做,初始化时在1302的ram中写入一个数值,以后每次上电都检测这个数值,如果检测到就不执行初始化程序,检测不到就执行初始化程序。但是我想知道怎么写这个检测程序。
回复

使用道具 举报

5#
ID:135636 发表于 2017-9-3 20:14 | 只看该作者
cjjcjj1 发表于 2017-9-2 21:31
你好!
1、要想断电时钟继续走时,1302要加后备电池
2、断电后,重启,时钟恢复 17年8月12日

后备电池是有加3V纽扣电池的;删掉初始化函数后第一次上电就什么也不显示了,我希望第一次上电时显示一个初始时间,用户在这个时间的基础上再修改。
回复

使用道具 举报

6#
ID:99130 发表于 2017-9-4 22:49 | 只看该作者
屏蔽掉初始化
回复

使用道具 举报

7#
ID:158667 发表于 2017-9-5 10:48 | 只看该作者
电路没问题,不同公司的1302驱动方法上可能存在不同,我也遇到过同样的问题,换个1302就好了
回复

使用道具 举报

8#
ID:135636 发表于 2017-9-7 21:53 | 只看该作者
mengx 发表于 2017-9-5 10:48
电路没问题,不同公司的1302驱动方法上可能存在不同,我也遇到过同样的问题,换个1302就好了

换过了,前后都是用达拉斯的芯片
回复

使用道具 举报

9#
ID:135636 发表于 2017-9-7 21:56 | 只看该作者
黑暗人才 发表于 2017-9-2 23:08
你可以修改一下你的初始化函数,DS1302里面不是有好多空着的寄存器嘛,你可以先检测某一个寄存器是否为0, ...

网上也是这么说的,我是检测1302内部的31字节的第一位,初始化时给这一位写入一个数据,再上电时读取这一位是不是之前写入的值,但是根据网上的程序修改没有效果。
回复

使用道具 举报

10#
ID:135636 发表于 2017-10-8 15:35 | 只看该作者
我修改了上电检测部分的程序(如下),
思路是:上电后检测RAM中存储的数据十位是否为7,如果是则跳过初始化程序(什么也不执行),如果不是则执行初始化子程序
可是不管我怎么修改,修改后的时间就是无法保存,每次上电后依然是初始化的时间,要怒了。。。

void init_1302() //初始化函数 设置时间
{
                write1302_time(write_control_add,0x00);  //保护取消,可以进行读写操作
                write1302_time(write_sec_add,0x30);//写入初始秒时间 0101 0110
                write1302_time(write_min_add,0x05);//写入初始分时间 0101 0110
                write1302_time(write_hr_add,0x21); //写入初始时时间 0101 0110
                write1302_time(write_week_add,0x07); //写入初始周时间 0101 0110
                write1302_time(write_month_add,0x09); //写入初始月时间 0101 0110
                write1302_time(write_day_add,0x03); //写入初始日时间 0101 0110
                write1302_time(write_year_add,0x17); //写入初始年时间 0101 0110
                write1302_time(write_RAM0_add,0x17); //往RAM寄存器中写入0xf0数据,因为RAM有掉电丢失特点,所以进入初始化函数的时候首先判断这个寄存器是否还有数据
                write1302_time(write_charger_add,0xab);        //使能涓流充电,两个二极管+8k电阻  1010 1011
                write1302_time(write_control_add,0x80);   //保护启动,禁止对1302写操作
}

void ram_flag()
{
        read_ram_data = read1302_time(read_RAM0_add);                
        ram_data = ((read_ram_data&0x70)>>4)*10+(read_ram_data&0x0f);
        if((ram_data%10) == 7)
        {
                write1302_time(write_control_add,0x80);   //保护启动,禁止对1302写操作
        }
        else if((ram_data%10) != 7)
        {
                init_1302();
        }
}
回复

使用道具 举报

11#
ID:140489 发表于 2017-10-10 15:58 | 只看该作者
jianwei2030 发表于 2017-9-7 21:53
换过了,前后都是用达拉斯的芯片

换进口的DS1302,同样的程序,进口的芯片可以,有些国产的芯片就是不行
回复

使用道具 举报

12#
ID:144936 发表于 2018-7-2 01:29 | 只看该作者
DS1302掉电后内部RAM的值不等于3,可以判断后初始化时间,然后标记为3即可。

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

13#
ID:362877 发表于 2018-7-2 09:40 | 只看该作者
你们也太厉害了吧
回复

使用道具 举报

14#
ID:362877 发表于 2018-7-2 09:41 | 只看该作者

DS1302掉电后内部RAM的值不等于3,可以判断后初始化时间,然后标记为3即可。
回复

使用道具 举报

15#
ID:420015 发表于 2019-3-26 20:44 | 只看该作者
我还看到过说1302的vcc2连接一个10000uF的电容,就可以断电也能继续计时,说再加一个write1302_time(0x90,0xa6);就可以
这个说法是真的吗?

为什么我的板是连了一个10 0000uF的电容,试了,失败了,还是说一定要加一个3v的备用电池才能做到断电继续计时?
回复

使用道具 举报

16#
ID:716109 发表于 2020-3-30 18:50 | 只看该作者
我以上方法都试了都不行
回复

使用道具 举报

17#
ID:47286 发表于 2020-3-30 20:48 | 只看该作者
不明白你说的不成都什么不成 也没太看明白你要求什么 1302这东西 掉电就没时间了 必须要重新写入时间

往1302的RAM写校验标记是可以的 完全没问题 我正在用 写的是第一个地址 注意 因为1302是BCD格式写入 如果你写的值超过6位读出来就只有6位 比如写0xaa进去出来是0x2a

如果你的板子没设计后备电池 可以在供电线路上并联一个电池 电池的正极串联一个二极管 和后备电池意思一样

如果是片子断电后再上电 也不一定非要去读1302 写个预处理函数 在主循环的while之前执行 只要是第一次上电 都先从1302读时间到缓冲区 然后再到主循环里显示 当然 这样做的前提是1302不能断电 否则读出来的肯定是错误的时间 读1302的RAM方法只是为了判断是否执行调表
回复

使用道具 举报

18#
ID:65297 发表于 2020-3-30 21:30 | 只看该作者
软件你已经写好了,而且是可以正常使用的,现在最简单的方法就是用一个IO口来判断是否需要初始化即可,
例如你的P55脚是空的,在初始化前面先判断P55,是0的话初始化,是1就不初始化,你烧录好程序,如果想要初始化就把P55接地再上电就会初始化了,不需要初始化时悬空即可,多简单啊
回复

使用道具 举报

19#
ID:316880 发表于 2020-3-30 23:51 | 只看该作者
这个问题啊,时间初始化是程序的问题,要设置一下那个什么命令,不太记得了,我DS1302,都是直接调用程序,改一下IO口就可以用了,你找的程序不对,你这个是程序初始化的时候把时间给初始化了。
回复

使用道具 举报

20#
ID:716109 发表于 2020-3-31 09:11 | 只看该作者
黑暗人才 发表于 2017-9-2 23:08
你可以修改一下你的初始化函数,DS1302里面不是有好多空着的寄存器嘛,你可以先检测某一个寄存器是否为0, ...

我是这样检测的,第一次上电后是我的初始化时间,但是第二次上电后时间从0开始,说明我的备用电源正常,应为向存储器写的内容没有丢失,但是时间为啥不对呢,请问遇到过同类型的问题吗,新手已被逼疯。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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