打印
[应用相关]

DS1302读出的数值为FF是什么原因?

[复制链接]
2882|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hu9jj|  楼主 | 2019-4-30 16:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
pi, IO, gp, GPIO, se
DS1302日历模块读不出正确数据,读出的值全部是FF,通常会是什么原因,该如何检查呢?
MCU的引脚已经正常配置,DS1302的写操作时序也正常(见下图),读操作的时序尚未抓取到。



    相关的代码如下:
extern uint16_t year;              //年
extern uint8_t mon,day,hour,minu,seco;//月日时分秒

void DS1302_Config(void)           //引脚配置
{
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,GPIO_PIN_5);//CLK输出模式、弱上拉
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_5);
        gpio_bit_set(GPIOB, GPIO_PIN_5);
       
        gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,GPIO_PIN_3);//RST输出模式、弱上拉
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_3);
        gpio_bit_set(GPIOB, GPIO_PIN_3);
}

void DS1302_PortConfig(uint8_t dir)//DAT端口配置(根据需要配置成输出或输入模式)
{
//        GPIO_InitTypeDef GPIO_InitStruct;
    if(dir == IO_OUT)
        {
        gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,GPIO_PIN_4);//输出模式、弱上拉
        gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_4);
        }
        else
        {
        gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_4);   //输入模式
        gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_4);
        }
        gpio_bit_set(GPIOB, GPIO_PIN_4);
}



/*****************************************************
函数功能:向1302写一个字节数据
入口参数:x
***************************************************/
void Write1302(uint8_t dat)
{
        uint8_t i;
        DATA_OUT;
        SCLK_0;

        delay_us(3);
        for(i=0;i<8;i++)
        {
                if(dat&0x01) DATA_1;
                else DATA_0;
                delay_us(4);
                SCLK_1;
                delay_us(4);
                SCLK_0;
                dat>>=1;
        }


}

/*****************************************************
函数功能:根据命令字,向1302写一个字节数据
入口参数:Cmd,储存命令字;dat,储存待写的数据
***************************************************/
void WriteSet1302(uint8_t Cmd,uint8_t dat)
{
        RST_0;
        SCLK_0;
        RST_1;
        delay_us(4);
        Write1302(Cmd);
        Write1302(dat);
        SCLK_1;
        RST_0;

}

/*****************************************************
函数功能:从1302读一个字节数据
入口参数:x
***************************************************/
uint8_t Read1302(void)
{
        uint8_t i,dat;
        DATA_IN;      //
        DATA_0;       //
    delay_us(4);
       
        for(i=0;i<8;i++)
        {
                dat>>=1;
                if(gpio_input_bit_get(GPIOB,GPIO_PIN_3) == SET)  //(DATA != 0)
                        dat|=0x80;
                else
                        dat&=0x7f;
                SCLK_1;
                delay_us(4);
                SCLK_0;
                delay_us(4);
        }
        DATA_OUT;      //
        return dat;
}

/*****************************************************
函数功能:根据命令字,从1302读取一个字节数据
入口参数:Cmd
***************************************************/
uint8_t ReadSet1302(uint8_t Cmd)
{
        uint8_t dat;
        RST_0;
        SCLK_0;
        RST_1;
        Write1302(Cmd);
        dat=Read1302();
        SCLK_1;
        RST_0;
        return dat;
}

