RobinHou 发表于 2025-4-15 18:12:22

32G12K128 FreeRTOS 下读取DS1302失败

我采用论坛上DS1302的例程,读取DS1302失败。我用逻辑分析仪抓了波形,SPI时钟大约3us,延时应该够了。请问调试经验丰富的人,能否从波形图上看出问题所在。

国芯人工智能 发表于 2025-4-15 18:18:00

在STC32G12K128微控制器上使用FreeRTOS实时操作系统读取DS1302实时时钟模块时遇到读取失败的问题,可能涉及多个方面的原因。以下是一些可能的原因及相应的解决方案,供您参考和排查。

1. 硬件连接问题
首先,确保DS1302模块与STC32G12K128微控制器的硬件连接正确无误。DS1302通常需要以下引脚连接:
VCC:电源正极,通常为3.3V或5V。
GND:电源地。
CLK:时钟信号,连接到微控制器的GPIO引脚。
DAT:数据信号,连接到微控制器的GPIO引脚。
RST:复位信号,连接到微控制器的GPIO引脚。

请检查这些引脚是否连接正确,并确保电源电压符合DS1302的要求。

2. 引脚配置与初始化
在软件中,确保正确配置了与DS1302通信的GPIO引脚。通常需要将CLK、DAT和RST引脚配置为输出模式,并在初始化时设置适当的电平状态。例如:

c
void DS1302Init(void) {
    GPIOInitTypeDef GPIOInitStruct;

    // 配置CLK、DAT、RST引脚为输出模式
    GPIOInitStruct.Pin = DS1302CLKPIN | DS1302DATPIN | DS1302RSTPIN;
    GPIOInitStruct.Mode = GPIOMODEOUTPUTPP;
    GPIOInitStruct.Pull = GPIONOPULL;
    GPIOInitStruct.Speed = GPIOSPEEDFREQLOW;
    HALGPIOInit(DS1302GPIOPORT, &GPIOInitStruct);

    // 初始化引脚状态
    HALGPIOWritePin(DS1302GPIOPORT, DS1302RSTPIN, GPIOPINRESET);
    HALGPIOWritePin(DS1302GPIOPORT, DS1302CLKPIN, GPIOPINRESET);
    HALGPIOWritePin(DS1302GPIOPORT, DS1302DATPIN, GPIOPINRESET);
}

3. 时序问题
DS1302的通信协议对时序有严格的要求。确保在读取和写入数据时,严格按照DS1302的时序图进行操作。以下是一个简单的读取字节的示例:

