找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 651|回复: 12
收起左侧

怎样可以利用DS1302的时钟进行开机时间累计

[复制链接]
ID:965189 发表于 2023-11-18 14:18 | 显示全部楼层 |阅读模式
怎样可以利用DS1302的时钟进行开机时间累计,开机时间累计,关机时间不累计。
回复

使用道具 举报

ID:1089601 发表于 2023-11-18 15:39 | 显示全部楼层
不一定非得用DS1302,累计开机时间关键是得有低电压中断在关机前记录累计的时间,在开机时继续累计时间,要是用DS1302可以利用掉电不易失的RAM储存累计时间。低电压中断是必须得用的。
回复

使用道具 举报

ID:771630 发表于 2023-11-18 16:21 | 显示全部楼层
简单的方法:开机后给1302输出32.768KHz的时钟信号
复杂的方法:开启后开启1302振荡器,当主控电压小于某个值或者检测到关机信号,关闭1302振荡器
回复

使用道具 举报

ID:965189 发表于 2023-11-18 17:01 | 显示全部楼层
时钟是一直运行的。
回复

使用道具 举报

ID:213173 发表于 2023-11-18 17:06 | 显示全部楼层
这是一款掉电中断保存数据到EEPROM的测试程序,最长时间99小时59分59秒,修改后时间记录可以无限长。时钟源用的定时器,楼主改用1302秒信号即可。特别注意事项:测试本示例时,需在ISP下载时将低压复位功能和低压时禁止EEPROM操作关闭。
  1. //测试条件:TX-1C实验板,MCU型号IAP15W4K58S4
  2. //注意:测试本示例时,需在ISP下载时将低压复位功能和低压时禁止EEPROM操作关闭
  3. #include <STC15F2K60S2.H>
  4. #include <intrins.h>                                //库头文件
  5. #define uint unsigned int                         //宏定义数据类型uint
  6. #define uchar unsigned char                 //宏定义数据类型uchar
  7. //宏定义ISP的操作命令
  8. #define CMD_IDLE    0               //空闲模式
  9. #define CMD_READ    1               //IAP字节读命令
  10. #define CMD_PROGRAM 2               //IAP字节编程命令
  11. #define CMD_ERASE   3               //IAP扇区擦除命令
  12. #define ENABLE_IAP  0x82            //CPU的等待时间
  13. #define IAP_ADDRESS 0x0800                        //测试地址
  14. sbit duan=P2^6;
  15. sbit wein=P2^7;
  16. sbit buzzer=P2^3;
  17. //顺序共阴极数码管段码表,段码a-h顺序接PX0-PX7
  18. uchar code table[]={//共阴数码管段码"0~f-."
  19.                 0x3f,0x06,0x5b,0x4f,
  20.                 0x66,0x6d,0x7d,0x07,
  21.                 0x7f,0x6f,0x77,0x7c,
  22.                 0x39,0x5e,0x79,0x71,0x40,0x80};
  23. uchar data dis_buf[8];                //缓存数组
  24. uchar hour,min,sec;
  25. uint num;
  26. uchar i;
  27. uint sign;
  28. void Timer0Init();                                        //定时器初始化声明
  29. void IapIdle();                                                //关闭IAP/EEPROM
  30. uchar IapReadByte(uint addr);                //读取EEPROM数据
  31. void IapProgramByte(uint addr, uchar dat);//写入EEPROM数据
  32. void IapEraseSector(uint addr);                //擦除EEPROM数据

  33. void main()                                                        
  34. {
  35.         P0M0 = 0x00;
  36.         P0M1 = 0x00;
  37.         P1M0 = 0x00;
  38.         P1M1 = 0x00;
  39.         P2M0 = 0x00;
  40.         P2M1 = 0x00;
  41.         P3M0 = 0x00;
  42.         P3M1 = 0x00;
  43.         P4M0 = 0x00;
  44.         P4M1 = 0x00;
  45.         P5M0 = 0x00;
  46.         P5M1 = 0x00;
  47.         P6M0 = 0x00;
  48.         P6M1 = 0x00;
  49.         P7M0 = 0x00;
  50.         P7M1 = 0x00;
  51.         if(IapReadByte(IAP_ADDRESS)==0xff)//如果首次上电没有保存过数据
  52.         {
  53.                 for(i=0;i<3;i++)
  54.                 {
  55.                         IapProgramByte(IAP_ADDRESS+i,0x00);//写0
  56.                 }
  57.                 hour=0;
  58.                 min=0;
  59.                 sec=0;
  60.                 sign=1;
  61.         }
  62.         else
  63.         {
  64.                 hour=IapReadByte(IAP_ADDRESS);
  65.                 min=IapReadByte(IAP_ADDRESS+1);
  66.                 sec=IapReadByte(IAP_ADDRESS+2);
  67.         }
  68.         IapEraseSector(IAP_ADDRESS);//擦除上次保存的数据为本次掉电做准备
  69.         PCON &= 0xDF;//清0掉电标志
  70.         ELVD = 1;//开低压中断
  71.         EA   = 1;//开总中断

  72.         Timer0Init();//初始化定时器

  73.         while(1)
  74.         {
  75.                 if(TF0)//查询T0中断请求标志
  76.                 {               
  77.                         TF0=0;//T0中断请求标志清0
  78.                         if(++num>=1000)//1秒
  79.                         {
  80.                                 num=0;                                
  81.                                 sec++;
  82.                                 if(++sec>=60)
  83.                                 {
  84.                                         sec=0;
  85.                                         min++;
  86.                                         if(min>=60)
  87.                                         {
  88.                                                 min=0;
  89.                                                 hour++;
  90.                                                 if(hour>99)hour=0;
  91.                                         }
  92.                                 }
  93.                         }
  94.                         dis_buf[0]=table[hour/10];
  95.                         dis_buf[1]=table[hour%10]|0x80;//加点
  96.                         dis_buf[2]=table[min/10];
  97.                         dis_buf[3]=table[min%10]|0x80;//加点
  98.                         dis_buf[4]=table[sec/10];
  99.                         dis_buf[5]=table[sec%10];
  100.                         P0=0x00;duan=1;duan=0;
  101.                         P0=~(0x01<<i);wein=1;wein=0;
  102.                         P0=dis_buf[i];duan=1;duan=0;
  103.                         i=++i%6;
  104.                 }//耗时569us
  105.         }
  106. }

  107. void Timer0Init(void)        //1毫秒@11.0592MHz
  108. {
  109.         AUXR |= 0x80;                //定时器时钟1T模式
  110.         TMOD &= 0xF0;                //设置定时器模式
  111.         TL0 = 0xCD;                        //设置定时初始值
  112.         TH0 = 0xD4;                        //设置定时初始值
  113.         TF0 = 0;                        //清除TF0标志
  114.         TR0 = 1;                        //定时器0开始计时
  115. }
  116. /*----------------------------
  117.         关闭IAP功能
  118. ----------------------------*/
  119. void IapIdle()
  120. {
  121.     IAP_CONTR = 0;                  //关闭IAP功能
  122.     IAP_CMD = 0;                    //清除命令寄存器
  123.     IAP_TRIG = 0;                   //清除触发寄存器
  124.     IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
  125.     IAP_ADDRL = 0;
  126. }
  127. /*----------------------------
  128. 从ISP/IAP/EEPROM区域读取一字节
  129. ----------------------------*/
  130. uchar IapReadByte(uint addr)
  131. {
  132.     uchar dat;                       //数据缓冲区

  133.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  134.     IAP_CMD = CMD_READ;             //设置IAP命令
  135.     IAP_ADDRL = addr;               //设置IAP低地址
  136.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  137.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  138.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  139.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  140.     dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
  141.     IapIdle();                      //关闭IAP功能
  142.     return dat;                     //返回
  143. }
  144. /*-------------------------------
  145. 写一字节数据到ISP/IAP/EEPROM区域
  146. --------------------------------*/
  147. void IapProgramByte(uint addr, uchar dat)
  148. {
  149.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  150.     IAP_CMD = CMD_PROGRAM;          //设置IAP命令
  151.     IAP_ADDRL = addr;               //设置IAP低地址
  152.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  153.     IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
  154.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  155.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  156.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  157.     IapIdle();                      //关闭IAP功能
  158. }
  159. /*----------------------------
  160. ISP/IAP/EEPROM扇区擦除
  161. ----------------------------*/
  162. void IapEraseSector(uint addr)
  163. {
  164.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  165.     IAP_CMD = CMD_ERASE;            //设置IAP命令
  166.     IAP_ADDRL = addr;               //设置IAP低地址
  167.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  168.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  169.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  170.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  171.     IapIdle();                      //关闭IAP功能
  172. }
  173. void PowerLost() interrupt 6
  174. {

  175.         EA = 0;                                                //关闭总中断
  176.         P0M1 = 0xff;                                //所有端口高阻
  177.         P1M1 = 0xff;
  178.         P2M1 = 0xff;
  179.         P3M1 = 0xff;
  180.         P4M1 = 0xff;
  181.         P5M1 = 0xff;
  182.         P6M1 = 0xff;
  183.         P7M1 = 0xff;
  184.         IapProgramByte(IAP_ADDRESS,hour);//写数据到EEPROM
  185.         IapProgramByte(IAP_ADDRESS+1,min);
  186.         IapProgramByte(IAP_ADDRESS+2,sec);
  187.         while((PCON & 0x20) != 0)         //复查低压标志
  188.         {
  189.                 PCON &= 0xDF;                  //清除低压标志
  190.                 _nop_();               
  191.                 _nop_();                            //坐等掉电
  192.         }
  193.         IAP_CONTR = 0x20;                 //发现是误报,重启单片机,恢复正常工作
  194. }
