java89vc 发表于 2011-3-28 21:25:53

STC89C52读取DS1302的问题,各位高手救命啊!俺都搞了一个礼拜了不成功啊!!!

俺的程序如下,麻烦各位有经验的兄弟帮我看看我的程序有没有问题啊,我检查N次了实在找不出那里错了,但下载到板子上数码管上一直显示 02实在不知道怎么办了,现在搞的我对学习单片机都快没兴趣了,(我的DS1302上接的电容是30pf的应该对读数据没影响吧,各位先帮我看看程序有没有问题,没问题我就去买个DS1302再试试),麻烦各位别贴程序给我看了,我已经在网上看了够多程序了我只是想让大家帮我看下我的写入函数还有读出函数有没有错误啊,如果程序没错的话我就去买DS1302了,麻烦大家了我只有初中学历学起来不容易大家别喷啊!!!(我这里只是暂时写个秒位和数码管显示秒位,其他时 分 先不管,我在百度发帖子也问不出个所以然来都是复制粘贴给我看,我好郁闷啊)

                                                                                               
                                                                                                               
#include<reg52.h>
#define wp 0x8e      //0x8e是写保护寄存器的地址
#define xie_shi 0x84   // 0x84是小时(写寄存器)的地址
#define xie_fen 0x82      // 0x82是分钟(写寄存器)的地址
#define xie_miao 0x80   // 0x80是秒位(写寄存器)的地址

#define du_shi 0x85// 0x85是小时(读寄存器)的地址
#define du_fen 0x83// 0x83是分钟(读寄存器)的地址
#define du_miao 0x81 // 0x81是秒位(读寄存器)的地址



/**************************************************************************************/

sbit RST=P3^7;// 片选
sbit SCLK=P3^5;// 时钟线
sbit IO=P3^4;    // 数据线
sbit ACC0=ACC^0;// 使用ACC来保存读出来的数据
sbit ACC7=ACC^7;
sbit leda=P1^4;   // 秒LED的高位
sbit ledb=P1^5;   // 秒LED的低位

/******************************************************************************************/
void int1302(); // 声明初始化函数
void xieds1302(unsigned char dizhi,shuju);//声明写DS1302函数
unsigned char duds1302(unsigned char dizhi);   //声明读DS1302函数
void display(unsigned char num);   // 声明显示函数
void delay(unsigned char xms);    // 声明延迟函数

unsigned char code table[]=       //数码管显示数组(共阳极)0-9
{
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90
};
/****************************************************************************************/


// 主函数体
void main()
{
        unsigned char k_1,k_2,k_3,shi_gao,shi_di,fen_gao,fen_di,miao_gao,miao_di,kkk;   // 定义变量用于存储时,分,秒
        int1302();   //初始化DS1302
        while(1)
        {
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

       kkk=duds1302(du_miao);/// 0X81 0X83 0X85 是时分 秒的读地址
       k_1=kkk;   // 把ACC中的值取出来方便下次使用
       k_2=kkk;   // 把ACC中的值取出来方便下次使用

            miao_gao=k_1>>4;
                      miao_di=k_2&0x0f;

       display(miao_gao);// 显示秒高位   
       leda=0;
       delay(5);
       leda=1;
        display(miao_di);// 显示秒低位      
        ledb=0;
       delay(5);
        ledb=1;
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
        }


}

// 初始化函数

void int1302()
{
       xieds1302(wp,0x00);//0x8e是控制寄存器地址,此句是取消写保护
       xieds1302(xie_shi,0x23);// 小时位初试化,初始化值为0X23=0010 0011 也就是23点
       xieds1302(xie_fen,0x30);// 分钟初始化,初始化值为 0X30=0011 0000   也就是30分
       xieds1302(xie_miao,0X44);// 秒位初始化,初始化值为 0X00=0100 0100也就是44秒。同时CH为0表示启动时钟振荡器
       xieds1302(wp,0x80);//0x80此句是重新启用写保护
}


// 写DS1302函数------------先送地址再送数据********DS1302默然先发送的头八位是地址字符,后八位才是数据

