2401_85308619 2024-11-06 23:47 采纳率: 44.4%
浏览 10

stm32使用DS1302实时时钟模块

stm32使用DS1302实时时钟模块用串口发送时间出现2165-165-165 165:165:85这样的格式不知道怎么解决

ds1302.c

#include "ds1302.h"
#include "stm32f10x.h"

static void DS1302_WriteByte(uint8_t addr,uint8_t data);
static uint8_t DS1302_ReadByte(uint8_t addr);

static void DS1302_Init(void);
static void DS1302_SetTime(uint8_t *writeTime);
static void DS1302_GetTime(DS1302TimeStruct *timeData);

DS1302ClassStruct DS1302Class = {
    .Init = DS1302_Init,
    .SetTime = DS1302_SetTime,
    .GetTime = DS1302_GetTime
};

/*
初始时间定义{0x20,0x21,0x11,0x13,0x10,0x10,0x00,0x06};
初始时间2021年11月13号10点10分00秒 星期六
*/
uint8_t time_buf[8] = {0x20};//初始时间
uint8_t readtime[8] = {0x20};//当前时间

//DS1302引脚定义,可根据实际情况自行修改端口定义
#define DS1302_CLK_PORT                    GPIOB
#define DS1302_CLK_CLK                    RCC_APB2Periph_GPIOB
#define DS1302_CLK_PIN                    GPIO_Pin_0

#define DS1302_DAT_PORT                    GPIOB
#define DS1302_DAT_CLK                    RCC_APB2Periph_GPIOB
#define DS1302_DAT_PIN                    GPIO_Pin_2

#define DS1302_RST_PORT                    GPIOA
#define DS1302_RST_CLK                    RCC_APB2Periph_GPIOA
#define DS1302_RST_PIN                    GPIO_Pin_11

// Pin0-7设置CRL寄存器 Pin8-15设置CRH寄存器 配置输入输出模式
#define DS1302_DAT_OutPut_Mode()    {DS1302_DAT_PORT->CRL &= 0xFF0FFFFF;DS1302_DAT_PORT->CRL |= 0x00300000;}
#define DS1302_DAT_InPut_Mode()        {DS1302_DAT_PORT->CRL &= 0xFF0FFFFF;DS1302_DAT_PORT->CRL |= 0x00400000;}

//DS1302引脚输出输入
#define DS1302_DAT_IN()          GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN)
#define DS1302_CLK_0                 DS1302_CLK_PORT->BSRR = (uint32_t)DS1302_CLK_PIN<<16 // 置0
#define DS1302_CLK_1          DS1302_CLK_PORT->BSRR = (uint32_t)DS1302_CLK_PIN // 置1
#define DS1302_DAT_0                 DS1302_DAT_PORT->BSRR = (uint32_t)DS1302_DAT_PIN<<16 // 置0
#define DS1302_DAT_1                DS1302_DAT_PORT->BSRR = (uint32_t)DS1302_DAT_PIN // 置1
#define DS1302_RST_0                 DS1302_RST_PORT->BSRR = (uint32_t)DS1302_RST_PIN<<16 // 置0
#define DS1302_RST_1                 DS1302_RST_PORT->BSRR = (uint32_t)DS1302_RST_PIN // 置1

//DS1302地址定义
#define DS1302_SEC_ADDR           0x80        //秒数据地址
#define DS1302_MIN_ADDR           0x82        //分数据地址
#define DS1302_HOUR_ADDR          0x84        //时数据地址
#define DS1302_DAY_ADDR           0x86        //日数据地址
#define DS1302_MONTH_ADDR         0x88        //月数据地址
#define DS1302_WEEK_ADDR          0x8a        //星期数据地址
#define DS1302_YEAR_ADDR          0x8c        //年数据地址
#define DS1302_CONTROL_ADDR       0x8e        //控制数据地址
#define DS1302_CHARGER_ADDR       0x90         //充电功能地址             
#define DS1302_CLKBURST_ADDR      0xbe

//向DS1302写入一字节数据
static void DS1302_WriteByte(uint8_t addr,uint8_t data) 
{
    uint8_t i;
    DS1302_RST_0; //禁止数据传输 !!!这条很重要
    DS1302_CLK_0; //确保写数据前SCLK为低电平
    DS1302_RST_1;    //启动DS1302总线    
    DS1302_DAT_OutPut_Mode();
    addr=addr&0xFE;  //最低位置零,寄存器0位为0时写,为1时读
    for(i=0;i<8;i++) //写入目标地址:addr
    {
        if (addr&0x01) DS1302_DAT_1;
        else DS1302_DAT_0;
        DS1302_CLK_1; //时钟上升沿写入数据
        DS1302_CLK_0;
        addr=addr>>1;
    }    
    for (i=0;i<8;i++) //写入数据:data
    {
        if(data&0x01) DS1302_DAT_1;
        else DS1302_DAT_0;
        DS1302_CLK_1;    //时钟上升沿写入数据
        DS1302_CLK_0;
        data = data >> 1;
    }
    DS1302_CLK_1;    // 将时钟电平置于高电平状态 ,处于已知状态
    DS1302_RST_0;    //停止DS1302总线
}
 
