https://github.com/cristobalgc/DS1302_LIBRARY_STM32_SPI
基于STM32CubeMX配置工程,当然不局限与STM32其他型号的芯片的使用,只要是stm32芯片都可以使用该源文件进行驱动,方便适配移植,减少不必要的重复开发工作。
/******************************************************************************/
/* */
/* 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
*
*
* Author: C.Garcia
* Date: 27/02/2021
*
* \n
*
* COMPONENT: DS1302
* TARGET: MCU
*
* \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;
}
/******************************************************************************/
/* */
/* 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 */
链接: https://pan.baidu.com/s/16cikuHeYi6-u6oI-qi0vxA
提取码: ezgz
我问沧海何时老,清风问我几时闲。--元代高克恭的《怡然观海》。 |
---|