STM32基于HAL工程通过硬件SPI驱动DS1302

STM32基于HAL工程通过硬件SPI驱动DS1302


  • ✨申明:本文章仅发表在CSDN网站,任何其他网站,未注明来源,见此内容均为盗链和爬取,请多多尊重和支持原创!
  • 🍁对于文中所提供的相关资源链接将作不定期更换。
  • 📌相关篇《STM32基于HAL工程读取DS1302时间数据
    📍从旧版STM32CubeIDE工程中移植过来的:https://github.com/cristobalgc/DS1302_LIBRARY_STM32_SPI
  • 🎯本工程使用STM32F103VE+DS1302实物验证没有问题。
基于STM32CubeMX配置工程,当然不局限与STM32其他型号的芯片的使用,只要是stm32芯片都可以使用该源文件进行驱动,方便适配移植,减少不必要的重复开发工作。
  • 📜串口打印信息:
    在这里插入图片描述

📓STM32CubeMX配置

  • 🌿使能一个SPI接口,使用半主机模式
    在这里插入图片描述
  • 🌿配置PA4引脚位RST引脚。
    在这里插入图片描述
    在这里插入图片描述
  • 🌿使能一个串口用于调试信息输出。
    在这里插入图片描述

📑DS1302驱动文件

  • 🌿DS1302.c文件
/******************************************************************************/
/*                                                                            */
/*   All rights reserved. Distribution or duplication without previous        */
/*   written agreement of the owner prohibited.                               */
/*                                                                            */
/******************************************************************************/

/** \file ds1302.c
 *
 * \brief Source code file for DS1302
 *
 * Source code file for DS1302 manager
 *
 * <table border="0" cellspacing="0" cellpadding="0">
 * <tr> <td> Author:   </td> <td> C.Garcia   </td></tr>
 * <tr> <td> Date:     </td> <td> 27/02/2021             </td></tr>
 * </table>
 * \n
 * <table border="0" cellspacing="0" cellpadding="0">
 * <tr> <td> COMPONENT: </td> <td> DS1302  </td></tr>
 * <tr> <td> TARGET:    </td> <td> MCU        </td></tr>
 * </table>
 * \note
 *
 * \see
 */
/*https://github.com/STMicroelectronics-CentralLabs/ST_Drone_FCU_F401/blob/master/STM32%20FW%20Project/BLE%20Remocon%20Beta%20release%20301117/Drivers/BSP/STEVAL_FCU001_V1/steval_fcu001_v1.c*/
/******************************************************************************/
/*                Include common and project definition header                */
/******************************************************************************/
#include "string.h"
/******************************************************************************/
/*                      Include headers of the component                      */
/******************************************************************************/
#include "ds1302.h"

/******************************************************************************/
/*                            Include other headers                           */
/******************************************************************************/

/******************************************************************************/
/*                   Definition of local symbolic constants                   */
/******************************************************************************/
#define DS1302_24H_FORMAT			(0U)
#define DS1302_12H_FORMAT			(1U)
#define DS1302_SECONDS_MAX			(59U)
#define DS1302_MINUTES_MAX			(59U)
#define DS1302_WEEKDAY_MAX			(7U)
#define DS1302_YEAR_MAX				(2100U)
#define DS1302_HOUR_MAX				(23U)
#define DS1302_MONTHDAY_MAX			(31U)
#define DS1302_MONTH_MAX			(12U)
#define DS1302_BURST_MAX_BYTES		(8U)
#define DS1302_MILENIUM				(2000U)
#define DS1302_INSTRUCTION_CYCLES	(2U)	//The number of cycles that an instruction needs to be executed
#define DS1302_12H					(12U)
#define DS1302_WEEK_DAYS_MAX		(8U)
#define DS1302_MONTHS_MAX			(13U)
#define DS1302_AMPM_MAX				(2U)

#define DS1302_UNKNOWN	("Unknown")
#define DS1302_AM 		("AM")
#define DS1302_PM 		("PM")
#define DS1302_EMPTY 	("  ")

/******************************************************************************/
/*                  Definition of local function like macros                  */
/******************************************************************************/
//++++++++++++++++++++++++++++++++++++++++++ Conversion Macros ++++++++++++++++++++++++++++++++++++++++++//|
//  Macros to convert the bcd values of the registers to normal integer variables.  The code uses        //|
//  seperate variables for the high byte and the low byte of the bcd, so these macros handle both bytes  //|
//  seperately.
#define DS1302_BCD2BIN(h,l)   (((h)*10) + (l))
#define DS1302_BIN2BCD_H(x)   ((x)/10)
#define DS1302_BIN2BCD_L(x)   ((x)%10)

