1、硬件连接：

2、DS1302规格书注意点

3、代码

4、结果

# 1、硬件连接：

STM32F103_PA10  --->    DS1302_RST（时能信号）

STM32F103_PA9  ------->  DS1302_I/O（输入输出信号）

STM32F103_PB13 --------> DS1302_SCLK（时钟信号）

# 3、代码

tb店上面模块附送的代码是51的。初步一看，读和写中，SCLK、IO口两线的时序不太正确。

## 3.1 DS1302Drv.c

/*
* author: xxJian
* date: 2018-9-3
* ported from https://github.com/msparks/arduino-ds1302
*
*/

#include "DS1302Drv.h"

uint8_t time_buf_reg[8] = {0x20,0x10,0x09,0x14,0x23,0x59,0x50,0x02};//³õÊ¼Ê±¼ä
uint32_t b_date, b_month, b_year, b_hour, b_minute, b_second, b_day;

// Returns the decoded decimal value from a binary-coded decimal (BCD) byte.
// Assumes 'bcd' is coded with 4-bits per digit, with the tens place digit in
// the upper 4 MSBs.
uint8_t bcdToDec(const uint8_t bcd)
{
return (10 * ((bcd & 0xF0) >> 4) + (bcd & 0x0F));
}

// Returns the binary-coded decimal of 'dec'. Inverse of bcdToDec.
uint8_t decToBcd(const uint8_t dec)
{
uint8_t tens, ones;

tens = dec / 10;
ones = dec % 10;
return (tens << 4) | ones;
}

// Returns the hour in 24-hour format from the hour register value.
uint8_t hourFromRegisterValue(const uint8_t value) {
if (value & 128)  // 12-hour mode
adj = 12 * ((value & 32) >> 5);
else           // 24-hour mode
adj = 10 * ((value & (32 + 16)) >> 4);
return (value & 15) + adj;
}

void DS1302_writeOut(const uint8_t value, uint8_t readAfter)
{
GPIO_InitTypeDef GPIO_InitStruct;
uint32_t i;

//pinMode(io_pin_, OUTPUT);
GPIO_InitStruct.Pin = DS1302_IO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DS1302_IO_GPIO_Port, &GPIO_InitStruct);

for (i = 0; i < 8; i++) {
//digitalWrite(io_pin_, (value >> i) & 1);
if( (value >> i) & 1 ) {
HAL_GPIO_WritePin(DS1302_IO_GPIO_Port, DS1302_IO_Pin, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(DS1302_IO_GPIO_Port, DS1302_IO_Pin, GPIO_PIN_RESET);
}
//HAL_Delay(1);
HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_RESET);    //digitalWrite(sclk_pin_, HIGH);
HAL_Delay(2);

if (readAfter && i == 7) {
// We're about to read data -- ensure the pin is back in input mode
// before the clock is lowered.
//pinMode(io_pin_, INPUT);
HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(DS1302_IO_GPIO_Port, DS1302_IO_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = DS1302_IO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DS1302_IO_GPIO_Port, &GPIO_InitStruct);
//HAL_Delay(1);
} else {
HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_SET);  //digitalWrite(sclk_pin_, LOW);
HAL_Delay(2);                                                                //delayMicroseconds(1);
}
}
}

{
uint8_t input_value;
uint8_t bit;
uint32_t i;

input_value = 0;
bit = 0;

GPIO_InitTypeDef GPIO_InitStruct;
HAL_GPIO_WritePin(DS1302_IO_GPIO_Port, DS1302_IO_Pin, GPIO_PIN_RESET);
//pinMode(io_pin_, INPUT);
GPIO_InitStruct.Pin = DS1302_IO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DS1302_IO_GPIO_Port, &GPIO_InitStruct);