void xieds1302(unsigned char dizhi,shuju)
{
        unsigned char i,j;
        SCLK=0;    // 时钟线为0
        RST=0;   // 片选为0
        RST=1;   // 片选为1准备发送地址,主要是RST在置1之前时钟线必须为低电平所以SCLK才先为0再RST为1
   

        for(i=0;i<8;++i)   // 发送地址(前八位发送的是地址控制字)
        {
                ACC=dizhi;
                IO=ACC0;
                SCLK=0;
                SCLK=1;    // 模拟上升沿
                ACC=ACC>>1;   // ACC右移一位等待下次循环发送出去

        };

        for(j=0;j<8;++j)    //发送数据
        {
                ACC=shuju;
                IO=ACC0;
                SCLK=0;
                SCLK=1;    // 模拟上升沿
                ACC=ACC>>1;   // ACC右移一位等待下次循环发送出去


        }
    RST=0;    // 发送数据结束

}


// 读DS1302函数------------先送地址再送数据********DS1302默然先发送的头八位是地址字符,后八位才是数据


unsigned char duds1302(unsigned char dizhi)
{
        unsigned char i,j;
        SCLK=0;    // 时钟线为0
        RST=0;   // 片选为0
        RST=1;   // 片选为1准备发送地址,主要是RST在置1之前时钟线必须为低电平所以SCLK才先为0再RST为1
   

        for(i=0;i<8;++i)   // 发送地址(前八位发送的是地址控制字)
        {
                ACC=dizhi;
                IO=ACC0;
                SCLK=0;
                SCLK=1;    // 模拟上升沿
                ACC=ACC>>1;   // ACC右移一位等待下次循环发送出去
               
        }
        ACC=0X00;
        for(j=0;j<8;++j)    //接受数据
        {
          
                ACC=ACC>>1;
                IO=1;
                               
                SCLK=0;

                ACC7=IO;
                SCLK=1;
               
       

        }
        RST=0;    // 发送数据结束
        return ACC;
   

}
// 显示函数
void display(unsigned char num)
{
        P0=table;
}

// 延迟函数
void delay(unsigned char xms)
{
        unsigned char i,j;
        for(i=xms;i>0;i--)
        {
                for(j=110;j>0;j--)
                {}
        }

}

hujian228 发表于 2011-3-28 21:41:54

数据和时钟10K电阻上拉做了吗

wanghuan8928 发表于 2011-3-28 21:45:47

回复【楼主位】java89vc
-----------------------------------------------------------------------

加我Q********,我帮你看看,给我点时间。

站长阿莫提示:本论坛不提倡使用QQ等私下沟通技术问题,也禁止QQ群讨论。我们这里的资料,不是天

上掉下来的,是大家的无私贡献才有今天的成就。

java89vc 发表于 2011-3-28 22:09:47

上拉都有的,我是用买的学习板调式的,我现在就是想让大家帮忙看看我的程序有没有错误,我心里没底调式了很久了。http://cache.amobbs.com/bbs_upload782111/files_37/ourdev_626288I1JC21.JPG
我学习板中DS1302的电路图 (原文件名:未命名.JPG)

LM1876 发表于 2011-3-28 23:48:49

我的DS1302程序模块,给你参考下,STC89系列通过,晶振两边的电容不能乱加的,会影响精度。对1302的读不能太频繁,写就更不能太快,1302不是很便宜吗?买他十几片不就得了?我第一次搞坏1302就是因为读写得太频繁。

/******************初始化工作状态**************************/
void ds1302_init()
{
    T_RST=0;
    T_CLK=0;
        write_1302(0x80,0x00);        //写秒寄存器,上电振荡器工作允许
        write_1302(0x90,0x00);        //写涓流控制,不允许涓流充电
   in_1302_time(0x80,ds1302_time,7);
}

void TIME_Update()
{
if (time_count)      
   {
      time_count--;
      return;
   }
   
time_out();
time_count=3;
}



/*****************DS1302:写入操作(上升沿)*********************/
void write_byte(unsigned char da)
{
   unsigned char i;
   ACC=da;
   for(i=8;i>0;i--)
   {
      T_IO=ACC0;
          T_CLK=0;   
      T_CLK=1;
      ACC=ACC>>1;
   }
}

/*****************DS1302:读取操作(下降沿)*****************/
unsigned char read_byte(void)
{
   unsigned char i;
   for(i=0;i<8;i++)
   {
      ACC=ACC>>1;
          T_CLK = 1;
          T_CLK = 0;
      ACC7 = T_IO;
   }
   return(ACC);

}