#define __SPI_DIRECTION_1LINE_TX(__HANDLE__) do{\
                                             CLEAR_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_RXONLY | SPI_CR1_CPOL );\
                                             SET_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE);\
                                             }while(0);

#define __SPI_DIRECTION_1LINE_RX(__HANDLE__) do {\
                                             CLEAR_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_RXONLY | SPI_CR1_BIDIOE);\
                                             SET_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_BIDIMODE | SPI_CR1_CPOL );\
                                             } while(0);
/******************************************************************************/
/*          Definition of local types (typedef, enum, struct, union)          */
/******************************************************************************/

/******************************************************************************/
/*                       Definition of local variables                        */
/******************************************************************************/

/******************************************************************************/
/*                     Definition of local constant data                      */
/******************************************************************************/
/* Days of a week */
static char const *ds1302_days[DS1302_WEEK_DAYS_MAX] = {DS1302_UNKNOWN, DS1302_SUNDAY, DS1302_MONDAY, DS1302_TUESDAY, DS1302_WEDNESDAY, DS1302_THURSDAY, DS1302_FRIDAY, DS1302_SATURDAY};
/* Months of a year */
static char const *ds1302_months[DS1302_MONTHS_MAX] = {DS1302_UNKNOWN, DS1302_JAN, DS1302_FEB, DS1302_MAR, DS1302_APR, DS1302_MAY, DS1302_JUN, DS1302_JUL, DS1302_AUG, DS1302_SEP, DS1302_OCT, DS1302_NOV, DS1302_DIC};
/* AM/PM*/
static char const *ds1302_AMPM[DS1302_AMPM_MAX] = {DS1302_AM, DS1302_PM};

/******************************************************************************/
/*                      Definition of exported variables                      */
/******************************************************************************/

/******************************************************************************/
/*                    Definition of exported constant data                    */
/******************************************************************************/

/******************************************************************************/
/*                  Declaration of local function prototypes                  */
/******************************************************************************/
/**
 * @brief  This function reads multiple bytes on SPI 3-wire.
 * @param[in]  ds1302: The DS1302 object.
 * @param[in]  val: value.
 * @param[in]  nBytesToRead: number of bytes to read.
 * @param[in]  Timeout: number of expected clock cycles to read a byte.
 * @retval ds1302_errors_t
 */
static ds1302_errors_t ds1302_ReadNBytes(const ds1302_T *ds1302, uint8_t *val, uint16_t nBytesToRead, uint32_t Timeout);

/**
  * @brief  Receives a Byte from the SPI bus.
  * @param[in]  ds1302: Ds1302 object.
  * @param[in]  val: the received value though SPI port.
  * @retval ds1302_errors_t
  */
static ds1302_errors_t ds1302_Read1Byte(const ds1302_T *ds1302, uint8_t *val);

/**
  * @brief  Calculate a delay in ticks of system frequency.
  * @param[in]  ds1302: The ds1302 object.
  * @retval The delay calculated in ticks of system frequency.
  */
static uint32_t ds1302_getDelay(const ds1302_T *ds1302);