// Bits from the DS1302 are output on the falling edge of the clock
// cycle. This is called after readIn (which will leave the clock low) or
// writeOut(..., true) (which will leave it high).
for (i = 0; i < 8; i++) {

HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_SET);    //digitalWrite(sclk_pin_, HIGH);
HAL_Delay(2);                                                                //delayMicroseconds(1);
HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_RESET);  //digitalWrite(sclk_pin_, LOW);
HAL_Delay(1);                                                                //delayMicroseconds(1);
HAL_Delay(1);
input_value |= (bit << i);  // Bits are read LSB first.
}

return input_value;
}

{
//const SPISession s(ce_pin_, io_pin_, sclk_pin_);

uint8_t cmd_byte;
uint8_t result;

HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_SET);

cmd_byte = (0x81 | (reg << 1));
DS1302_writeOut(cmd_byte, DEF_true);

HAL_Delay(1);
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_RESET);

return result;
}

void DS1302_writeRegister(const uint8_t reg, const uint8_t value)
{
//const SPISession s(ce_pin_, io_pin_, sclk_pin_);

uint8_t cmd_byte;

HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_SET);

cmd_byte = (0x80 | (reg << 1));
DS1302_writeOut(cmd_byte, DEF_false);
DS1302_writeOut(value, DEF_false);

HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_RESET);
}

void DS1302_writeProtect(const uint8_t enable)
{
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_SET);
DS1302_writeRegister(kWriteProtectReg, (enable << 7));
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_RESET);
}

void DS1302_halt(const uint8_t enable)
{
uint8_t sec;
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_SET);
sec &= ~(1 << 7);
sec |= (enable << 7);
DS1302_writeRegister(kSecondReg, sec);
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_RESET);
}

void DS1302_writeRam(const uint8_t address, const uint8_t value)
{
return;
}

}

{
return 0;
}

}

void DS1302_writeRamBulk(const uint8_t* const data, int len)
{
if (len <= 0) {
return;
}
if (len > kRamSize) {
len = kRamSize;
}

//const SPISession s(ce_pin_, io_pin_, sclk_pin_);

DS1302_writeOut(kRamBurstWrite, DEF_false);
for (int i = 0; i < len; ++i) {
DS1302_writeOut(data[i], DEF_false);
}
}

void DS1302_readRamBulk(uint8_t* const data, int len)
{
if (len <= 0) {
return;
}
if (len > kRamSize) {
len = kRamSize;
}

//const SPISession s(ce_pin_, io_pin_, sclk_pin_);

for (int i = 0; i < len; ++i) {
}
}

{
//const SPISession s(ce_pin_, io_pin_, sclk_pin_);

HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_SET);

//Time t(2099, 1, 1, 0, 0, 0, Time::kSunday);

/*
time_buf_reg[7] = DS1302_readIn() & 0x7F;  //sec
*/

b_year  = 2000 + bcdToDec(time_buf_reg[1]);
b_day   = bcdToDec(time_buf_reg[2]);
b_month = bcdToDec(time_buf_reg[3]);
b_date  = bcdToDec(time_buf_reg[4]);
b_hour  = hourFromRegisterValue(time_buf_reg[5]);
b_minute = bcdToDec(time_buf_reg[6]);
b_second = bcdToDec(time_buf_reg[7]);

HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_RESET);

}

void DS1302_timeWrite(void)
{

// We want to maintain the Clock Halt flag if it is set.
uint8_t ch_value;

HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_SET);

//const SPISession s(ce_pin_, io_pin_, sclk_pin_);