复制代码

评分

参与人数 1黑币 +5 收起 理由
tianqi911 + 5 绝世好帖!

查看全部评分

回复

使用道具 举报

ID:965189 发表于 2023-11-18 22:07 | 显示全部楼层
wulin 发表于 2023-11-18 17:06
这是一款掉电中断保存数据到EEPROM的测试程序,最长时间99小时59分59秒,修改后时间记录可以无限长。时钟源 ...

谢谢你的回复,我就是想利用一直运行的DS1302的秒信号进行计时,DS1302时钟不变。只是不知道怎样写可以利用到钞信号或者分信号。
回复

使用道具 举报

ID:353115 发表于 2023-11-18 23:00 | 显示全部楼层
可以利用MCU的低压中断,存储运行时间。下次上电读取运行时间,继续走时。
回复

使用道具 举报

ID:213173 发表于 2023-11-19 07:18 | 显示全部楼层
君工创 发表于 2023-11-18 22:07
谢谢你的回复,我就是想利用一直运行的DS1302的秒信号进行计时,DS1302时钟不变。只是不知道怎样写可以利 ...

一般读DS1302的周期小于1秒,当前读到DS1302的秒数与上一次读到DS1302的秒数比较,如相同则表示没有变化。不同则表示已走过1秒,保存当前秒数,为下一次比较判断做准备,累计数+1。采用分累计也是同理。
        if(sign!=sec)
        {
                sign=sec;
                s_count++;
        }
