找回密码
 立即注册
查看: 64|回复: 5

51单片机 ds1302通信问题 求助

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-03 12:42:50
已绑定手机

1

主题

1

回帖

11

积分

新手上路

积分
11
发表于 5 天前 | 显示全部楼层 |阅读模式
本人最近在看江协科技的视频学习51单片机,但在使用ds1302实时时钟时遇到了问题:
开发板:普中c51开发板
芯片型号:STC89C52RC


问题描述:在使用ds1302和mcu进行通信时,在读取数据之前io口不置0,则通过串口通信接收到的数据总会间隔一个出现一次0x7F(既通信IO口接收到的一直为1),代码如下:
main.c文件:
#include <REGX52.h>
#include "ds1302.h"
#include "Delay.h"
#include "serial.h"


void main()
{
        unsigned char ds1302_timer[] = {25, 9, 2, 2, 24, 51, 49};
        unsigned char i = 0;
        unsigned char timer = 0x00;
        uart_init();
       
        DS1302_Write(0x8E, 0x00); // 关闭写保护


        for(i = 0; i < 7; i++)
                DS1302_Write(time_address, ds1302_timer%10+ds1302_timer/10*16);
       
        while(1)
        {
                for(i = 0; i < 7; i++)
                {
                        timer = DS1302_Read(time_address);
                        uart_transmit(timer);
                }


                Delay(100);
        }
}




ds1302.c文件:
#include <REGX52.h>
#include "Delay.h"
#include "ds1302.h"


sbit SCLK = P3^6;
sbit CE = P3^5;
sbit IO = P3^4;


const unsigned char time_address[] = {0x8C, 0x88, 0x86, 0x8A, 0x84, 0x82, 0x80};


void DS1302_Write_Byte(unsigned char command)
{
        unsigned char i = 0;
       
        for(i = 0; i < 8; i++)
        {
                IO = command & 0x01;
                Delay_Microsecond(2);
                SCLK = 0;
                Delay_Microsecond(2);
                SCLK = 1;


                command >>= 1;
        }
}


void DS1302_Write(unsigned char address, unsigned char control)
{
       
        CE = 0;
        Delay_Microsecond(2);
        SCLK = 0;
        Delay_Microsecond(2);
        CE = 1;
        Delay_Microsecond(2);
       
        DS1302_Write_Byte(address);
        DS1302_Write_Byte(control);
       
        CE = 0;
}

unsigned char DS1302_Read_Byte()
{
        unsigned char i = 0;
        unsigned char time = 0x00;
       
        //IO = 0;  这里不置0则遇到间隔一次就出现io读取到的一直为1的问题


        for(i = 0; i < 8; i++)
        {
                SCLK = 1;
                Delay_Microsecond(2);
                SCLK = 0;
                Delay_Microsecond(2);


                if(IO == 1)
                        time |= (0x01 << i);
        }




        return time;
}

unsigned char DS1302_Read(unsigned char address)
{       
        unsigned char time = 0x00;
        address |= 0x01;


        CE = 0;
        Delay_Microsecond(2);
        SCLK = 0;
        Delay_Microsecond(2);
        CE = 1;
        Delay_Microsecond(2);
       
        DS1302_Write_Byte(address);
        time = DS1302_Read_Byte();
       
        CE = 0;
        return time;
}


serial.c文件:
#include <regx52.h>
#include "serial.h"


// 波特率9600
void uart_init()
{
  PCON &= 0x0F;
        SCON = 0x50;
       
        TMOD &= 0x0F;
        TMOD |= 0x20;


        TL1 = 0xFD;
        TH1 = 0xFD;
       
        EA = 0;
        TI = 0;
        RI = 0;
        TR1 = 1;
}

void uart_transmit(unsigned char byte)
{
        SBUF = byte;
        while(!TI);
        TI = 0;
}




ds1302.c

1.26 KB, 下载次数: 0

main.c

527 Bytes, 下载次数: 0

serial.c

399 Bytes, 下载次数: 0

回复

使用道具 举报 送花

3

主题

1998

回帖

844

积分

等待验证会员

积分
844
发表于 5 天前 | 显示全部楼层
尊敬的用户:

您好!感谢您对国芯人工智能的关注与支持。针对您在使用51单片机(STC89C52RC)与DS1302通信过程中遇到的问题,我们已认真阅读您的描述,并结合相关技术原理进行分析,现将问题原因及解决建议整理如下:

一、问题现象分析

您提到在读取DS1302数据之前未将IO口置为低电平,导致串口接收到的数据中出现间隔性0x7F(即二进制1111111),且通信IO口始终为高电平。此现象表明DS1302与MCU之间的通信逻辑存在异常。

二、可能原因分析

1. 时序不匹配  
DS1302采用SPI协议进行通信,其时序要求较为严格。若未在通信前正确配置控制引脚(CE、SCLK、I/O),可能导致数据传输失败或读取错误。

2. IO口未初始化为输出模式  
DS1302的I/O口在通信过程中需作为双向口使用,但若未正确设置方向寄存器(如P2M1/P2M0),可能导致数据无法正常传输。

