打印

关于DS1302时钟的问题,求救大神

[复制链接]
1780|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本人用DS1302做时钟,仿真没有错误。先前用LCD1602显示正确,后面改用LCD12864显示就出错了,时间跳动1、2秒,又归为初始时间。百调不灵,我又接回LCD1602,用先前测试成功的程序,发现LCD1602显示 ??:??:??。我以为是DS1302模块坏了,换了块重复以上步骤,依旧出错。在网上查有人说 DS1302读字节最后 IO 要拉低,我按照加了句,显示依旧出错。求大神指教

相关帖子

沙发
rainsying|  楼主 | 2014-5-25 15:12 | 只看该作者
#include <reg52.h>       
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
#define LCD1602_dat P0

//LCD1602端口
sbit RS = P2^0;
sbit RW = P2^1;
sbit EN = P2^2;
//DS1302端口
sbit RST  = P2^3;
sbit IO   = P2^4;
sbit SCLK = P2^5;

//DS18B20端口
sbit DQ = P2^6; //DS18B20的数据口位P2.0
               
                          //秒    分    时    日    月  星期    年
uchar code Time_init[] = {0x00, 0x00, 0x12, 0x01, 0x01, 0x05, 0x10}; //初始时间
uchar data now[7]; //时间缓存

void delay10us(uchar n) //延时10uS(STC90C52RC/12MHz)
{
    while (n--)
    {
        _nop_();
        _nop_();
                _nop_();
    }
}

void delay1ms(uint t)
{
        uint i,j;
        for(i=0;i<t;i++)
        for(j=0;j<100;j++);
}

void Wr_Com(uchar com)        //LCD1602写指令
{
        delay1ms(1);
        RS=0;
        RW=0;
        EN=0;
        LCD1602_dat=com;
        delay1ms(1);
        EN=1;
        delay1ms(1);
        EN=0;
}

void Wr_Dat(uchar dat)        //LCD1602写数据
{
        delay1ms(1);
        RS=1;
        RW=0;
        EN=0;
        LCD1602_dat=dat;
        delay1ms(1);
        EN=1;
        delay1ms(1);
        EN=0;
}

void Lcd1602_Init()        //LCD1602初始化设置
{
        delay1ms(15);
        Wr_Com(0x38);
        delay1ms(5);
        Wr_Com(0x08);
        delay1ms(5);
        Wr_Com(0x01);
        delay1ms(5);
        Wr_Com(0x06);
        delay1ms(5);
        Wr_Com(0x0c);
        delay1ms(5);
}

void display(uchar *p)        //LCD1602显示字符串
{
        while(*p!='\0')
        {
                Wr_Dat(*p);
                p++;delay1ms(1);
        }
}

uchar DS1302_ReadByte() //从DS1302读1字节数据
{
    uchar i;
    uchar dat=0;

    for(i=0;i<8;i++)
    {
        SCLK = 0;//时钟线拉低
        _nop_(); //延时等待
        _nop_();
        dat >>= 1; //数据右移一位
        if (IO) dat |= 0x80; //读取数据
        SCLK = 1; //时钟线拉高
        _nop_();            
        _nop_();
    }
    return dat;
}

void DS1302_WriteByte(uchar dat) //向DS1302写1字节数据
{
    uchar i;

    for(i=0;i<8;i++)
    {
        SCLK = 0; //时钟线拉低
        _nop_(); //延时等待
        _nop_();
        dat >>= 1; //移出数据
        IO = CY; //送出到端口
        SCLK = 1; //时钟线拉高
        _nop_(); //延时等待
        _nop_();
    }
}

uchar DS1302_ReadData(uchar addr) //读DS1302某地址的的数据
{
    uchar dat;

    RST = 0;
    _nop_(); //延时等待
    _nop_();
    SCLK = 0;
    _nop_(); //延时等待
    _nop_();
    RST = 1;
    _nop_(); //延时等待
    _nop_();
    DS1302_WriteByte(addr); //写地址
    dat = DS1302_ReadByte(); //读数据
    SCLK = 1;
    RST = 0;

    return dat;
}

void DS1302_WriteData(uchar addr,uchar dat) //往DS1302的某个地址写入数据
{
    RST = 0;
    _nop_(); //延时等待
    _nop_();
    SCLK = 0;
    _nop_(); //延时等待
    _nop_();
    RST = 1;
    _nop_(); //延时等待
    _nop_();
    DS1302_WriteByte(addr); //写地址
    DS1302_WriteByte(dat); //写数据
    SCLK = 1;
    RST = 0;
}

void DS1302_SetTime(uchar *p) //写入初始时间
{
    uchar addr = 0x80;
    uchar n = 7;

    DS1302_WriteData(0x8e,0x00); //允许写操作
    while(n--)
    {
        DS1302_WriteData(addr,*p++);
        addr += 2;
    }
    DS1302_WriteData(0x8e,0x80); //写保护
}

void DS1302_Initial() //初始化DS1302
{
    RST = 0;
    SCLK = 0;
    DS1302_WriteData(0x8e, 0x00); //允许写操作
    DS1302_WriteData(0x80, 0x00); //时钟启动
    DS1302_WriteData(0x90, 0xa6); //一个二极管+4K电阻充电
    DS1302_WriteData(0x8e, 0x80); //写保护
}