```c
uint8t DS1302ReadByte(void) {
    uint8t data = 0;
    uint8t i;

    for (i = 0; i < 8; i++) {
      HALGPIOWritePin(DS1302GPIOPORT, DS1302CLKPIN, GPIOPINSET);
      HALDelay(1); // 适当延时
      data |= HALGPIOReadPin(DS1302GPIOPORT, DS1302DATPIN)

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

ercircle 发表于 2025-4-15 18:28:00



普中开发板上测过的例程参考下:

DebugLab 发表于 2025-4-15 20:41:42

#define                Protrct_Enable        0x80                //使能写保护
#define                Protect_Disable        0x00                //禁用写保护
#define                Write_Protect        0x8e                //定义写保护寄存器地址
#define                Write_TCS                0x90                //定义写充电寄存器地址
#define                Write_Year                0x8c                //定义写年寄存器地址
#define                Write_Week                0x8a                //定义写星期寄存器地址
#define                Write_Month                0x88                //定义写月寄存器地址
#define                Write_Date                0x86                //定义写日寄存器地址
#define                Write_Hour                0x84                //定义写小时寄存器地址
#define                Write_Minute        0x82                //定义写分钟寄存器地址
#define                Write_Second        0x80                //定义写秒钟寄存器地址
#define                Read_TCS                0x91                //定义读充电寄存器地址
#define                Read_Year                0x8d                //定义读年寄存器地址
#define                Read_Week                0x8b                //定义读星期寄存器地址
#define                Read_Month                0x89                //定义读月寄存器地址
#define                Read_Date                0x87                //定义读日寄存器地址
#define                Read_Hour                0x85                //定义读小时寄存器地址
#define                Read_Minute                0x83                //定义读分钟寄存器地址
#define                Read_Second                0x81                //定义读秒钟寄存器地址
#define                TCS_OFF                        0xa0                //设置DS1302充电方式为关闭
#define                TCS_1D2K                0xa5                //设置DS1302充电方式为1个二极管,2K电阻
#define                TCS_1D4K                0xa6                //设置DS1302充电方式为1个二极管,4K电阻
#define                TCS_1D8K                0xa7                //设置DS1302充电方式为1个二极管,8K电阻
#define                TCS_2D2K                0xa9                //设置DS1302充电方式为2个二极管,2K电阻
#define                TCS_2D4K                0xaa                //设置DS1302充电方式为2个二极管,4K电阻
#define                TCS_2D8K                0xab                //设置DS1302充电方式为2个二极管,8K电阻
#define                Init_Year                0x19                //初始化年
#define                Init_Week                0x03                //初始化星期
#define                Init_Month                0x08                //初始化月
#define                Init_Date                0x28                //初始化日
#define                Init_Hour                0x14                //初始化小时
#define                Init_Minute                0x13                //初始化分钟
#define                Init_Second                0x00                //初始化秒钟/*----------------------------DS1302写数据----------------------------*/
//void Write_DS1302 (unsigned char addr,unsigned char dat)
//{
//        unsigned char i,temp;                                //声明移位次数、临时变量
//        DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
//        DS1302_CLK=0;                                                //拉低DS1302_CLK
//        DS1302_RST=1;                                                //DS1302_RST为高,使能DS1302数据传输
//        for(i=8;i>0;i--)                                        //循环移位8次
//        {
//                DS1302_CLK=0;                                        //拉低DS1302_CLK
//                temp=addr;                                                //把地址赋值给临时变量
//                DS1302_DAT=(bit)(temp&0x01);        //每次传输低字节,数据放到数据端口
//                DS1302_CLK=1;                                        //拉高DS1302_CLK,锁存数据
//                addr>>=1;                                                //地址右移一位
//        }
//        for(i=8;i>0;i--)                                        //循环移位8次
//        {
//                DS1302_CLK=0;                                        //拉低DS1302_CLK
//                temp=dat;                                                //把数据赋值给临时变量
//                DS1302_DAT=(bit)(temp&0x01);        //只取最低一位
//                DS1302_CLK=1;                                        //拉高DS1302_CLK,锁存数据
//                dat>>=1;                                                //右移一位
//        }
//        DS1302_CLK=0;                                                //拉低DS1302_CLK
//        DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
//}

/*----------------------------DS1302读数据----------------------------*/
unsigned char Read_DS1302(unsigned char addr)
{
        unsigned char i,temp,dat,dat1;
        DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
        DS1302_CLK=0;                                                //拉低DS1302_CLK
        DS1302_RST=1;                                                //DS1302_RST为高,使能DS1302数据传输
        for(i=8;i>0;i--)                                        //循环移位8次
        {
                DS1302_CLK=0;                                        //拉低DS1302_CLK
                temp=addr;                                                //把地址赋值给临时变量
                DS1302_DAT=(bit)(temp&0x01);        //每次传输低位
                DS1302_CLK=1;                                        //拉高DS1302_CLK,锁存数据
                addr>>=1;                                                //addr右移一位
        }
        P3M0=P3M0&0x3d;
        for(i=8;i>0;i--)                                        //循环移位8次
        {
                ACC>>=1;                                                //ACC右移一位
                DS1302_CLK=1;                                        //先拉高DS1302_CLK
                DS1302_CLK=0;                                        //拉低DS1302_CLK,准备读取数据
                ACC_7=DS1302_DAT;                                //读取数据,ACC_7为存放数据变量的最高位一位
        }
        P3M0=P3M0|0x02;
        DS1302_CLK=0;                                                //拉低DS1302_CLK
        DS1302_RST=0;                                                //拉低DS1302_RST,禁止DS1302数据传输
        dat=ACC;                                                        //把ACC赋值给dat
        dat1=dat&0xf0;                                                //数据进制转换, 提取高四位
        dat1>>=4;                                                        //移动到低四位,作为十位
        dat=dat&0x0f;                                                //提取低四位,作为个位
        dat=dat+dat1*10;                                        //得到的十进制数
        return dat;                                                        //返回十进制值
}

/*----------------------------初始化DS1302----------------------------*/
//void Init_DS1302(void)
//{
//        Write_DS1302(Write_Protect,Protect_Disable);        //禁用写保护
//        Write_DS1302(Write_TCS,TCS_2D8K);                                //初始化充电方式
//        Write_DS1302(Write_Year,Init_Year);                                //初始化年
//        Write_DS1302(Write_Week,Init_Week);                                //初始化星期
//        Write_DS1302(Write_Month,Init_Month);                        //初始化月
//        Write_DS1302(Write_Date,Init_Date);                                //初始化日
//        Write_DS1302(Write_Hour,Init_Hour);                                //初始化小时
//        Write_DS1302(Write_Minute,Init_Minute);                        //初始化分钟
//        Write_DS1302(Write_Second,Init_Second);                        //初始化秒钟
//        Write_DS1302(Write_Protect,Protrct_Enable);                //使能写保护
//}

RobinHou 发表于 2025-4-16 12:46:46

感谢楼上各位老师,问题解决了。最初我是参考这个帖子DS1302 自用代码 (通用) - 老鸟反刍/吐槽,新手乐园,毕业设计 国芯技术交流网站 - AI32位8051交流社区,移植代码的。读时间寄存器参考了这段代码。//========================================================================
//                                                                                                 读取时间
// ***********************************************************************
//========================================================================      
void Ds1302ReadTime()
{
      unsigned char n;
      unsigned char dd="";
      for (n=0; n<7; n++)
      {
                TIME = Ds1302Read(READ_RTC_ADDR);
      }
      for (n=0; n<7; n++)
      {
                TIME = Ds1302Read(READ_RTC_ADDR);
      }
      Year=BCD_DEC(TIME);
      Week=BCD_DEC(TIME);
      Month=BCD_DEC(TIME);
      day=BCD_DEC(TIME);
      Hour=BCD_DEC(TIME);
      Minute=BCD_DEC(TIME);
      Second=BCD_DEC(TIME);
} 我做了一些改动,我用addr =0x81 读秒寄存器,每读一次地址加2. 结果读第二轮时,没有把地址恢复到0x81.经过这次教训,我也感觉这段代码重复读2次,似乎没有必要,没有对读出来的时间寄存器的数据做时间有效性的校验,读取多次,也只是使用最后一次的数据。提高不了读取成功的机率。除非芯片本身固有的特性,第二轮读取的数据成功几率更高。
页: [1]
查看完整版本: 32G12K128 FreeRTOS 下读取DS1302失败