/*****************DS1302:写入数据(先送地址,再写数据)***************************/
void write_1302(unsigned char addr,unsigned char da)
{
   T_RST=0;   
   T_CLK=0;                                 
   T_RST=1;   //重新工作
   write_byte(addr);    //写入地址
   
   write_byte(da);
   T_RST=0;
   T_CLK=1;
}

/******************DS1302:读取数据(先送地址,再读数据)**************************/
unsigned char read_1302(unsigned char addr)
{
   unsigned char temp;
   T_RST=0;            
   T_CLK=0;
   T_RST=1;            //重新工作
   write_byte(addr);   //写入地址
   temp=read_byte();
   T_RST=0;
   T_CLK=0;   
   return(temp);
}


/******************设1302初始时**************************/
void in_1302_time(unsigned char addr,unsigned char *p,unsigned char n)
{
   write_1302(0x8e,0x00);//写控制,寄存器能够写入
   for(;n>0;n--)
   {
          write_1302(addr,*p);
       p++;
       addr=addr+2;
   }
   write_1302(0x8e,0x00);//写控制,寄存器不能够写入
}

/******************读取当前时间**************************/
void out_1302time(unsigned char addr,unsigned char *p,unsigned char n)
{

for(;n>0;n--)
   {
      *p=read_1302(addr);
       p++;
      addr=addr+2;
   }
}




/**************显示绶冲**********/
void time_disbuf(unsigned char *p)       
{       
    Year_H=((*(p+6)&0xf0)>>4);          //十年
    Year_L=(*(p+6)&0x0f);          //年个位
    Month_H=((*(p+4)&0xf0)>>4);      //十月
    Month_L=(*(p+4)&0x0f);      //月个位
    //Week=;          //星期
    Day_H=((*(p+3)&0xf0)>>4);         //十天
    Day_L=(*(p+3)&0x0f);         //天
    Hour_H=((*(p+2)&0xf0)>>4);   //十小时
    Hour_L=(*(p+2)&0x0f);   //小时
    Minute_H=((*(p+1)&0xf0)>>4);   //十分
    Minute_L=(*(p+1)&0x0f);   //分
    Second_H=(*(p)&0x0f>>4);       //十秒
    Second_L =(*(p)&0x0f );//秒
       
}



void time_out()
{
out_1302time(0x81,ds1302_time,7);
time_disbuf(ds1302_time);
}

java89vc 发表于 2011-3-29 00:12:14

我麻烦你们帮我看看我的程序那里出错了可以吗?我现在就是想搞明白我的思路那里搞错了,麻烦你门了!

xivisi 发表于 2011-3-29 00:14:16

用串口输出 调试信息吧 这样辅助调试

armok 发表于 2011-3-29 00:37:47

millwood0 发表于 2011-3-29 07:50:28

"我现在就是想搞明白我的思路那里搞错了"

you have no clue about programming, particularly modular programming.

what you are are a few routines:

1) i2c routines: that read from / write to the i2c bus. they work with any i2c compliant devices and can be used somewhere else.

2) ds1302 low-level routines: that read from / write to a given address in ds1302,using the i2c routines above.

3) ds1302 high-level routines that read / write seconds / minutes / hours / etc. to ds1302, using the above ds1302 low-level routines.

4) display routines that have nothing to do with the above.

once you have the code structured like this, you can debug them independently, and reuse them in the future. and if you change devices or peripherals, you can swap out the correct routines and recompile and your code will work, with confidence.

for example, here is a section of my low-level ds323x routine:

==========================

//send byte to ch on ds1307
void ds323x_write(unsigned char ch, unsigned char byte_t) {
        i2c_start();
        i2c_write(DS323x_ID | DS323x_WRITE);         //send the device id+write command
        i2c_write(ch);
        i2c_write(byte_t);
        i2c_stop();
}
==========================

the i2c_start(), i2c_write() and i2c_stop() are i2c routines.

the above code writes byte_t to a given address in ds323x.

and here is my high level ds323x routine (a macro in this particular case) that writes minutes to ds323x:

============================

//write / read minutes
#define ds323x_min_write(val)        ds323x_write(DS323x_MIN, DEC2BCD(val))
============================

it takes value "val", converts it to BCD and then writes to address DS323x_MIN using the low-level ds323x routine ds323x_write().