/*****************************************************
函数功能: 1302进行初始化设置
***************************************************/
void DS1302_Init(void)
{

        DATA_OUT;
       
        /*--------------------这是每次都初始化的语句-----------------*/
/*
        WriteSet1302(0x8E,0x00);                     //根据写状态寄存器命令字,写入不保护指令
        WriteSet1302(0x80,((55/10)<<4|(55%10)));     //根据写秒寄存器命令字,写入秒的初始值
        WriteSet1302(0x82,((11/10)<<4|(11%10)));     //根据写分寄存器命令字,写入分的初始值
        WriteSet1302(0x84,((9/10)<<4|(9%10)));       //根据写小时寄存器命令字,写入小时的初始值
        WriteSet1302(0x86,((6/10)<<4|(6%10)));       //根据写日寄存器命令字,写入日的初始值
        WriteSet1302(0x88,((2/10)<<4|(2%10)));       //根据写月寄存器命令字,写入月的初始值
        WriteSet1302(0x8c,((15/10)<<4|(15%10)));     //根据写年寄存器命令字,写入年的初始值
        WriteSet1302(0x90,0xa5);                     //打开充电功能 选择2K电阻充电方式
        WriteSet1302(0x8E,0x80);                     //根据写状态寄存器命令字,写入保护指令

*/
        //如果不想每次都初始化时间,也就是掉电后还想让时钟继续走时的话 就用下面的语句        ,此时vcc1外接3v电池
    uint8_t flag;
        LCD_write_ASCII(0,4,"No");
       
    flag= ReadSet1302(0x81);
    if(flag&0x80)                                //判断时钟芯片是否关闭
    {
        WriteSet1302(0x8E,0x00);                 //关闭写保护
               WriteSet1302(0x80,((45/10)<<4|(45%10))); //写入秒初始值
        WriteSet1302(0x82,((15/10)<<4|(15%10))); //写入分的初始值
        WriteSet1302(0x84,((9/10)<<4|(9%10)));   //写入小时的初始值
        WriteSet1302(0x86,((6/10)<<4|(6%10)));   //写入日的初始值
        WriteSet1302(0x88,((5/10)<<4|(5%10)));   //写入月的初始值
        WriteSet1302(0x8c,((19/10)<<4|(19%10))); //写入年的初始值
        WriteSet1302(0x90,0xa5);                 //打开充电功能 5=一个二极管2K电阻,9=两个二极管2K电阻
                                                 //             6=一个二极管4K电阻,a=两个二极管4K电阻
                                                 //             7=一个二极管8K电阻,b=两个二极管8K电阻
        WriteSet1302(0x8E,0x80);                             //打开写保护
                LCD_write_ASCII(0,4,"OK");
    }

}

//向DS302写入时钟数据
void DS1302_write_date(void)
{
        uint8_t temp;
       
        WriteSet1302(0x8E,0x00);                     //关闭写保护
        WriteSet1302(0x80,0x80);                     //暂停时钟
        WriteSet1302(0x90,0xa5);                         //涓流充电
        temp = ((year%100)/10<<4|(year%10));
        WriteSet1302(0x8C,temp);                     //年
        temp = ((mon/10)<<4|(mon%10));
        WriteSet1302(0x88,temp);                         //月
        temp = ((day/10)<<4|(day%10));
        WriteSet1302(0x86,temp);                     //日
        temp = ((hour/10)<<4|(hour%10));
        WriteSet1302(0x84,temp|0x80);                //时(24小时制式)
        temp = ((minu/10)<<4|(minu%10));
        WriteSet1302(0x82,temp);                     //分
        WriteSet1302(0x80,0x00);                     //秒
//        WriteSet1302(0x8A,0x01);                     //周
        WriteSet1302(0x8E,0x80);                     //打开写保护     
}

//从DS302读出时钟数据
void DS1302_read_date(void)  
{
    uint8_t temp;
        temp = ReadSet1302(0x8D);                    //年 0x8D
        year = 2000 + ((temp&0x70)>>4)*10 + (temp&0x0F);
        temp = ReadSet1302(0x89);;                             //月 0x89
        mon = ((temp&0x70)>>4)*10 + (temp&0x0F);
        temp = ReadSet1302(0x87);                    //日 0x87
        day = ((temp&0x70)>>4)*10 + (temp&0x0F);
        temp = ReadSet1302(0x85);                             //时 0x85
        hour = ((temp&0x70)>>4)*10 + (temp&0x0F);
        temp = ReadSet1302(0x83);                         //分 0x83
        minu = ((temp&0x70)>>4)*10 + (temp&0x0F);
        temp = ReadSet1302(0x81)&0x7f;               //秒,屏蔽秒的第7位,避免超出59
        seco = ((temp&0x70)>>4)*10 + (temp&0x0F);
}