回复

使用道具 举报

ID:140275 发表于 2023-11-19 10:24 | 显示全部楼层
本帖最后由 1534545848 于 2023-11-23 07:28 编辑

;****************************************20150523--OK
JISHU0:        INC        48H                ;+1支

        MOV        A,48H
        ANL        A,#0FH
        CJNE        A,#10,RTN0        ;0--9支;;
        ANL        48H,#0F0H
        MOV        A,48H
        ADD        A,#10H
        MOV        48H,A
        ANL        A,#0F0H
        CJNE        A,#0A0H,RTN0        ;0--90支;;
        ANL        48H,#0FH
        INC        49H
        MOV        A,49H
        ANL        A,#0FH
        CJNE        A,#10,RTN0        ;0--900支;;
        ANL        49H,#0F0H
        MOV        A,49H
        ADD        A,#10H
        MOV        49H,A
        ANL        A,#0F0H
        CJNE        A,#0A0H,RTN0        ;0--9000支;;
        ANL        49H,#0FH
        INC        4AH
        MOV        A,4AH
        ANL        A,#0FH
        CJNE        A,#10,RTN0        ;0--90000支;;
        ANL        4AH,#0F0H
        MOV        A,4AH
        ADD        A,#10H
        MOV        4AH,A
        ANL        A,#0F0H
        CJNE        A,#0A0H,RTN0        ;0--900000支;;
        ANL        4AH,#0FH
        INC        4BH
        MOV        A,4BH
        ANL        A,#0FH
        CJNE        A,#10,RTN0        ;0--9000000支;;
        ANL        4BH,#0F0H
        MOV        A,4BH
        ADD        A,#10H
        MOV        4BH,A
        ANL        A,#0F0H
        CJNE        A,#0A0H,RTN0        ;0--90000000支;;
        ANL        4BH,#0FH
        INC        4CH
        MOV        A,4CH
        ANL        A,#0FH
        CJNE        A,#10,RTN0        ;0--900000000支;;
        ANL        4CH,#0F0H
        MOV        A,4CH
        ADD        A,#10H
        MOV        4CH,A
        ANL        A,#0F0H
        CJNE        A,#0A0H,RTN0        ;0--9000000000支;;
        ANL        4CH,#0FH

        RET
回复

使用道具 举报

ID:965189 发表于 2023-11-19 11:27 | 显示全部楼层
wulin 发表于 2023-11-19 07:18
一般读DS1302的周期小于1秒,当前读到DS1302的秒数与上一次读到DS1302的秒数比较,如相同则表示没有变化 ...

非常感谢你的指导,按照你的方法,成功了。之前不成功是因为在if(.......)前面保存sign=sec.照你的方法,只在if(){sign=sec;}的大括号内保存秒(sign=sec;).
回复

使用道具 举报

ID:883242 发表于 2023-11-19 16:53 | 显示全部楼层
wulin 发表于 2023-11-18 17:06
这是一款掉电中断保存数据到EEPROM的测试程序,最长时间99小时59分59秒,修改后时间记录可以无限长。时钟源 ...

1302自带NVRAM,根本就不需要EEPROM。
回复

使用道具 举报

ID:996773 发表于 2023-11-20 09:36 | 显示全部楼层
Hephaestus 发表于 2023-11-19 16:53
1302自带NVRAM,根本就不需要EEPROM。

说的对,1302自带电存储单元,可以像写入时钟数据一样存储字节,楼上显然没用过1302,不了解
回复

使用道具 举报

ID:1034262 发表于 2023-11-20 17:13 | 显示全部楼层
DS1302有SRAM,将开机时间存储在里面即可。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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