using this approach, I can reuse code that I have developed before, knowing that they would work out of the box. I can write brand new code to a new device in a matter of minutes. and if I were to move the code to a chip and wish to use hardware i2c, all I need to do is to swap in my hardware i2c routines and recompile. and the code will work right away.

learning the right way to code is very very important for a programmer.

oufuqiang 发表于 2011-3-29 08:10:50

DS1302初学者代码,仅116行,实现时、分、秒的显示及调整。
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4465520&bbs_page_no=1&search_mode=3&search_text=oufuqiang&bbs_id=9999

lystone0001 发表于 2011-3-29 10:22:42

我的ds1302时间走得特别快 不知是什么原因,求解?

LM1876 发表于 2011-3-29 15:41:26

不是晶振问题就是晶振两边电容/

java89vc 发表于 2011-3-29 20:21:16

谢谢楼上的几位了,难道就没人愿意帮帮新人,帮我看下程序那里出错了吗?好悲剧

oufuqiang 发表于 2011-3-30 08:21:09

不要用ACC,会出很奇怪的问题的。

IO=ACC0;
SCLK=0;
SCLK=1;    // 模拟上升沿
ACC=ACC>>1;   // ACC右移一位等待下次循环发送出去

改成:
IO=shuju&0x01;
试试。

xjjiang 发表于 2011-3-30 08:26:07

楼主写入开启时钟后晶振真的起振了吗,示波器是否有量过?

java89vc 发表于 2011-3-30 23:59:29

问题解决了,我重新写了一遍,程序如下:
但我很不明白,在读函数时 fpr循环写成这样就可以   for(i=8;i>0;i--)    ,写成这样就不能正常显示只能显示00 for(i=0;i<8;i++),麻烦哪位大哥能帮我解释下吗,都是循环8次为什么i=8就可以i=0就不行啊!!!!!! 我新写的程序如下

#include<reg52.h>
#define uchar unsigned char

sbit rst=P3^7;
sbit clk=P3^5;
sbit io=P3^4;
sbit led0=P1^4;
sbit led1=P1^5;
sbit ACC0=ACC^0;
sbit ACC7=ACC^7;

uchar read1302(uchar add);
void write1302(uchar add,uchar data0);
void delay(unsigned char a);

unsigned char table[]=
{0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90};         //0~~9段码