使用特权

评论回复
沙发
hu9jj|  楼主 | 2019-4-30 20:35 | 只看该作者
找到原因了,原来是读数据 的函数中引脚代码错了,现在可以正常取数了。结贴!

使用特权

评论回复
板凳
zhuomuniao110| | 2019-4-30 21:39 | 只看该作者
给力,分享一下正确的代码。

使用特权

评论回复
地板
xinpian101| | 2019-4-30 21:51 | 只看该作者
工具可以

使用特权

评论回复
5
hu9jj|  楼主 | 2019-5-1 09:11 | 只看该作者
zhuomuniao110 发表于 2019-4-30 21:39
给力,分享一下正确的代码。

其实就是引脚的编号写错了,我的DAT 引脚接在PB4上,但我的代码却错写成PB3。以下是修改后的代码:

/*****************************************************
函数功能:从1302读一个字节数据
入口参数:x
***************************************************/
uint8_t Read1302(void)
{
        uint8_t i,dat;
        DATA_IN;      //设置为输入
        DATA_0;       //
    delay_us(4);
       
        for(i=0;i<8;i++)
        {
                dat>>=1;
                if(gpio_input_bit_get(GPIOB,GPIO_PIN_4) == SET)  //(DAT = 1)
                        dat|=0x80;
                else
                        dat&=0x7f;
                SCLK_1;
                delay_us(4);
                SCLK_0;
                delay_us(4);
        }
        DATA_OUT;      //
        return dat;
}

使用特权

评论回复
6
幸福小强| | 2019-5-2 21:25 | 只看该作者
很标准的例子。

使用特权

评论回复
7
hu9jj|  楼主 | 2019-5-3 10:41 | 只看该作者

是的,原例程是STM32HAL库的,我移植到GD32E23x,第一次使用,也不知道是没写进去还是没读出来,通过逻辑分析仪抓取时序图,发现写时序正常,读时序出问题,最后排查到是读DAT时引脚标错了,更正过来就顺利读出数据了。

使用特权

评论回复
8
henangongda123| | 2019-5-3 11:03 | 只看该作者
1302误差比较大,建议你用我玩的那款IC,实测误差真的很小

使用特权

评论回复
9
hu9jj|  楼主 | 2019-5-4 09:12 | 只看该作者
henangongda123 发表于 2019-5-3 11:03
1302误差比较大,建议你用我玩的那款IC,实测误差真的很小

让我使劲猜猜您玩的是哪款IC

使用特权

评论回复
10
henangongda123| | 2019-5-6 10:56 | 只看该作者
hu9jj 发表于 2019-5-4 09:12
让我使劲猜猜您玩的是哪款IC

被系统删了

使用特权

评论回复
评论
hu9jj 2019-5-6 14:31 回复TA
哦,也许涉嫌广告推销吧。 
11
hanzhen654| | 2019-5-6 18:24 | 只看该作者
检查引脚 是否连接正确

使用特权

评论回复
12
hanzhen654| | 2019-5-6 18:24 | 只看该作者
然后就是底层的时序是否按照芯片手册来编写的

使用特权

评论回复
13
hu9jj|  楼主 | 2019-5-6 21:31 | 只看该作者
hanzhen654 发表于 2019-5-6 18:24
检查引脚 是否连接正确

正是引脚编号写错了。

使用特权

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

本版积分规则

认证:Microchip
简介:让我们来为您提供帮助。我们可提供各种资源来帮助您解决一切问题。是否需要与我们的客户支持团队联系?您可以通过电话、在线聊天功能或电子邮件与他们联系。

151

主题

1059

帖子

11

粉丝