xiaobendan 发表于 2026-6-25 12:26:19

网老四 发表于 2026-6-25 12:12
晶振两端负载电容等效串联的,你只在晶振一端加电容,一个电容容量再大也没多大作用,
还是老老实实按照晶振参 ...

X1端的电容很容易发生不起阵

梁工 发表于 2026-6-25 14:54:23

xiaobendan 发表于 2026-6-25 11:37
但是很大可能板子几个月都不通电啊,咋办

DS1302里面有SRAM的,记录最后校准的时间。
比如,2026-6-25校准了一次,然后关机。
大约6个月后,比如2026-12-30-12:34:56开机,检测到连续188天没有校准过。
假设10天快45秒,则188天快了846秒=14分6秒,计算好时间为12:20:50,写入DS1302。
同时将2026-12-30写入DS1302的SRAM中。

xiaobendan 发表于 2026-6-25 15:52:52

梁工 发表于 2026-6-25 14:54
DS1302里面有SRAM的,记录最后校准的时间。
比如,2026-6-25校准了一次,然后关机。
大约6个月后,比如20 ...

太复杂了,太费脑子了{:ciya:}

wulin 发表于 2026-6-25 17:24:22

xiaobendan 发表于 2026-6-25 15:52
太复杂了,太费脑子了
长时间断电可以利用单片机低压中断将掉电时的日期保存在DS1302的RAM,待下次上电,用当前日期减上次掉电的日期得到断电天数,再乘以日误差,再用此误差值修正DS1302当前时间。给你一个低压中断保存数据在DS1302的RAM中的示例,稍加修改即可套用。
//测试条件:STC8H实验板,MCU型号STC8H3K48S2
//注意:测试本示例时,需在ISP下载时将【允许低
//压复位(禁止低压中断)】关闭,低压检测电压选3V以上
#include "stc8h.h"            
#include "intrins.h"
typedef unsigned charu8;
typedef unsigned int   u16;
typedef unsigned longu32;

sbit SCLK = P5^0;             //DS1302时钟
sbit DSIO = P5^1;             //DS1302数据
sbit REST = P5^2;             //DS1302复位
sbit key1 = P3^3;             //按键1 设置
sbit key2 = P3^2;             //按键2 加
sbit key3 = P3^1;             //按键3 减
sbit key4 = P3^0;             //按键4 读RAM
//DS1302读取和写入时分秒的地址命令---//
u8code READ_RTC_ADDR = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; //DS1302读时钟地址/命令
u8code WRITE_RTC_ADDR= {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //DS1302写时钟地址/命令
//u8code READD_RAM[]={0xc1,0xc3,0xc5,0xc7,0xc9,0xcb,0xcd,......0xfd};//31字节读RAM地址/命令
//u8code WRITE_RAM[]={0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,......0xfc};//31字节写RAM地址/命令
//日历缓存   顺序是秒,分,时,日,月,周,年,格式十进制
char data TIME[]={ 30,30,12, 1, 1, 2,24};
u8 code table[]={
      0x3f,0x06,0x5b,0x4f,
      0x66,0x6d,0x7d,0x07,
      0x7f,0x6f,0x77,0x7c,
      0x39,0x5e,0x79,0x71};
u8 data LED_buf;         //数码管显存
bit B_1ms;                  //1ms标志
bit flag;                     //标志
u8Key_value;                //键值
u8temp;                     //临时
u8rama,ramb;                //缓冲
u16 num;                      //测试变量
u16 count;                  //计数
bit flicker;                  //闪烁
//DS1302操作函数声明*****************************************
void Ds1302Write(u8 addr, u8 dat);//向1302芯片写入地址和数据
u8   Ds1302Read(u8 addr);   //从1302读数据
void Ds1302ReadTime();      //读取秒分时日月周年信息
void Ds1302Init();            //DS1302初始化
u8   BCD_D(u8 bcd);         //BCD码转十进制函数
u8   D_BCD(u8 Dec);         //十进制转BCD码函数
void Timer0_Init();                        //1毫秒@11.0592MHz
void display();               //显示函数
void key_scan();            //按键扫描
void McuInit();               //初始化端口模式
void McuSleep();            //端口高阻模式
void Delay100ms();            //延时函数
//主函数
void main()
{      
      McuInit();
      Ds1302Init();
      Delay100ms();
      rama=Ds1302Read(0xc1);    //读取RAM中保存的数据
      ramb=Ds1302Read(0xc3);    //读取RAM中保存的数据
      num=rama<<8|ramb;         //合并字节
      PCON &= 0xDF;             //清0掉电标志
      ELVD = 1;               //开低压中断
      EA   = 1;               //开总中断
      Timer0_Init();
      while(1)
      {
                if(B_1ms)             //1ms到
                {
                        B_1ms = 0;
                        display();      //数码管显示
                        if(Key_value==0)Ds1302ReadTime();//读取Ds1302时间信息
                        if(temp!=TIME)
                        {
                              temp=TIME;                //秒更新
                              if(++num>999)num=0;          //测试数据
                              flicker=0;                   //秒点复位
                              count=0;                     //计数复位
                        }
                        LED_buf=table/10];    //时十位
                        if(flicker)LED_buf=table%10];//时个位
                        elseLED_buf=table%10]|0x80;//时个位+秒点
                        LED_buf=table/10];    //分十位
                        LED_buf=table%10];    //分个位
                        LED_buf=0x40;               //"-"
                        LED_buf=table;    //测试数百位
                        LED_buf=table;   //测试数十位
                        LED_buf=table;      //测试数个位
                        key_scan();                      //按键扫描
                }
      }
}
//T0中断服务函数
void Timer0_Isr(void) interrupt 1
{
      B_1ms=1;
      if(++count>=500)
                flicker=1;                //闪烁
      if(count%100==0)
                flag=~flag;               //快闪
}