void Get_Time(uchar *p) //获取当前时间及显示
{
    uchar addr=0x81;
    uchar n=7;
        uchar SHI_1,SHI_2,FEN_1,FEN_2,MIAO_1,MIAO_2; //时、分、秒
//        uchar RI_1,RI_2,YUE_1,YUE_2,NIAN_1,NIQN_2; //日、月、年

    while (n--)
    {
        *p++ = DS1302_ReadData(addr);
        addr += 2;
    }

//  RI_1,RI_2,YUE_1,YUE_2,NIAN_1,NIQN_2;       
        SHI_1  = now[2] >> 4;
        SHI_2  = now[2] & 0x0f;
        FEN_1  = now[1] >> 4;
        FEN_2  = now[1] & 0x0f;       
        MIAO_1 = now[0] >> 4;
        MIAO_2 = now[0] & 0x0f;

        Wr_Com(0x80);
        display("Time:");
        Wr_Com(0x85);               
        Wr_Dat(SHI_1+0x30);
        Wr_Dat(SHI_2+0x30);
        Wr_Dat(':');
        Wr_Dat(FEN_1+0x30);
        Wr_Dat(FEN_2+0x30);
        Wr_Dat(':');
        Wr_Dat(MIAO_1+0x30);
        Wr_Dat(MIAO_2+0x30);
}


void DS18B20_Reset() //复位DS18B20,并检测设备是否存在
{
    CY = 1;
    while (CY)
    {
        DQ = 0;                     //送出低电平复位信号
        delay10us(48);              //延时至少480us
        DQ = 1;                     //释放数据线
        delay10us(6);               //等待60us
        CY = DQ;                    //检测存在脉冲
        delay10us(42);              //等待设备释放数据线
    }
}

uchar DS18B20_ReadByte() //从DS18B20读1字节数据
{
    uchar i;
    uchar dat = 0;

    for(i=0;i<8;i++)
    {
        dat >>= 1;
        DQ = 0; //开始时间片
        _nop_(); //延时等待
        _nop_();
        DQ = 1; //准备接收
        _nop_(); //接收延时
        _nop_();
        if(DQ){dat |= 0x80;} //读取数据
        delay10us(6); //等待时间片结束
    }

    return dat;
}

void DS18B20_WriteByte(uchar dat) //向DS18B20写1字节数据
{
    uchar i;

    for(i=0;i<8;i++)
    {
        DQ = 0; //开始时间片
        _nop_(); //延时等待
        _nop_();
        dat >>= 1; //送出数据
        DQ = CY;
        delay10us(6); //等待时间片结束
        DQ = 1; //恢复数据线
    }
}

void Get_Temp() //获取温度及显示
{
        uchar TPH,TPL; //存放温度值的高低字节
        uint dat;
        uint x1,x2,x3,x4,x5;

    DS18B20_Reset(); //设备复位
    DS18B20_WriteByte(0xCC); //跳过ROM命令
    DS18B20_WriteByte(0x44); //开始转换命令
           while (!DQ); //等待转换完成
        DS18B20_Reset(); //设备复位
        DS18B20_WriteByte(0xCC); //跳过ROM命令
        DS18B20_WriteByte(0xBE); //读暂存存储器命令
        TPL = DS18B20_ReadByte(); //读温度低字节
        TPH = DS18B20_ReadByte(); //读温度高字节
        dat = (TPH<<8)+TPL; //DB18B20测温范围 -55℃~125℃

        if(dat<=2000)        //显示正温度       
        {
                dat = dat*(10.0/16.0);
                Wr_Com(0xC5); //送去LCD1602显示
                Wr_Dat('+');
        }               
        else                        //显示负温度
        {
                dat = 65537 - dat;
                dat = dat*(10.0/16.0);
                Wr_Com(0xC5); //送去LCD1602显示
                Wr_Dat('-');       
        }

        x1=dat/10000;
    dat=dat%10000;
        x2=dat/1000;
        dat=dat%1000;
        x3 =dat/100;
        dat=dat%100;
        x4=dat/10;
        dat=dat%10;
        x5=dat;

        Wr_Com(0xC0); //送去LCD1602显示
        display("Temp:");
        Wr_Com(0xC6);
//        Wr_Dat(x1 + 0x30);
//        Wr_Dat(x2 + 0x30);
        Wr_Dat(x3 + 0x30);
        Wr_Dat(x4 + 0x30);
        Wr_Dat('.');
        Wr_Dat(x5 + 0x30);
}

void main()
{
        Lcd1602_Init(); //初始化LCD1602
    DS1302_Initial(); //初始化DS1302                                               
    DS1302_SetTime(Time_init);           //设置初始时间
   
        while(1)
        {
                Get_Time(now); //获取当前时间
                Get_Temp(); //获取当前温度
        }   
}

















使用特权

评论回复
板凳
rainsying|  楼主 | 2014-5-25 15:20 | 只看该作者
C:\Users\Sying\Desktop\捕获.PNG

使用特权

评论回复
地板
rainsying|  楼主 | 2014-5-25 15:24 | 只看该作者

捕获.PNG (435.62 KB )

捕获.PNG

使用特权

评论回复
5
dirtwillfly| | 2014-5-25 16:14 | 只看该作者
你调试时,注意下从DS1302里读到的数据是什么,先界定下是读DS1302出问题了,还是写显示屏出问题了

使用特权

评论回复
6
roykin| | 2014-5-27 12:44 | 只看该作者
目测是写显示屏出问题了…

使用特权

评论回复
7
wh6ic| | 2014-5-28 12:55 | 只看该作者
? = 0x3F
楼主读I2C的值错了,是全0xff

使用特权

评论回复
8
sl_lovearm| | 2014-5-29 11:56 | 只看该作者
应该是DS1302_WriteByte函数里面写得有问题,从最低位开始传输数据,使用右移指令,怎么用CY呢,CY是左移时 用于从高位传输数据时用的吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

12

帖子

1

粉丝