//DS1302_writeRegister(kSecondReg, decToBcd(b_second));      //DS1302¸Õ°²×°ÉÏµç³Ø£¬ÔËÐÐÕâÐÐ¡£·ñÔòÔËÐÐÏÂÃæÄÇÐÐ
DS1302_writeRegister(kSecondReg,ch_value | decToBcd(b_second));
DS1302_writeRegister(kMinuteReg,decToBcd(b_minute));
DS1302_writeRegister(kHourReg,decToBcd(b_hour));
DS1302_writeRegister(kDateReg,decToBcd(b_date));
DS1302_writeRegister(kMonthReg,decToBcd(b_month));
DS1302_writeRegister(kDayReg ,decToBcd(b_day));
DS1302_writeRegister(kYearReg,decToBcd(b_year - 2000));
/*
DS1302_writeOut(kClockBurstWrite, DEF_false);
DS1302_writeOut(ch_value | decToBcd(b_second), DEF_false);
DS1302_writeOut(decToBcd(b_minute), DEF_false);
DS1302_writeOut(decToBcd(b_hour), DEF_false);
DS1302_writeOut(decToBcd(b_date), DEF_false);
DS1302_writeOut(decToBcd(b_month), DEF_false);
DS1302_writeOut(decToBcd(b_day), DEF_false);
DS1302_writeOut(decToBcd(b_year - 2000), DEF_false);
// All clock registers *and* the WP register have to be written for the time
// to be set.
DS1302_writeOut(0, DEF_false);  // Write protection register.
DS1302_writeOut(0, DEF_false);  // Trickle Charge register.
*/

HAL_GPIO_WritePin(DS1302_SCLK_GPIO_Port, DS1302_SCLK_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(DS1302_CE_GPIO_Port, DS1302_CE_Pin, GPIO_PIN_RESET);
}


## 3.2 DS1302Drv.h

#ifndef __DS1302DRV_H__
#define __DS1302DRV_H__

#include "stm32f1xx_hal.h"

#define DEF_true 	1
#define DEF_false 0

#define kRamSize 31

#define DS1302_SCLK_GPIO_Port 	LED5_GPIO_Port
#define DS1302_SCLK_Pin 				LED5_Pin
typedef enum
{
kSecondReg       = 0,
kMinuteReg       = 1,
kHourReg         = 2,
kDateReg         = 3,
kMonthReg        = 4,
kDayReg          = 5,
kYearReg         = 6,
kWriteProtectReg = 7,
kChargeReg			 = 8,

// The RAM register space follows the clock register space.
} DS1302_Register;

typedef enum
{
kClockBurstWrite = 0xBE,
kRamBurstWrite   = 0xFE
} DS1302_Command;

typedef enum
{
kSunday    = 1,
kMonday    = 2,
kTuesday   = 3,
kWednesday = 4,
kThursday  = 5,
kFriday    = 6,
kSaturday  = 7
} DS1302_Day;

extern uint8_t time_buf_reg[8];

uint8_t bcdToDec(const uint8_t bcd) ;
uint8_t decToBcd(const uint8_t dec) ;
uint8_t hourFromRegisterValue(const uint8_t value);
void DS1302_writeOut(const uint8_t value, uint8_t readAfter) ;
void DS1302_writeRegister(const uint8_t reg, const uint8_t value) ;
void DS1302_writeProtect(const uint8_t enable) ;
void DS1302_halt(const uint8_t enable) ;
void DS1302_writeRam(const uint8_t address, const uint8_t value) ;
void DS1302_writeRamBulk(const uint8_t* const data, int len) ;
void DS1302_readRamBulk(uint8_t* const data, int len) ;

//Top layer function
void DS1302_timeWrite(void) ;

#endif /* __DS1302DRV_H__ */


# 4、结果

time_buf_reg[8]这个数据中，分别存放了DS1302中7个寄存器的读取值。见一下代码。

    time_buf_reg[7] = DS1302_readRegister(kSecondReg);    //sec
time_buf_reg[1] = DS1302_readRegister(kYearReg);      //yr

time_buf_reg[0]存放的是0x20。主要因为DS1302用1个8位的寄存器存放年份，范围只有0-99。也就是配合了0x20，所表达的范围是2000-2099。

2019年5月11日更新：有一段时间DS1302模块没有安装纽扣电池，重新使用本次代码发现有点问题。经调试发现，DS1302_timeWrite() 函数内，有一行代码是专门判断Clock Halt（时间停止）标志位是否设置的。估计是DS1302初安装纽扣电池上电时，这个时钟是停止计算的。因此，上纽扣电池的第一次执行，需要使用这行：

DS1302_writeRegister(kSecondReg, decToBcd(b_second));		

DS1302_writeRegister(kSecondReg,ch_value | decToBcd(b_second));