调试DS1302时遇到的问题

2020-02-02 09:28发布

这几天用DS1302,程序出来之后很不理想
先贴贴程序:
void WriteByte(uchar dat)
{
        uchar i;
        ACC=dat;
        for(i=8;i>0;i--)
        {
                Dat_1302=ACC0;
                CLK_1302=1;       
                _nop_();_nop_();_nop_();
                CLK_1302=0;        //产生上升沿输入数据
                ACC=ACC>>1;
        }       
}

void WriteSet1302(uchar Cmd,uchar dat)
{
        RST_1302=0;
        CLK_1302=0; //确保写数居前SCLK被拉低
        RST_1302=1; //启动数据传输
        WriteByte(Cmd);
        WriteByte(dat);
        RST_1302=0;
        CLK_1302=1;       
}

uchar ReadByte(void)
{
        uchar i;
        for(i=8;i>0;i--)
        {
                ACC7=Dat_1302;//ds1302读数据的时候,第一个数据读取在发一个Byte命令后,在第八位的下降沿
                ACC=ACC>>1;
                CLK_1302=1;
                CLK_1302=0;//产生下降沿输出一位数据
                _nop_();_nop_();_nop_();
        }
        return(ACC);
}

uchar ReadSet1302(uchar Cmd)
{
        uchar dat;
        RST_1302=0;
        CLK_1302=0; //确保写数居前SCLK被拉低
        RST_1302=1; //启动数据传输
        WriteByte(Cmd);
        dat=ReadByte();
        RST_1302=0;
        CLK_1302=1;
        return dat; //将读出的数据返回
}

void Init1302(void)
{
        WriteSet1302(0x8e,0x00);
        WriteSet1302(0x80,0x05);//初始化时分秒
        WriteSet1302(0x82,0x10);
        WriteSet1302(0x84,0x15);
        WriteSet1302(0x90,0xab);
        WriteSet1302(0x8e,0x80);
}
程序遇到的问题是读取时间时老是出错,有时候是秒的数据错了,有时候是分的数据,有时候是时间的数据
而且写进去时间后读出来的数据也有错
不知道是哪里的问题
在网上看了很多这方面的程序,感觉都没有错
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
24条回答
elecfun
1楼-- · 2020-02-03 03:10
本帖最后由 elecfun 于 2012-3-28 19:16 编辑

试试我这个 DS1302.H


//DS1302功能函数
// 51 @ 12MHz
//elecfun @ 2010-11-6
#ifndef _DS1302_
#define _DS1302_

sbit
DS1302_RST = P2^3;   //引脚定义,移植请修改此处
sbit DS1302_CLK = P2^4;   //
sbit DS1302_DAT = P2^5;   //

#define DS1302_SECOND   0x80
#define DS1302_MINUTE   0x82
#define DS1302_HOUR         0x84
#define DS1302_WEEK         0x8A
#define DS1302_DAY         0x86
#define DS1302_MONTH    0x88
#define DS1302_YEAR         0x8C

#define BCD2DEC(X)     (((X&0x70)>>4)*10 + (X&0x0F))     //用于将BCD码转成十进制的宏
#define DEC2BCD(X)     ((X/10)<<4 | (X%10))               //用于将十进制转成BCD码的宏

typedef struct
__SYSTEMTIME__
{

    unsigned char
Second;
    unsigned char
Minute;
    unsigned char
Hour;
    unsigned char
Week;
    unsigned char
Day;
    unsigned char
Month;
    unsigned char
Year;
}
SYSTEMTIME;     //定义的时间类型



/*********************************************************************************************
函数名:DS1302写字节函数
调  用:DS1302_WriteByte(uchar);
参  数:需要写入的数据
返回值:
备  注:内部函数
/**********************************************************************************************/

void
DS1302_WriteByte(unsigned char wByte)
{

    unsigned char
i=0;
    for
(i=0; i<8; i++) {
        if
(wByte & 0x01)
            DS1302_DAT = 1;
        else

            DS1302_DAT = 0;

        DS1302_CLK = 1;
        DS1302_CLK = 0;

        wByte >>= 1;
    }
}