void main()
{
    write1302(0x8e,0x00);
    write1302(0x80,0x00);
    write1302(0x82,0x00);
    write1302(0x84,0x00);
    write1302(0x8e,0x80);


        while(1)
        {
                uchar temp;
                   temp=read1302(0x81);
               
                P0=table;
                   led1=0;
                   delay(10);
                   led1=1;
   

                   P0=table;
                   led0=0;
                   delay(10);
                   led0=1;
        }
}
//*************************************
uchar read1302(uchar add)
{
        uchar i,j,temp;
        rst=0;
        clk=0;
        rst=1;
    ACC=add;
        for(i=8;i>0;i--)
        /********************************
//        for(i=0;i<8;i++)                                 有问题这个
/***************************************************************
        {
                io=ACC0;
                clk=0;
                clk=1;
                ACC=ACC>>1;


        };
    for(j=0;j<8;++j)
       {
          ACC=ACC>>1;
          clk=1;
          clk=0;
          ACC7=io;

      }
      temp=ACC;
      rst=0;
//clk=1;
      return(temp);
      




}
void write1302(uchar add,uchar data0)
{
        uchar i,j;
      rst=0;
        clk=0;
        rst=1;
        ACC=add;
        for(i=8;i>0;i--)
        {
                io=ACC0;
                clk=0;
                clk=1;
                ACC=ACC>>1;


        }
        ACC=data0;
        for(j=8;j>0;j--)
        {
                io=ACC0;
                clk=0;
                clk=1;
                ACC=ACC>>1;


        }
      rst=0;
//clk=1;

   


}


void delay(unsigned char a)
{
   unsigned char i;
   while(a-- !=0)
   {
      for(i=0;i<80;i++);
   }
}

myqiang1990 发表于 2011-3-31 00:12:42

回复【15楼】java89vc
-----------------------------------------------------------------------

你确认是for有问题??我想不是。。你在认真检查和测试一下。。。

lystone0001 发表于 2011-3-31 08:28:01

我的ds1302时钟走得特别快 ,请教

java89vc 发表于 2011-4-1 00:47:16

问题完全解决了!谢谢兄弟们的帮助,多谢13楼的兄弟的提醒,ACC确实不好用,我把程序中的ACC全部更换为B寄存器后问题就解决了,for循环的问题也没有了使用i=8或i=0,都可以,我猜想是不是算i++的时候要使用ACC但i--不使用呢(纯数瞎猜!!!待高手解答),连续两个礼拜每天九点钟下班回来就研究这个每天都搞到2点多才睡觉,本来没信心学单片机了现在成功了多少给自己加了点动力,谢谢大家的帮助!!!

eefans 发表于 2011-4-1 11:47:14

应该养成习惯,既然是c语言,就多定义自己的变量。你可以通过分析汇编后的代码,看到ACC是不是在做别的运算时被修改了。

flyleaf91 发表于 2011-4-3 18:36:45

很感谢楼主!!!!!!我最近写了一个模数转换的,一直读数为0,调了一个星期,放下了,今天写好这个ds1302也出现这样的问题,跟楼主的解决方法一样。我现在想研究一下为什么用 for(i=0;i<8;i++)不行

flyleaf91 发表于 2011-4-4 23:40:38

回复【20楼】flyleaf91
很感谢楼主!!!!!!我最近写了一个模数转换的,一直读数为0,调了一个星期,放下了,今天写好这个ds1302也出现这样的问题,跟楼主的解决方法一样。我现在想研究一下为什么用 for(i=0;i&lt;8;i++)不行
-----------------------------------------------------------------------

楼主,哈,我研究了一下,搞明白为什么用for(i=0;i<8;i++)不行 了,有兴趣了解的请看我的博客http://blog.csdn.net/flyleaf91/archive/2011/04/04/6302209.aspx   很有趣啊,哈

java89vc 发表于 2011-4-5 10:14:50

回复【20楼】flyleaf91
很感谢楼主!!!!!!我最近写了一个模数转换的,一直读数为0,调了一个星期,放下了,今天写好这个ds1302也出现这样的问题,跟楼主的解决方法一样。我现在想研究一下为什么用 for(i=0;i&lt;8;i++)不行
-----------------------------------------------------------------------

呵呵共同学习!!!经过几天努力显示和调时间都没问题了,过几天把程序整理了发上来,方便跟我遇到同样问题的兄弟们。

java89vc 发表于 2011-4-5 10:21:01

回复【21楼】flyleaf91
回复【20楼】flyleaf91
很感谢楼主!!!!!!我最近写了一个模数转换的,一直读数为0,调了一个星期,放下了,今天写好这个ds1302也出现这样的问题,跟楼主的解决方法一样。我现在想研究一下为什么用 for(i=0;i&lt;8;i++)不行
-----------------------------------------------------------------------
楼主,哈,我研究了一下,搞明白为什么用for(i=0;i&lt;8;i++)不行 了,有兴趣了解的请看我的博客http://blog.csdn.net/flyleaf91/archive/2011/04/04/6302209.aspx   很有趣啊,哈
-----------------------------------------------------------------------


看过楼主的博客了,写的很详细,学习了,没学过汇编的我真悲剧,过两天恶补 一下!

k322310 发表于 2011-4-5 11:57:51

ACC是累加器,一定要用这个吗?用unsigned char 行不行?我的是这样:

unsigned char du,w;             //定义读时接收字符和位
for(i=8;i>0;i--)
         {   CLK=1;
               delay(20);
               CLK=0;
               w=DIO;

               du>>=1;
               du=du|(w<<=7);
            }

k322310 发表于 2011-4-5 13:30:02

回复【23楼】java89vc
-----------------------------------------------------------------------

太好了 我的电子钟也跑起来了~~用以上的unsigned char 是OK的

624147208 发表于 2011-4-17 17:56:08

DS1302标记

zy1313113aa 发表于 2011-9-13 13:46:27

标记,回去看看这个问题

15138767426 发表于 2011-9-13 23:38:17

我也是正在研究...感觉还是有点复杂。。。。继续努力吧
页: [1]
查看完整版本: STC89C52读取DS1302的问题,各位高手救命啊!俺都搞了一个礼拜了不成功啊!!!