//从DS1302读出一字节数据
static uint8_t DS1302_ReadByte(uint8_t addr) 
{
    uint8_t i,temp;    
    DS1302_RST_0; //这条很重要
    DS1302_CLK_0; //先将SCLK置低电平,确保写数居前SCLK被拉低
    DS1302_RST_1; //启动DS1302总线
    DS1302_DAT_OutPut_Mode();
    //写入目标地址:addr
    addr=addr|0x01; //最低位置高,寄存器0位为0时写,为1时读
    for(i=0;i<8;i++) 
    {
        if (addr&0x01) DS1302_DAT_1;
        else DS1302_DAT_0;
        DS1302_CLK_1; //写数据
        DS1302_CLK_0;
        addr = addr >> 1;
    }    
    //从DS1302读出数据:temp
    DS1302_DAT_InPut_Mode();
    for(i=0;i<8;i++)
    {
        temp=temp>>1;
        if (DS1302_DAT_IN()) temp|=0x80;
        else temp&=0x7F;
        DS1302_CLK_1;
        DS1302_CLK_0;
    }    
    DS1302_CLK_1;  //将时钟电平置于已知状态
    DS1302_RST_0;    //停止DS1302总线
    return temp;
}
/**
  * @brief  DS1302引脚初始化
  * @param  None
  * @retval None
  * @note   None
  */
static void DS1302_Init(void) 
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(DS1302_CLK_CLK | DS1302_DAT_CLK | DS1302_RST_CLK, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin=DS1302_CLK_PIN;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(DS1302_CLK_PORT,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin=DS1302_RST_PIN;
    GPIO_Init(DS1302_RST_PORT,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin=DS1302_DAT_PIN;
    GPIO_Init(DS1302_DAT_PORT,&GPIO_InitStructure);
}
/**
  * @brief  写入DS1302时间数据,初始化计时初值
  * @param  None
  * @retval None
  * @note   None
  */
static void DS1302_SetTime(uint8_t *writeTime) 
{
    DS1302_WriteByte(DS1302_CONTROL_ADDR,0x00);       //关闭写入
    DS1302_WriteByte(DS1302_SEC_ADDR,0x80);           //暂停时钟 
    //DS1302_WriteByte(DS1302_CHARGER_ADDR,0xa9);     //涓流充电 
    DS1302_WriteByte(DS1302_YEAR_ADDR,writeTime[1]);   //年 
    DS1302_WriteByte(DS1302_MONTH_ADDR,writeTime[2]);  //月 
    DS1302_WriteByte(DS1302_DAY_ADDR,writeTime[3]);    //日 
    DS1302_WriteByte(DS1302_HOUR_ADDR,writeTime[4]);   //时 
    DS1302_WriteByte(DS1302_MIN_ADDR,writeTime[5]);    //分
    DS1302_WriteByte(DS1302_SEC_ADDR,writeTime[6]);    //秒
    DS1302_WriteByte(DS1302_WEEK_ADDR,writeTime[7]);      //周 
    DS1302_WriteByte(DS1302_CHARGER_ADDR,0xA5);//打开充电功能 选择2K电阻充电方式
    DS1302_WriteByte(DS1302_CONTROL_ADDR,0x80);//打开写入 
}
/**
  * @brief  获取DS1302时间数据
  * @param  None
  * @retval None
  * @note   None
  */
static void DS1302_GetTime(DS1302TimeStruct *timeData)
{ 
    uint8_t readtime[8] = {0x20};//当前时间
  readtime[1]=DS1302_ReadByte(DS1302_YEAR_ADDR);          //年 
    readtime[2]=DS1302_ReadByte(DS1302_MONTH_ADDR);         //月 
    readtime[3]=DS1302_ReadByte(DS1302_DAY_ADDR);           //日 
    readtime[4]=DS1302_ReadByte(DS1302_HOUR_ADDR);          //时 
    readtime[5]=DS1302_ReadByte(DS1302_MIN_ADDR);           //分 
    readtime[6]=(DS1302_ReadByte(DS1302_SEC_ADDR))&0x7f;    //秒,屏蔽秒的第7位,避免超出59
    readtime[7]=DS1302_ReadByte(DS1302_WEEK_ADDR);          //周     
    timeData->year=(readtime[0]>>4)*1000+(readtime[0]&0x0F)*100+(readtime[1]>>4)*10+(readtime[1]&0x0F); //计算年份
    timeData->month=(readtime[2]>>4)*10+(readtime[2]&0x0F);  //计算月份
    timeData->day=(readtime[3]>>4)*10+(readtime[3]&0x0F);    //计算日期
    timeData->hour=(readtime[4]>>4)*10+(readtime[4]&0x0F);   //计算小时
    timeData->minute=(readtime[5]>>4)*10+(readtime[5]&0x0F); //计算分钟
    timeData->second=(readtime[6]>>4)*10+(readtime[6]&0x0F); //计算秒钟
    timeData->week=(readtime[7]&0x0F);                       //计算星期        
#ifdef DEBUG_printf
    //printf("read: %d年%d月%d日 %d时%d分%d秒\n", timeData->year, timeData->month, timeData->day, timeData->hour, timeData->minute, timeData->second);    
#endif
}

ds1302.h

  #ifndef __DS1302_H
#define __DS1302_H

#include "main.h"
#include "sys.h"


typedef struct {
    uint16_t year;
    uint8_t  month;
    uint8_t  day;
    uint8_t  hour;
    uint8_t  minute;
    uint8_t  second;
    uint8_t  week;
} DS1302TimeStruct;

typedef struct {
    void (* Init)(void);
    void (* SetTime)(uint8_t *writeTime);
    void (* GetTime)(DS1302TimeStruct *timeData);
} DS1302ClassStruct;

extern DS1302ClassStruct DS1302Class;


 
#endif

main.c

#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include "stm32f10x_exti.h"

#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "stm32f10x_gpio.h"
#include "stm32f10x_it.h"
#include "sys.h"
#include "delay.h""
#include "usart.h"
#include "myiic.h"
#include "time.h"
#include "stdlib.h"
#include "ds1302.h"

int main(void)
{
    int Mode = 0;
    uint8_t initTime[8] = {0x20, 0x23, 0x04, 0x09, 0x09, 0x00, 0x00, 0x07};
    DS1302TimeStruct getTime;
    DS1302Class.Init(); // 初始化
    DS1302Class.SetTime(initTime); // 写入时间    

    while (1)
    {
        DS1302Class.GetTime(&getTime); // 获取时间
        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == 1 && Mode == 0)
        {    
            Mode = 1;
            Serial_Printf("%d-%d-%d %d:%d:%d\n", getTime.year, getTime.month, getTime.day, getTime.hour, getTime.minute, getTime.second);
            delay_ms(500);
        } 
        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == 0 && Mode == 1) 
        {
            Mode = 0;
            Serial_Printf("%d-%d-%d %d:%d:%d\n", getTime.year, getTime.month, getTime.day, getTime.hour, getTime.minute, getTime.second);
            delay_ms(500);
        }
    }
}


  • 写回答