/*********************************************************************************************
函数名:DS1302读字节函数
调  用:uchar DS1302_ReadByte();
参  数:
返回值:读出的一个字节
备  注:内部函数
/**********************************************************************************************/

unsigned char
DS1302_ReadByte(void)
{

    unsigned char
i=0,result=0;
    DS1302_DAT = 1;
    for
(i=0; i<8; i++) {
        if
(DS1302_DAT == 1)
            result |= (0x01<<i);

        DS1302_CLK = 1;
        DS1302_CLK = 0;
    }

    DS1302_DAT = 0;
    return
(result);
}


/*********************************************************************************************
函数名:DS1302读字节函数
调  用:uchar DS1302_ReadData(uchar);
参  数:指定的地址
返回值:读出指定地址的一个字节数据
备  注:
/**********************************************************************************************/
     
unsigned char
DS1302_ReadData(unsigned char rAdd)
{

    unsigned char
rDat=0;

    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    DS1302_WriteByte(rAdd);       //写地址
    rDat = DS1302_ReadByte();     //读数据
    DS1302_RST = 0;
    DS1302_CLK = 1;
    return
(rDat);
}


/*********************************************************************************************
函数名:DS1302写字节函数
调  用:DS1302_WriteData(uchar,uchar);
参  数:指定的地址,指定的数据
返回值:
备  注:
/**********************************************************************************************/
     
void
DS1302_WriteData(unsigned char wAdd, unsigned char wDat)
{

    DS1302_CLK = 0;
    DS1302_RST = 0;
    DS1302_RST = 1;
    DS1302_WriteByte(wAdd);       //写地址
    DS1302_WriteByte(wDat);       //写数据
    DS1302_RST = 0;
    DS1302_CLK = 1;
}


/*********************************************************************************************
函数名:DS1302读数据函数
调  用:DS1302_GetTime_ALL(SYSTEMTIME);
参  数:存储数据的SYSTEMTIME结构体
返回值:
备  注:
/**********************************************************************************************/

void
DS1302_GetTime_ALL(SYSTEMTIME *Time)
{

    unsigned char
ReadValue;
    ReadValue = DS1302_ReadData(DS1302_SECOND+1);
    Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_ReadData(DS1302_MINUTE+1);
    Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_ReadData(DS1302_HOUR+1);
    Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_ReadData(DS1302_DAY+1);
    Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);     
    ReadValue = DS1302_ReadData(DS1302_WEEK+1);
    Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_ReadData(DS1302_MONTH+1);
    Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_ReadData(DS1302_YEAR+1);
    Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);     
}


/*********************************************************************************************
函数名:DS1302设置时间数据函数
调  用:DS1302_SetTime(uchar, uchar);
参  数:存储数据的SYSTEMTIME结构体
返回值:
备  注:
/**********************************************************************************************/

void
DS1302_SetTime(unsigned char sADD, unsigned char sDAT)
{

    DS1302_WriteData(0x8e,0x00);          //关闭写保护

    DS1302_WriteData(sADD,DEC2BCD(sDAT));
    /*DS1302_WriteData(DS1302_MONTH,DEC2BCD(Time->Month));
    DS1302_WriteData(DS1302_WEEK,DEC2BCD(Time->Week));
    DS1302_WriteData(DS1302_DAY,DEC2BCD(Time->Day));
    DS1302_WriteData(DS1302_HOUR,DEC2BCD(Time->Hour)|Time_24_Hour);
    DS1302_WriteData(DS1302_MINUTE,DEC2BCD(Time->Minute));
    DS1302_WriteData(DS1302_SECOND,DEC2BCD(Time->Second)|Time_Start);*/

    DS1302_WriteData(0x8e,0x80);          //打开写保护     
}

