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

stm32使用DS1302实时时钟模块

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

ds1302.c

#include "ds1302.h"
#include "sys.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[7] = {0x20};//初始时间
uint8_t readtime[7] = {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                    GPIOA
#define DS1302_DAT_CLK                    RCC_APB2Periph_GPIOA
#define DS1302_DAT_PIN                    GPIO_Pin_11

#define DS1302_RST_PORT                    GPIOB
#define DS1302_RST_CLK                    RCC_APB2Periph_GPIOB
#define DS1302_RST_PIN                    GPIO_Pin_2

// 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_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_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_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[7] = {0x20, 0x24, 0x11, 0x07, 0x12, 0x00, 0x00};//当前时间
      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
    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); //计算秒钟
#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 "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;
    // 202411111200秒
    uint8_t initTime[8] = {0x20, 0x24, 0x11, 0x07, 0x12, 0x00, 0x00};
    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:24
    关注

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

    根据你提供的代码和问题描述,看起来你在使用DS1302实时时钟模块时遇到了串口发送时间格式不正确的问题。你提到从DS1302读取的时间数据显示为类似"2165-165-165 165:165:85"的格式,这明显不是正常的日期和时间格式。这个问题可能源于你在读取或处理DS1302时间数据时存在错误。

    首先,你应该检查DS1302的返回值是否正确。DS1302的返回值应该是BCD格式,即年、月、日、小时、分钟和秒都是以十进制数值的形式返回。你需要将这些BCD值转换为正常的十进制数值。在你的代码中,你似乎已经在做这样的转换,但是可能存在错误。

    另外,你的代码中的DS1302Class.GetTime(&getTime)函数返回的可能是原始的BCD值,而不是转换后的十进制值。你需要确保在读取时间后正确地将BCD值转换为十进制值。你可以尝试修改GetTime函数,使其在返回之前完成这个转换。

    另外,你还需要检查你的串口发送函数是否正确工作。确保你正在以正确的格式发送数据,并且数据的字节顺序(大端或小端)是正确的。如果你在发送数据前没有进行正确的字节顺序转换,那么可能会出现类似的问题。

    如果以上都没有问题,那么问题可能在于你的DS1302模块本身可能存在故障或者配置不正确。你需要检查DS1302模块的接线是否正确,以及模块的时钟和电源是否正常。

    希望这些信息能帮助你解决问题。如果你还有其他问题或需要进一步的帮助,请告诉我更多关于你的问题的细节。

    评论

报告相同问题?

问题事件

  • 修改了问题 11月6日
  • 创建了问题 11月6日