1条回答 默认 最新

  • 香格里辣 2024-11-06 23:48
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    从你的描述来看,DS1302模块通过串口发送的时间数据格式有问题。这种格式2165-165-165 165:165:85显然不是常见的日期和时间格式。这可能是由于读取或处理时间数据时出现了错误。这个问题可能是由于以下几个原因造成的:

    1. 读取数据错误:检查DS1302模块的数据读取是否正确。确保你正确地读取了所有寄存器,并且正确处理了读取的数据。特别是在处理小时、分钟和秒钟数据时,要特别小心。它们可能在不同的寄存器中,并且在读取时可能需要组合。另外,一些位可能被用作日期/时间的标志位(如星期几),所以在处理这些数据时要小心。
    2. 数据处理逻辑错误:检查你的数据处理逻辑是否正确。在读取时间数据后,你需要按照正确的格式组合这些数据。可能是在组合数据时出现了问题,导致输出的时间格式不正确。
    3. 串口发送数据格式问题:确保在通过串口发送数据时,数据的格式是正确的。检查是否在发送数据前对数据进行了正确的处理或转换。确保数据是以正确的格式发送到串口,并且接收端能够正确解析这些数据。

    为了解决这些问题,你可以尝试以下几个步骤:

    • 仔细检查DS1302的数据手册和通信协议,确保你的代码遵循了正确的时序和寄存器读写逻辑。
    • 在程序中添加调试打印语句,检查从DS1302读取的数据是否正确。这样可以帮助你识别是否存在数据读取或处理错误的问题。
    • 如果可能的话,使用一个示波器或逻辑分析仪来监视与DS1302的通信信号,以确保通信是准确的。
    • 检查串口发送的代码部分,确保数据被正确地格式化并发送到串口。如果有可能的话,使用一个终端仿真器来接收并解析这些数据,看看是否仍然存在问题。

    如果你能提供更多的代码细节或调试信息,我可能能够提供更具体的帮助。

    评论

报告相同问题?

问题事件

  • 创建了问题 11月6日