/*********************************************************************************************
函数名:DS1302辅助设置日期函数
调  用:unsigned char DS1302_GetTheDay();
参  数:
返回值:当月总天数
备  注:自动读取DS1302内部年、月,并计算当月总天数
/**********************************************************************************************/

unsigned char
DS1302_GetTheDay(void)
{

    unsigned char
tYear,tMonth;

    tYear = BCD2DEC(DS1302_ReadData(DS1302_YEAR+1));  //当前年
    tMonth = BCD2DEC(DS1302_ReadData(DS1302_MONTH+1));//当前月
    switch (tMonth)
    {

    case
1:
    case
3:
    case
5:
    case
7:
    case
8:
    case
10:
    case
12:return 31;  //1、3、5、7、8、10、12 月均为31天
    case 4:
    case
6:
    case
9:
    case
11:return 30;  //4、6、9、11 月均为30天
    case 2:            
        if
(tYear%4 == 0) //2月闰年为29天
            return 29;
        else
            return
28;  //平年为28天
    default:    return 0;
    }
}


/*********************************************************************************************
函数名:DS1302初始化函数
调  用:Init_DS1302();
参  数:存储数据的SYSTEMTIME结构体
返回值:
备  注:
/**********************************************************************************************/

void
Init_DS1302(void)                        //-设置1302的初始时间(2007年1月1日00时00分00秒星期一)
{
    unsigned char
i;
    if
(DS1302_ReadData(0xc1) != 0x10){
        DS1302_WriteData(0x8e,0x00);        //允许写操作
        DS1302_WriteData(0x8c,0x10);        //年
        DS1302_WriteData(0x8a,0x04);        //星期
        DS1302_WriteData(0x88,0x07);        //月
        DS1302_WriteData(0x86,0x01);        //日
        DS1302_WriteData(0x84,0x12);        //小时
        DS1302_WriteData(0x82,0x00);        //分钟
        DS1302_WriteData(0x80,0x00);        //秒
        DS1302_WriteData(0x90,0xACC5);      //充电     
        DS1302_WriteData(0xc0,0x10);        //写入初始化标志RAM(第00个RAM位置)
        for(i=0; i<60; i+=2){              //清除闹钟RAM位为0
            DS1302_WriteData(0xC2+i,0x00);
        }

        DS1302_WriteData(0x8E,0x80);        //禁止写操作
    }
}

#endif
millwood0
2楼-- · 2020-02-03 03:23
       ACC=dat;


anyone writing that kind of code has no business writing code at all.
caiden_chen
3楼-- · 2020-02-03 03:39
检查读取过程有没有被中断 检查时序
BXAK
4楼-- · 2020-02-03 08:46
 精彩回答 2  元偷偷看……
caiden_chen
5楼-- · 2020-02-03 11:53
BXAK 发表于 2012-3-28 20:07
不同于DS18B20单总线,
DS1302的时序是不受中断影响的

其实我说的是两个问题. 一个是有没有中断, 另一个是时序对不对.  
我的意思是:先检查中断 如果确认没有中断影响的话 则进一步检查时序(因为程序时序问题可能性小一些 而中断容易被忽视. 注意同样晶振频率 在不同51内核的单片机不一样,所以参考已有的程序时要注意,不要照搬)

另外, 你说"DS1302的时序是不受中断影响" 可能吗?  实际上,读写DS1302的接口是软件实现的,当然会有影响. 比如说中断处理时间太长,或者外部中断没处理好,造成本应只中断一次的却反复中断多次,能没影响吗
BXAK
6楼-- · 2020-02-03 14:45
caiden_chen 发表于 2012-3-28 21:55
其实我说的是两个问题. 一个是有没有中断, 另一个是时序对不对.  
我的意思是:先检查中断 如果确认没有中 ...

我做的一个带时钟遥控开关,
解码用定时器中断查询方式,定时器每256us频繁中断,
不关中断读取DS1302没发现什么问题

定时器每100us频繁中断解码时,读取DS1302也没发现什么问题