3. 未执行写入命令操作  
DS1302在读取数据前需先发送读取命令(如0x81),若未正确发送该指令,可能导致读取结果异常。

4. 电源或时钟不稳定  
DS1302依赖外部32.768kHz晶振和VCC供电,若供电不稳定或晶振未起振,可能导致通信中断或数据错误。

三、解决方案建议

1. 确保IO口初始化正确  
在代码中明确设置DS1302的控制引脚(CE、SCLK、I/O)为输出模式,并在通信前将CE拉低以使能芯片。

2. 遵循DS1302通信时序  
在读取数据前,应按照以下步骤操作:
将CE拉低;
发送读取命令(如0x81);
通过SCLK脉冲读取数据;
最后将CE拉高以结束通信。

3. 检查DS1302硬件连接  
确认DS1302的VCC、GND、SCLK、I/O、CE引脚与MCU连接正确,且晶振电路工作正常。

4. 调试与验证  
建议使用示波器或逻辑分析仪观察SCLK、I/O信号波形,确认时序是否符合DS1302规范。同时,可通过串口打印中间变量,验证程序执行流程是否正确。

四、参考代码片段(仅供参考)

```c
void DS1302WriteByte(unsigned char dat) {
    unsigned char i;
    for(i=0; i> i) & 0x01;
        DS1302SCLK = 1;
    }
}

unsigned char DS1302ReadByte(void) {
    unsigned char i, dat = 0;
    for(i=0; i

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:35
  • 最近打卡:2025-09-03 17:31:52

14

主题

152

回帖

1765

积分

版主

积分
1765
发表于 5 天前 | 显示全部楼层
已帮您转发给专业技术,稍后晚点会有技术回复
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-03 12:42:50
已绑定手机

1

主题

1

回帖

11

积分

新手上路

积分
11
发表于 5 天前 | 显示全部楼层
yao眼*** 发表于 2025-9-3 17:32
已帮您转发给专业技术,稍后晚点会有技术回复

感谢您
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-09-07 07:40:03
已绑定手机

86

主题

6079

回帖

1万

积分

超级版主

积分
11207
发表于 4 天前 | 显示全部楼层
建议使用内置RTC的Ai MCU,不需要外挂RTC芯片

测试通过的DS1302程序如下:
头文件:
  1. #define                DS1302_CLK                P30                        //定义DS1302时钟IO口
  2. #define                DS1302_DAT                P31                        //定义DS1302数据IO口
  3. #define                DS1302_RST                P32                        //定义DS1302复位IO口
  4. #define                Protrct_Enable        0x80                //使能写保护
  5. #define                Protect_Disable        0x00                //禁用写保护
  6. #define                Write_Protect        0x8e                //定义写保护寄存器地址
  7. #define                Write_TCS                0x90                //定义写充电寄存器地址
  8. #define                Write_Year                0x8c                //定义写年寄存器地址
  9. #define                Write_Week                0x8a                //定义写星期寄存器地址
  10. #define                Write_Month                0x88                //定义写月寄存器地址
  11. #define                Write_Date                0x86                //定义写日寄存器地址
  12. #define                Write_Hour                0x84                //定义写小时寄存器地址
  13. #define                Write_Minute        0x82                //定义写分钟寄存器地址
  14. #define                Write_Second        0x80                //定义写秒钟寄存器地址
  15. #define                Read_Year                0x8d                //定义读年寄存器地址
  16. #define                Read_Week                0x8b                //定义读星期寄存器地址
  17. #define                Read_Month                0x89                //定义读月寄存器地址
  18. #define                Read_Date                0x87                //定义读日寄存器地址
  19. #define                Read_Hour                0x85                //定义读小时寄存器地址
  20. #define                Read_Minute                0x83                //定义读分钟寄存器地址
  21. #define                Read_Second                0x81                //定义读秒钟寄存器地址
  22. //#define                Init_TCS                0xa0                //设置DS1302充电方式为关闭
  23. //#define                Init_TCS                0xa5                //设置DS1302充电方式为1个二极管,2K电阻
  24. //#define                Init_TCS                0xa6                //设置DS1302充电方式为1个二极管,4K电阻
  25. //#define                Init_TCS                0xa7                //设置DS1302充电方式为1个二极管,8K电阻
  26. //#define                Init_TCS                0xa9                //设置DS1302充电方式为2个二极管,2K电阻
  27. //#define                Init_TCS                0xaa                //设置DS1302充电方式为2个二极管,4K电阻
  28. #define                Init_TCS                0xab                //设置DS1302充电方式为2个二极管,8K电阻
  29. #define                Init_Year                0x25                //初始化年
  30. #define                Init_Week                0x04                //初始化星期
  31. #define                Init_Month                0x09                //初始化月
  32. #define                Init_Date                0x04                //初始化日
  33. #define                Init_Hour                0x12                //初始化小时
  34. #define                Init_Minute                0x00                //初始化分钟
  35. #define                Init_Second                0x00                //初始化秒钟
复制代码
子程序:
  1. /*----------------------------地址、数据发送子程序----------------------------*/
  2. void Write_DS1302 (unsigned char addr,unsigned char dat)
  3. {
  4.         unsigned char i,temp;                                //声明移位次数、临时变量
  5.         DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
  6.         DS1302_CLK=0;                                                //拉低DS1302_CLK
  7.         DS1302_RST=1;                                                //DS1302_RST为高,使能DS1302数据传输
  8. /*----------------------------发送地址----------------------------*/
  9.         for (i=8;i>0;i--)                                        //循环移位8次
  10.         {
  11.                 DS1302_CLK=0;                                        //拉低DS1302_CLK
  12.                 temp=addr;                                                //把地址赋值给临时变量
  13.                 DS1302_DAT=(bit)(temp&0x01);        //每次传输低字节,数据放到数据端口
  14.                 DS1302_CLK=1;                                        //拉高DS1302_CLK,锁存数据
  15.                 addr>>=1;                                                //地址右移一位
  16.         }
  17. /*----------------------------发送数据----------------------------*/
  18.         for(i=8;i>0;i--)                                        //循环移位8次
  19.         {
  20.                 DS1302_CLK=0;                                        //拉低DS1302_CLK
  21.                 temp=dat;                                                //把数据赋值给临时变量
  22.                 DS1302_DAT=(bit)(temp&0x01);        //只取最低一位
  23.                 DS1302_CLK=1;                                        //拉高DS1302_CLK,锁存数据
  24.                 dat>>=1;                                                //右移一位
  25.         }
  26.         DS1302_CLK=0;                                                //拉低DS1302_CLK
  27.         DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
  28. }
  29. /*----------------------------数据读取子程序----------------------------*/
  30. unsigned char Read_DS1302(unsigned char addr)
  31. {
  32.         unsigned char i,temp,dat,dat1;
  33.         DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
  34.         DS1302_CLK=0;                                                //拉低DS1302_CLK
  35.         DS1302_RST=1;                                                //DS1302_RST为高,使能DS1302数据传输
  36. /*----------------------------发送地址----------------------------*/
  37.         for(i=8;i>0;i--)                                        //循环移位8次
  38.         {
  39.                 DS1302_CLK=0;                                        //拉低DS1302_CLK
  40.                 temp=addr;                                                //把地址赋值给临时变量
  41.                 DS1302_DAT=(bit)(temp&0x01);        //每次传输低位
  42.                 DS1302_CLK=1;                                        //拉高DS1302_CLK,锁存数据
  43.                 addr>>=1;                                                //addr右移一位
  44.         }
  45. /*----------------------------读取数据----------------------------*/
  46.         P3M0=P3M0&0x1d;
  47.         for(i=8;i>0;i--)                                        //循环移位8次
  48.         {
  49.                 ACC>>=1;                                                //ACC右移一位
  50.                 DS1302_CLK=1;                                        //先拉高DS1302_CLK
  51.                 DS1302_CLK=0;                                        //拉低DS1302_CLK,准备读取数据
  52.                 ACC_7=DS1302_DAT;                                //读取数据,ACC_7为存放数据变量的最高位一位
  53.         }
  54.         P3M0=P3M0|0x02;
  55.         DS1302_CLK=0;                                                //拉低DS1302_CLK
  56.         DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
  57.         dat=ACC;                                                        //把ACC赋值给dat
  58.         dat1=dat&0xf0;                                                //数据进制转换, 提取高四位
  59.         dat1>>=4;                                                        //移动到低四位,作为十位
  60.         dat=dat&0x0f;                                                //提取低四位,作为个位
  61.         dat=dat+dat1*10;                                        //得到的十进制数
  62.         return dat;                                                        //返回十进制值
  63. }
  64. /*----------------------------初始化DS1302----------------------------*/
  65. void Init_DS1302(void)
  66. {
  67.         Write_DS1302(Write_Protect,Protect_Disable);        //禁用写保护
  68.         Write_DS1302(Write_TCS,Init_TCS);                                //初始化充电方式
  69.         Write_DS1302(Write_Year,Init_Year);                                //初始化年
  70.         Write_DS1302(Write_Week,Init_Week);                                //初始化星期
  71.         Write_DS1302(Write_Month,Init_Month);                        //初始化月
  72.         Write_DS1302(Write_Date,Init_Date);                                //初始化日
  73.         Write_DS1302(Write_Hour,Init_Hour);                                //初始化小时
  74.         Write_DS1302(Write_Minute,Init_Minute);                        //初始化分钟
  75.         Write_DS1302(Write_Second,Init_Second);                        //初始化秒钟
  76.         Write_DS1302(Write_Protect,Protrct_Enable);                //使能写保护
  77. }
复制代码
调用:
  1. Read_DS1302(Read_Hour)
  2. Read_DS1302(Read_Minute)
  3. Read_DS1302(Read_Second)
复制代码


回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-09-07 07:40:03
已绑定手机

86

主题

6079

回帖

1万

积分

超级版主

积分
11207
发表于 4 天前 | 显示全部楼层
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-9-8 02:57 , Processed in 0.120980 second(s), 83 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表