/******************************************************************************/
/*                       Definition of local functions                        */
/******************************************************************************/
static ds1302_errors_t ds1302_Read1Byte(const ds1302_T *ds1302, uint8_t *val)
{
	uint16_t delay = 0u;
	ds1302_errors_t errorcode = DS1302_OK;
	/* Disable the SPI and change the data line to input */
	/* Check if the SPI is already enabled */
	if ((ds1302->cfg.spi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE){
		/* Disable SPI peripheral */
		__HAL_SPI_DISABLE(ds1302->cfg.spi);
	}
	SPI_1LINE_RX(ds1302->cfg.spi);

	__disable_irq();
	__HAL_SPI_ENABLE(ds1302->cfg.spi);
	for(delay = 0; delay < ds1302->data.delayTicks; delay++){__DSB();}
	__HAL_SPI_DISABLE(ds1302->cfg.spi);
	__enable_irq();

	while ((ds1302->cfg.spi->Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE);
	/* read the received data */
	*val = *(__IO uint8_t *)ds1302->cfg.spi->Instance->DR;

	/* Wait for the BSY flag reset */
	while ((ds1302->cfg.spi->Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY);

	return errorcode;
}


static ds1302_errors_t ds1302_ReadNBytes(const ds1302_T *ds1302, uint8_t *val, uint16_t nBytesToRead, uint32_t Timeout)
{
	uint16_t delay = 0U;
	uint32_t tickstart;

	ds1302_errors_t errorcode = DS1302_OK;

	 /* Init tickstart for timeout management*/
	 tickstart = HAL_GetTick();

	/* Disable the SPI and change the data line to input */
	/* Check if the SPI is already enabled */
	if ((ds1302->cfg.spi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE){
		/* Disable SPI peripheral */
		__HAL_SPI_DISABLE(ds1302->cfg.spi);
	}
	SPI_1LINE_RX(ds1302->cfg.spi);

	/* Interrupts should be disabled during this operation */
	__disable_irq();
	__HAL_SPI_ENABLE(ds1302->cfg.spi);

	/* Transfer loop */
	while (nBytesToRead > 1U)
	{
		/* Check the RXNE flag */
		if (ds1302->cfg.spi->Instance->SR & SPI_FLAG_RXNE)
		{
			/* read the received data */
			*val = *(__IO uint8_t *) &ds1302->cfg.spi->Instance->DR;
			val += sizeof(uint8_t);
			nBytesToRead--;
		}
		else
		{
			/* Timeout management */
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
			{
				errorcode = DS1302_TIMEOUT;
				goto error;
			}
		}
	}

	/* In master RX mode the clock is automatically generated on the SPI enable.
  	  So to guarantee the clock generation for only one data, the clock must be
  	  disabled after the first bit and before the latest bit of the last Byte received */
	/* __DSB instruction are inserted to guarantee that clock is Disabled in the right timeframe */

	for(delay=0; delay<ds1302->data.delayTicks; delay++){__DSB();}
	__HAL_SPI_DISABLE(ds1302->cfg.spi);

	__enable_irq();

	while ((ds1302->cfg.spi->Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE);
	/* read the received data */
	*val = *(__IO uint8_t *) &ds1302->cfg.spi->Instance->DR;
	while ((ds1302->cfg.spi->Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY);

error:
return errorcode;
}

static uint32_t ds1302_getDelay(const ds1302_T *ds1302){
	uint32_t HCLK_Frequency = 0U;
	uint32_t timeSpiTransferBitns = 0U;
	uint32_t execTimens = 0U;
	uint32_t spiBaudPrescaler = 0U;
	uint32_t result = 0U;

	if (ds1302 != NULL){
		switch (ds1302->cfg.spi->Init.BaudRatePrescaler){
		case SPI_BAUDRATEPRESCALER_2:
			spiBaudPrescaler = 2;
			break;
		case SPI_BAUDRATEPRESCALER_4:
			spiBaudPrescaler = 4;
			break;
		case SPI_BAUDRATEPRESCALER_8:
			spiBaudPrescaler = 8;
			break;
		case SPI_BAUDRATEPRESCALER_16:
			spiBaudPrescaler = 16;
			break;
		case SPI_BAUDRATEPRESCALER_32:
			spiBaudPrescaler = 32;
			break;
		case SPI_BAUDRATEPRESCALER_64:
			spiBaudPrescaler = 64;
			break;
		case SPI_BAUDRATEPRESCALER_128:
			spiBaudPrescaler = 128;
			break;
		case SPI_BAUDRATEPRESCALER_256:
			spiBaudPrescaler = 256;
			break;
		default:
			break;
		};

		HCLK_Frequency = HAL_RCC_GetHCLKFreq();
		timeSpiTransferBitns = HCLK_Frequency/spiBaudPrescaler;
		timeSpiTransferBitns = 1000000000000/timeSpiTransferBitns;
		execTimens = 1000000000000/HCLK_Frequency;
		result = (timeSpiTransferBitns/execTimens)/DS1302_INSTRUCTION_CYCLES;
	}

	return result;
}
/******************************************************************************/
/*                      Definition of exported functions                      */
/******************************************************************************/
ds1302_errors_t DS1302_Init(ds1302_T *ds1302, const ds1302_cfg_T *config){
	uint16_t i;
	ds1302_errors_t error = DS1302_OK;
	/* Write protect command (disable) */
	uint8_t ds1302_wp[2] = {DS1302_ENABLE, 0x00};
	/* Trickle charge command (disable) */
	uint8_t ds1302_trickle[2] = {DS1302_TRICKLE, 0x00};

	if((ds1302 != NULL) && (config != NULL)){

		ds1302->cfg.spi = config->spi;
		ds1302->cfg.RstPin.McuPort = config->RstPin.McuPort;
		ds1302->cfg.RstPin.Pinreset = config->RstPin.Pinreset;

		ds1302->data.delayTicks = ds1302_getDelay(ds1302);
		DS1302_Write(ds1302, ds1302_wp, 2);//
		for(i=0 ;i<20;i++){;}//delay
		DS1302_Write(ds1302, ds1302_trickle, 2);
		for(i=0 ;i<20;i++){;}//delay
	}else{
		error = DS1302_NOK;
	}
	return error;
}

ds1302_errors_t DS1302_Write(const ds1302_T *ds1302, uint8_t *data, uint8_t size){
	ds1302_errors_t error;
	HAL_GPIO_WritePin(ds1302->cfg.RstPin.McuPort, ds1302->cfg.RstPin.Pinreset, GPIO_PIN_SET);
	error = HAL_SPI_Transmit(ds1302->cfg.spi, data, size, DS1302_TIMEOUT_MAX);
	HAL_GPIO_WritePin(ds1302->cfg.RstPin.McuPort, ds1302->cfg.RstPin.Pinreset, GPIO_PIN_RESET);
	return error;
}

ds1302_errors_t DS1302_Read(ds1302_T *ds1302, uint8_t RegisterAddr, uint8_t *ptr, uint8_t nbytes){
	ds1302_errors_t error;

	RegisterAddr|= 0x01U;// last bit should be set for read

	HAL_GPIO_WritePin(ds1302->cfg.RstPin.McuPort, ds1302->cfg.RstPin.Pinreset, GPIO_PIN_SET);
	HAL_SPI_Transmit(ds1302->cfg.spi, &RegisterAddr, 1, DS1302_TIMEOUT_MAX);
	/* Check if we need to read one byte or more */
	if(nbytes > 1U){
		error = ds1302_ReadNBytes(ds1302, ptr, nbytes, DS1302_TIMEOUT_MAX);
	}else{
		error = ds1302_Read1Byte(ds1302, ptr);
	}
	HAL_GPIO_WritePin(ds1302->cfg.RstPin.McuPort, ds1302->cfg.RstPin.Pinreset, GPIO_PIN_RESET);
	/* Change the data line to output and enable the SPI */
	SPI_1LINE_TX(ds1302->cfg.spi);
	__HAL_SPI_ENABLE(ds1302->cfg.spi);
	return error;
}

ds1302_errors_t DS1302_setTime(ds1302_T *ds1302, const uint8_t hformat, const uint8_t hours, const uint8_t minutes,
		const uint8_t seconds, const uint8_t ampm , const uint8_t dayofweek, const uint8_t dayofmonth, const uint8_t month,
		const int year){
	uint8_t arraysend[9];
	ds1302_errors_t error;
	arraysend[0] = DS1302_CLOCK_BURST_WRITE;
	memset ((char *)&ds1302->data.send, 0, sizeof(rtc_T));
	if((seconds <= DS1302_SECONDS_MAX) && (minutes <= DS1302_MINUTES_MAX) &&
			(hours <= DS1302_HOUR_MAX) && (dayofweek <= DS1302_WEEKDAY_MAX) &&
			(dayofmonth <= DS1302_MONTHDAY_MAX) && (month <= DS1302_MONTH_MAX ) &&
			(year <= DS1302_YEAR_MAX)){

		ds1302->data.send.seconds.b.Seconds10 = DS1302_BIN2BCD_H( seconds);
		ds1302->data.send.seconds.b.Seconds = DS1302_BIN2BCD_L( seconds);
		ds1302->data.send.seconds.b.CH = 0;  // 1 for Clock Halt, 0 to run

		ds1302->data.send.Minutes.b.Minutes10 = DS1302_BIN2BCD_H(minutes);
		ds1302->data.send.Minutes.b.Minutes = DS1302_BIN2BCD_L(minutes);

		if((hformat) && (hours <= DS1302_12H)){
			ds1302->data.send.Hour.h12.b.Hour10 = DS1302_BIN2BCD_H(hours);
			ds1302->data.send.Hour.h12.b.Hour = DS1302_BIN2BCD_L(hours);
			ds1302->data.send.Hour.h12.b.AM_PM = ampm;
			ds1302->data.send.Hour.h12.b.hour_12_24 = DS1302_12H_FORMAT;
		} else {
			ds1302->data.send.Hour.h24.b.Hour10 = DS1302_BIN2BCD_H(hours);
			ds1302->data.send.Hour.h24.b.Hour = DS1302_BIN2BCD_L(hours);
			ds1302->data.send.Hour.h24.b.hour_12_24 = DS1302_24H_FORMAT; // 0 for 24 hour format
		}

		ds1302->data.send.MonthDay.b.MonthDay10 = DS1302_BIN2BCD_H(dayofmonth);
		ds1302->data.send.MonthDay.b.MonthDay = DS1302_BIN2BCD_L(dayofmonth);

		ds1302->data.send.Month.b.Month10 = DS1302_BIN2BCD_H(month);
		ds1302->data.send.Month.b.Month = DS1302_BIN2BCD_L(month);

		ds1302->data.send.Weekday.b.Day = dayofweek;

		ds1302->data.send.Year.b.Year10 = DS1302_BIN2BCD_H(year-DS1302_MILENIUM);
		ds1302->data.send.Year.b.Year = DS1302_BIN2BCD_L(year-DS1302_MILENIUM);

		ds1302->data.send.WriteProct.b.WP = 0U;
	}
	memcpy(&arraysend[1], &ds1302->data.send, DS1302_BURST_MAX_BYTES);
	error = DS1302_Write(ds1302, arraysend, 9);
	return error;
}

ds1302_errors_t DS1302_updateDateTime(ds1302_T *ds1302) {
	ds1302_errors_t error = DS1302_OK;
	uint8_t month;
	if(ds1302 != NULL){
		error = DS1302_Read(ds1302, DS1302_CLOCK_BURST_READ, (uint8_t*)&ds1302->data.received, DS1302_BURST_MAX_BYTES);

		month = DS1302_BCD2BIN(ds1302->data.received.Month.b.Month10, ds1302->data.received.Month.b.Month);

		if(!ds1302->data.received.Hour.h24.b.hour_12_24){
			ds1302->data.dateandtime.hours = DS1302_BCD2BIN(ds1302->data.received.Hour.h24.b.Hour10, ds1302->data.received.Hour.h24.b.Hour);
			ds1302->data.dateandtime.amPm = DS1302_EMPTY;
		}else{
			ds1302->data.dateandtime.hours = DS1302_BCD2BIN(ds1302->data.received.Hour.h12.b.Hour10, ds1302->data.received.Hour.h12.b.Hour);
			ds1302->data.dateandtime.amPm = ds1302_AMPM[ds1302->data.received.Hour.h12.b.AM_PM];
		}

		ds1302->data.dateandtime.minutes = DS1302_BCD2BIN(ds1302->data.received.Minutes.b.Minutes10, ds1302->data.received.Minutes.b.Minutes);
		ds1302->data.dateandtime.seconds = DS1302_BCD2BIN(ds1302->data.received.seconds.b.Seconds10, ds1302->data.received.seconds.b.Seconds);
		ds1302->data.dateandtime.weekday = ds1302_days[ds1302->data.received.Weekday.b.Day];
		ds1302->data.dateandtime.month = ds1302_months[month];
		ds1302->data.dateandtime.monthday =  DS1302_BCD2BIN(ds1302->data.received.MonthDay.b.MonthDay10, ds1302->data.received.MonthDay.b.MonthDay);
		ds1302->data.dateandtime.year = DS1302_BCD2BIN(ds1302->data.received.Year.b.Year10, ds1302->data.received.Year.b.Year) + DS1302_MILENIUM;
	} else {
		error = DS1302_NOK;
	}

	return error;
}


uint8_t DS1302_getSecondsUnits(ds1302_T *ds1302) {

	return ds1302->data.received.seconds.b.Seconds;
}

uint8_t DS1302_getSecondsDec(ds1302_T *ds1302){

	return ds1302->data.received.seconds.b.Seconds10;
}

uint8_t DS1302_getMinutesUnits(ds1302_T *ds1302){

	return ds1302->data.received.Minutes.b.Minutes;
}

uint8_t DS1302_getMinutesDec(ds1302_T *ds1302){

	return ds1302->data.received.Minutes.b.Minutes10;
}

uint8_t DS1302_getHourUnits(ds1302_T *ds1302){
	uint8_t ret;
	if(ds1302->data.received.Hour.h24.b.hour_12_24 == DS1302_24H_FORMAT){
		ret = ds1302->data.received.Hour.h24.b.Hour;
	}else{
		ret = ds1302->data.received.Hour.h12.b.Hour;
	}
	return ret;
}

uint8_t DS1302_getHourDec(ds1302_T *ds1302){
	uint8_t ret;
	if(ds1302->data.received.Hour.h24.b.hour_12_24 == DS1302_24H_FORMAT){
		ret = ds1302->data.received.Hour.h24.b.Hour10;
	}else{
		ret = ds1302->data.received.Hour.h12.b.Hour10;
	}
	return ret;
}

const char* DS1302_getAmPmStatus(ds1302_T *ds1302){
	return ds1302->data.dateandtime.amPm;
}

uint8_t DS1302_getMonthDay(ds1302_T *ds1302){
	return ds1302->data.dateandtime.monthday;
}

const char * DS1302_getMonth(ds1302_T *ds1302){
	return ds1302->data.dateandtime.month;
}

extern uint16_t DS1302_getYear(ds1302_T *ds1302){
	return ds1302->data.dateandtime.year;
}

const char* DS1302_geWeekDay(ds1302_T *ds1302){
	return ds1302->data.dateandtime.weekday;
}

  • 🌿DS1302.h文件
/******************************************************************************/
/*                                                                            */
/*   All rights reserved. Distribution or duplication without previous        */
/*   written agreement of the owner prohibited.                               */
/*                                                                            */
/******************************************************************************/

/** \file ds1302.h
 *
 * \brief Header file for DS1302 component
 *
 * Header file for DS1302 manager

 */

#ifndef DS_1302_H_
#define DS_1302_H_

/******************************************************************************/
/*                         Project Includes                                   */
/******************************************************************************/
#include "stm32f1xx_hal.h"
/******************************************************************************/
/*                 Definition of exported symbolic constants                  */
/******************************************************************************/
/* Days of a Week */
#define DS1302_MONDAY "Mon"
#define DS1302_TUESDAY "Tue"
#define DS1302_WEDNESDAY "Wed"
#define DS1302_THURSDAY "Thu"
#define DS1302_FRIDAY "Fri"
#define DS1302_SATURDAY "Sat"
#define DS1302_SUNDAY "Sun"
/* Months of a year */
#define DS1302_JAN  "Jan"
#define DS1302_FEB "Feb"
#define DS1302_MAR "Mar"
#define DS1302_APR "Apr"
#define DS1302_MAY "May"
#define DS1302_JUN "Jun"
#define DS1302_JUL "Jul"
#define DS1302_AUG "Aug"
#define DS1302_SEP "Sep"
#define DS1302_OCT "Oct"
#define DS1302_NOV "Nov"
#define DS1302_DIC "Dec"

//+++++++++++++++++++++++++++++++++++++++++ Set Register Names ++++++++++++++++++++++++++++++++++++++++++//
//  Since the highest bit is always '1', the registers start at 0x80.  If the register is read, the      //|
//  lowest bit should be '1'.                                                                            //|

#define DS1302_SECONDS           (0x80U)
#define DS1302_MINUTES           (0x82U)
#define DS1302_HOURS             (0x84U)
#define DS1302_DATE              (0x86U)
#define DS1302_MONTH             (0x88U)
#define DS1302_DAY               (0x8AU)
#define DS1302_YEAR              (0x8CU)
#define DS1302_CLOCK_BURST       (0xBEU)
#define DS1302_CLOCK_BURST_WRITE (0xBEU)
#define DS1302_CLOCK_BURST_READ  (0xBFU)
#define DS1302_RAMSTART          (0xC0U)
#define DS1302_RAMEND            (0xFCU)
#define DS1302_RAM_BURST         (0xFEU)
#define DS1302_RAM_BURST_WRITE   (0xFEU)
#define DS1302_RAM_BURST_READ    (0xFFU)

#define DS1302_ENABLE            (0x8EU)
#define DS1302_TRICKLE           (0x90U)
#define DS1302_TIMEOUT_MAX       (100U)
/******************************************************************************/
/*                Definition of exported function like macros                 */
/******************************************************************************/

/******************************************************************************/
/*         Definition of exported types (typedef, enum, struct, union)        */
/******************************************************************************/
typedef enum ds1302_errors_e
{
    DS1302_NOK,     /**< DS1302 ERROR */
    DS1302_OK,      /**< DS1302 OK */
    DS1302_TIMEOUT  /**< DS1302 timeout */
} ds1302_errors_t;

typedef struct
{
    union
    {
        uint8_t reg;
        struct
        {
            uint8_t Seconds: 4;            /**< 4-bits to hold low decimal digits 0-9 */
            uint8_t Seconds10: 3;          /**< 3-bits to hold high decimal digit 0-5 */
            uint8_t CH: 1;                 /**< 1-bit to hold CH = Clock Halt */
        } b;
    } seconds;

    union
    {
        uint8_t reg;
        struct
        {
            uint8_t Minutes: 4;         /**< 4-bits to hold low decimal digits 0-9 */
            uint8_t Minutes10: 3;       /**< 3-bits to hold high decimal digit 0-5 */
            uint8_t reserved1: 1;       /**< Reserved */
        } b;
    } Minutes;

    union
    {

        union
        {
            uint8_t reg;
            struct                                                // 24-hour section
            {
                uint8_t Hour: 4;         /**< 4-bits to hold low decimal digits 0-9 */
                uint8_t Hour10: 2;       /**< 2-bits to hold high decimal digits 0-2 */
                uint8_t reserved2: 1;    /**< Reserved */
                uint8_t hour_12_24: 1;   /**< 1-bit to set 0 for 24 hour format  */
            } b;
        } h24;

        union
        {
            uint8_t reg;
            struct                                                // 12 hour section
            {
                uint8_t Hour: 4;        /**< 4-bits to hold low decimal digits 0-9 */
                uint8_t Hour10: 1;      /**< 2-bits to hold high decimal digits 0-2 */
                uint8_t AM_PM: 1;       /**< 1-bit to set AM or PM, 0 = AM, 1 = PM */
                uint8_t reserved2: 1;   /**< Reserved */
                uint8_t hour_12_24: 1;  /**< 1-bit to set 1 for 12 hour format  */
            } b;
        } h12;
    } Hour;

    union
    {
        uint8_t reg;
        struct
        {
            uint8_t MonthDay: 4;        /**< 4-bits to hold low decimal digits 0-9 */
            uint8_t MonthDay10: 2;      /**< 2-bits to hold high decimal digits 0-3 */
            uint8_t reserved3: 2;       /**< Reserved */
        } b;
    } MonthDay;

    union
    {
        uint8_t reg;
        struct
        {
            uint8_t Month: 4;       /**< 4-bits to hold low decimal digits 0-9 */
            uint8_t Month10: 1;     /**< 1-bits to hold high decimal digits 0-5 */
            uint8_t reserved4: 3;   /**< Reserved */
        } b;
    } Month;

    union
    {
        uint8_t reg;
        struct
        {
            uint8_t Day: 3;         /**< 3-bits to hold decimal digit 1-7 */
            uint8_t reserved5: 5;   /**< Reserved */
        } b;
    } Weekday;
    union
    {
        uint8_t reg;
        struct
        {
            uint8_t Year: 4;      /**< 4-bits to hold high decimal digit 20 */
            uint8_t Year10: 4;    /**< 4-bits to hold high decimal digit 14 */
        } b;
    } Year;

    union
    {
        uint8_t reg;
        struct
        {
            uint8_t reserved6: 7; /**< Reserved */
            uint8_t WP: 1;        /**< WP = Write Protect */
        } b;
    } WriteProct;

} rtc_T;

typedef struct ds1302_gpio_cfg_s
{
    GPIO_TypeDef *McuPort; /**< The selected Port for the CE signal, it can be GPIOA, GPIOB...*/
    uint16_t Pinreset; /**< The GPIO pin into the port for the CE signal, it can be GPIO_PIN_4, GPIO_PIN_5...*/
} ds1302_gpio_cfg_t;


typedef struct ds1302_cfg_s
{
    SPI_HandleTypeDef *spi;
    ds1302_gpio_cfg_t RstPin;
} ds1302_cfg_T;

typedef struct ds1302_datatime_s
{
    uint8_t seconds;
    uint8_t hours;
    uint8_t minutes;
    uint8_t monthday;
    const char *month;
    const char *weekday;
    const char *amPm;
    uint16_t year;
} ds1302_datatime_t;

typedef struct ds1302_data_s
{
    uint32_t delayTicks;
    rtc_T received;
    rtc_T send;
    ds1302_datatime_t dateandtime;
} ds1302_data_T;

typedef struct ds1302_s
{
    ds1302_cfg_T cfg;
    ds1302_data_T data;
} ds1302_T;
/******************************************************************************/
/*                    Declaration of exported variables                       */
/******************************************************************************/

/******************************************************************************/
/*                  Declaration of exported constant data                     */
/******************************************************************************/

/******************************************************************************/
/*               Declaration of exported function prototypes                  */
/******************************************************************************/

/**
  * @brief  Initialize the DS1302 Driver.
  * @param[in]  ds1302: The Ds1302 object.
  * @param[in]  config: The configuration to be applied into the selected DS1302 object.
  * @retval   ds1302_errors_t
  *
 */
extern ds1302_errors_t DS1302_Init(ds1302_T *ds1302, const ds1302_cfg_T *config);

/**
  * @brief  Write a valid command into the driver .
  * @param[in]  ds1302: The DS1302 object.
  * @param[in]  data: Data to be written
  * @param[in]  size: Data size.
  * @retval   ds1302_errors_t
  *
 */
extern ds1302_errors_t DS1302_Write(const ds1302_T *ds1302,  uint8_t *data, uint8_t size);

/**
  * @brief  Set the date-time into the DS1302 chip.
  * @param[in]  ds1302: The DS1302 object.
  * @param[in]  hformat: Hour format. Set 0 for 24H format. Set 1 for 12h format.
  * @param[in]  hours: Number of hours to set into the driver.
  * @param[in]  minutes: Number of minutes to set into the driver.
  * @param[in]  seconds: Number of seconds to set into the driver.
  * @param[in]  ampm: In case of 12h format : 0 = AM, 1 = PM.
  * @param[in]  dayofweek : Day of week to set into the driver.
  * @param[in]  dayofmonth: Day of month to set into the driver.
  * @param[in]  month: Month to set into the driver.
  * @param[in]  year: Year to set into the driver.
  * @retval   ds1302_errors_t
 */
extern ds1302_errors_t DS1302_setTime(ds1302_T *ds1302, const uint8_t hformat, const uint8_t hours, const uint8_t minutes,
                                      const uint8_t seconds, const uint8_t ampm , const uint8_t dayofweek, const uint8_t dayofmonth, const uint8_t month,
                                      const int year);
/**
  * @brief  Read from a register
  * @param[in]  ds1302: The DS1302 object.
  * @param[in]  RegisterAddr: specifies the ds1302 register to be written.
  * @param[in]  ptr: Data to be written
  * @param[in]  nbytes: Number of bytes to be written in to the driver
  * @retval   None
 */
extern ds1302_errors_t DS1302_Read(ds1302_T *ds1302, uint8_t RegisterAddr, uint8_t *ptr, uint8_t nbytes);

/**
  * @brief  Update the date and time of the DS1302 driver.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   ds1302_errors_t
 */
extern ds1302_errors_t DS1302_updateDateTime(ds1302_T *ds1302);

/**
  * @brief  Get the unit part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The unit part of the seconds number
 */
extern uint8_t DS1302_getSecondsUnits(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint8_t DS1302_getSecondsDec(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint8_t DS1302_getMinutesUnits(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint8_t DS1302_getMinutesDec(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint8_t DS1302_getHourUnits(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint8_t DS1302_getHourDec(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern const char *DS1302_geWeekDay(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern const char *DS1302_getAmPmStatus(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint8_t DS1302_getMonthDay(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern const char *DS1302_getMonth(ds1302_T *ds1302);

/**
  * @brief  Get the decimal part of the seconds.
  * @param[in]  ds1302: The DS1302 object.
  * @retval   The decimal part of the seconds number
 */
extern uint16_t DS1302_getYear(ds1302_T *ds1302);

#endif /* SW_COMPONENT */

📝主程序代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "ds1302.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define HOUR_FORMAT (0) // 0 = 0-24h; 1= 0-12h
#define HOUR        (21U)
#define MINUTES     (20U)
#define SECONDS     (45U)
#define AM_PM       (1U)
#define WEEKDAY     (2U)
#define MONTHDAY    (3U)
#define MONTH       (4U)
#define YEAR        (2023U)
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define DS1302_BCD2BIN(h,l)   (((h)*10) + (l))
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
static ds1302_T rtc;

static ds1302_cfg_T ds1302_config =
{
    &hspi1,
    {GPIOA, GPIO_PIN_4}
};
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    uint32_t TimerUART = HAL_GetTick();
    DS1302_Init(&rtc, &ds1302_config);//初始化DS1302
		//设置时间到DS1302中
//  DS1302_setTime(&rtc, HOUR_FORMAT, HOUR, MINUTES, SECONDS, AM_PM, WEEKDAY, MONTHDAY, MONTH, YEAR);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

        if ((HAL_GetTick() - TimerUART) > 3000)
        {
            DS1302_updateDateTime(&rtc);
					printf("%02d-%s-%02d %02d : %02d : %02d T:%s", \
					rtc.data.dateandtime.year, rtc.data.dateandtime.month, rtc.data.dateandtime.monthday,\
					rtc.data.dateandtime.hours, rtc.data.dateandtime.minutes, rtc.data.dateandtime.seconds,\
					rtc.data.dateandtime.weekday
					);
            TimerUART = HAL_GetTick();
            HAL_GPIO_TogglePin(GPIOE, LED_Pin);
        }
    }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

📚工程源码

  • ✨申明:本文章仅发表在CSDN网站,任何其他网站,未注明来源,见此内容均为盗链和爬取,请多多尊重和支持原创!
  • 🍁对于文中所提供的相关资源链接将作不定期更换。
链接: https://pan.baidu.com/s/16cikuHeYi6-u6oI-qi0vxA
提取码: ezgz

  我问沧海何时老,清风问我几时闲。--元代高克恭的《怡然观海》。
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值