void PowerLost() interrupt 6      //低压中断
{
      EA = 0;                     //关闭总中断
      TR0= 0;
      McuSleep();                   //关闭所有不用端口,保留连接Ds1302的端口
      Ds1302Write(0x8e,0x00);       //禁止写保护功能
      Ds1302Write(0xc0,num>>8);   //写num高8位
      Ds1302Write(0xc2,num);      //写num低8位      
      Ds1302Write(0x8e,0x80);       //打开写保护功能
//      P5M0 = 0x00; P5M1 = 0xff;   //关闭连接Ds1302的端口
      while((PCON & 0x20) != 0)   //复查低压标志
      {
                PCON &= 0xDF;             //清除低压标志
                _nop_();               
                _nop_();                  //坐等掉电
      }
      IAP_CONTR = 0x20;             //发现是误报,重启单片机,恢复正常工作
}

void Timer0_Init(void)                      //1毫秒@11.0592MHz
{
      AUXR |= 0x80;                              //定时器时钟1T模式
      TMOD &= 0xF0;                              //设置定时器模式
      TL0 = 0xCD;                                    //设置定时初始值
      TH0 = 0xD4;                                    //设置定时初始值
      TF0 = 0;                                    //清除TF0标志
      TR0 = 1;                                    //定时器0开始计时
      ET0 = 1;                                    //使能定时器0中断
}

