晶振两端负载电容等效串联的,你只在晶振一端加电容,一个电容容量再大也没多大作用,
还是老老实实按照晶振参 ...
X1端的电容很容易发生不起阵 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中。 梁工 发表于 2026-6-25 14:54
DS1302里面有SRAM的,记录最后校准的时间。
比如,2026-6-25校准了一次,然后关机。
大约6个月后,比如20 ...
太复杂了,太费脑子了{:ciya:} 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]