//==============DS1302驱动部分=====================
//写1302时钟数据
void Ds1302Write(u8 addr, u8 dat)
{
      u8 i;
      REST= 1;
      for(i=0;i<8;i++)      //写地址/命令
      {
                DSIO=addr & 0x01;   //数据由低位到高位传送
                addr>>=1;
                SCLK = 1;         //数据在上升沿时,DS1302读取数据
                SCLK = 0;
      }
      for(i=0;i<8;i++)      //写数据
      {
                DSIO=dat & 0x01;
                dat>>= 1;
                SCLK = 1;         //数据在上升沿时,DS1302读取数据
                SCLK = 0;      
      }               
      REST = 0;               //传送数据结束      
}
//读1302时钟数据
u8 Ds1302Read(u8 addr)
{
      u8 i,dat,dat1;
      REST = 1;
      for(i=0; i<8; i++)      //开始传送八位地址命令
      {
                DSIO = addr & 0x01; //数据由低位到高位传送
                addr >>= 1;
                SCLK = 1;         //数据在上升沿时,DS1302读取数据
                SCLK = 0;
      }
      for(i=0;i<8;i++)      // 读取8位数据
      {
                dat1 = DSIO;      // 从最低位开始接收
                dat=(dat>>1)|(dat1<<7);
                SCLK = 1;
                SCLK = 0;         // 下降沿有效,读取DS1302数据
      }
      REST = 0;
      DSIO = 0;
      return dat;      
}
//初始化DS1302
void Ds1302Init()
{
//      u8 i;
      REST = 0;
      SCLK = 0;
      DSIO = 0;      
      Ds1302Write(0x8E,0x00);   // 禁止写保护功能
//      for(i=0;i<7;i++)          // 写入7个字节的时钟信号:分秒时日月周年
//                Ds1302Write(WRITE_RTC_ADDR,D_BCD(TIME));      
      Ds1302Write(0x8E,0x80);   // 打开写保护功能
}
//读取时钟信息
void Ds1302ReadTime()
{
      u8 i;
      for(i=0;i<3;i++)          //读取3个字节的时钟信号:秒分时
                TIME=BCD_D(Ds1302Read(READ_RTC_ADDR));//BCD转换成十进制保存
}
//BCD码转十进制函数
u8 BCD_D(u8 bcd)
{
      return ((bcd>>4)*10)+(bcd & 0x0f);
}
//十进制转BCD码函数,返回BCD码
u8 D_BCD(u8 Dec)
{
      return (Dec/10*16+Dec%10);
}
//数码管动态显示函数
void display()
{
      static u8 j;                  //循环计数变量
      P0=0x00;                      //消隐
      P2=~(0x01<<j);                //送位码      
      if(Key_value==1 && flag &&(j==0||j==1))
                P0=0x00;                  //消隐
      else if(Key_value==2 && flag &&(j==2||j==3))
                P0=0x00;                  //消隐
      else P0=LED_buf;         //送段码不加点
      j=++j%8;                      //循环计数
}
//按键扫描函数

void key_scan()
{
      static bit key_sign=0;//按键状态标志
      static u8 count=0;    //消抖计数
      u8 i;
      if(!key1||!key2||!key3||!key4)
      {
                if(++count>=10 && key_sign==0)
                {
                        key_sign=1;
                        if(!key1)
                        {
                              Key_value=++Key_value%3;
                              if(Key_value==0)
                              {
                                        Ds1302Write(0x8e,0x00);   // 禁止写保护功能
                                        TIME=0;
                                        for(i=0;i<3;i++)          // 写入3个字节的时钟信号:分秒时
                                                Ds1302Write(WRITE_RTC_ADDR,D_BCD(TIME));      
                                        Ds1302Write(0x8e,0x80);   // 打开写保护功能
                              }
                        }
                        if(!key2)
                        {
                              if(Key_value==1)
                              {
                                        TIME++;
                                        if(TIME>23)TIME=0;
                              }
                              if(Key_value==2)
                              {
                                        TIME++;
                                        if(TIME>59)TIME=0;
                              }
                        }
                        if(!key3)
                        {
                              if(Key_value==1)
                              {
                                        TIME--;
                                        if(TIME<0)TIME=23;
                              }
                              if(Key_value==2)
                              {
                                        TIME--;
                                        if(TIME<0)TIME=59;
                              }
                        }
                        if(!key4)
                        {
                              rama=Ds1302Read(0xc1);//读取RAM中保存的数据
                              ramb=Ds1302Read(0xc3);//读取RAM中保存的数据
                              num=rama<<8|ramb;
                        }
                }
      }
      else
      {
                key_sign=0;
                count=0;
      }
}
//初始化单片机端口
void McuInit()
{
      P0M0 = 0xff; P0M1 = 0x00;//推挽模式
      P1M0 = 0x00; P1M1 = 0x00;//准双向模式
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x00; P3M1 = 0x00;
      P4M0 = 0x00; P4M1 = 0x00;
      P5M0 = 0x00; P5M1 = 0x00;
      P6M0 = 0x00; P6M1 = 0x00;
      P7M0 = 0x00; P7M1 = 0x00;
}
//设置单片机端口省电
void McuSleep()
{
      P0M0 = 0x00; P0M1 = 0x00;//准双向模式
}
void Delay100ms(void)      //@11.0592MHz
{
      unsigned char data i, j, k;

      _nop_();
      i = 6;
      j = 157;
      k = 59;
      do
      {
                do
                {
                        while (--k);
                } while (--j);
      } while (--i);
}


页: 1 [2]
查看完整版本: 弄了一个比较贵的说是原装的DS1302换上了