一、直接上代码
本人新手小白,写的很烂,代码可以运行,设置和读取时间正常。若有不足,恳请斧正。
RtcDs1338.c
/*
RtcDs1338.c
Implementation File for Ds1338 Module
*/
/*
modification history
--------------------
01a, 20Mar24, Jasper Created
*/
/* Includes */
#include "include.h"
#include <cmsis_os.h>
#include "BspI2C.h"
#include "Rtc/RtcDs1338.h"
#if (RTC_ENABLE && RTC_DS1338_ENABLE)
/* Pragmas */
#pragma diag_suppress 177 /* warning: #177-D: function "FUNC" was set but never used */
#pragma diag_suppress 550 /* warning: #550-D: variable was set but never used */
/* Debug config */
#if RTC_DEBUG || 1
#undef TRACE
#define TRACE(...) DebugPrintf(__VA_ARGS__)
#else
#undef TRACE
#define TRACE(...)
#endif /* RTC_DEBUG */
#if RTC_ASSERT
#undef ASSERT
#define ASSERT(a) while(!(a)){DebugPrintf("ASSERT failed: %s %d\n", __FILE__, __LINE__);}
#else
#undef ASSERT
#define ASSERT(...)
#endif /* RTC_ASSERT */
/* Local defines */
/* Register definition */
#define DS1338_REG_SECONDS (0x00)
#define DS1338_REG_MINUTES (0x01)
#define DS1338_REG_HOURS (0x02)
#define DS1338_REG_DAY (0x03)
#define DS1338_REG_DATE (0x04)
#define DS1338_REG_MONTH (0x05)
#define DS1338_REG_YEAR (0x06)
#define DS1338_REG_CONTROL (0x07)
#define DS1338_REG_RAM_BEGIN (0x08)
#define DS1338_REG_RAM_END (0x3F)
/* Local types */
typedef struct {
uint8_t ucYear; /* Bcd: 0~99 */
uint8_t ucMon; /* Bcd: 1~12 */
uint8_t ucDay; /* Bcd: 1~31 */
uint8_t ucWeek; /* Bcd: 1~7 */
uint8_t ucHour; /* Bcd: 1~12 / 0~23 */
uint8_t ucMin; /* Bcd: 0~59 */
uint8_t ucSec; /* Bcd: 0~59 */
}DsTime_t;
/* Forward declaration */
static uint8_t prvDs1338ReadTime(DsTime_t *time);
static uint8_t prvDs1338WriteTime(DsTime_t *time);
static Time_t prvDs1338ToStdCTime(DsTime_t* pxDsTm);
static DsTime_t prvStdCToDs1338Time(Time_t* pxTm);
static uint8_t prvBcdToDec(uint8_t ucBcd);
static uint8_t prvDecToBcd(uint8_t ucDec);
static Status_t prvPrintDs1338Time(DsTime_t *pxDsTm);
static Status_t prvPrintStdCTime(Time_t *pxTm);
/* Local variables */
static Bool_t s_bInit = FALSE;
static Bool_t s_bConfig = FALSE;
#if RTC_RTOS
static osMutexId s_xMutex;
#endif /* RTC_RTOS */
/* Local defines */
#if RTC_RTOS
#define DS1338_MUTEX_INIT() do{ \
osMutexDef(Ds1338Mutex); \
s_xMutex = osMutexCreate(osMutex(Ds1338Mutex)); \
}while(0)
#define DS1338_LOCK() osMutexWait(s_xMutex, osWaitForever)
#define DS1338_UNLOCK() osMutexRelease(s_xMutex)
#else
#define DS1338_MUTEX_INIT()
#define DS1338_LOCK()
#define DS1338_UNLOCK()
#endif /* RTC_RTOS */
#define DS1338_RAM_SIZE (31)
/* Functions */
Status_t RtcDs1338Init(void)
{
if (s_bInit == FALSE) {
DS1338_MUTEX_INIT();
#if RTC_RTOS
if (NULL == s_xMutex) {
TRACE("RtcDs1302Init create mutex failed\n");
return STATUS_ERR;
}
#endif /* RTC_RTOS */
s_bInit = TRUE;
return STATUS_OK;
}
else {
return STATUS_ERR;
}
}
Time_t RtcDs1338ReadTime(void)
{
DsTime_t xDsTm;
ASSERT((TRUE == s_bInit) && (TRUE == s_bConfig));
DS1338_LOCK();
prvDs1338ReadTime(&xDsTm);
DS1338_UNLOCK();
return prvDs1338ToStdCTime(&xDsTm);
}
Status_t RtcDs1338WriteTime(Time_t xTm)
{
DsTime_t xDsTm;
ASSERT((TRUE == s_bInit) && (TRUE == s_bConfig));
DS1338_LOCK();
xDsTm = prvStdCToDs1338Time(&xTm);
prvDs1338WriteTime(&xDsTm);
DS1338_UNLOCK();
return STATUS_OK;
}
#if (RTC_STDC_TIME == 3)
time_t time(time_t * timer)
{
Time_t tm;
time_t t;
tm = RtcDs1338ReadTime();
t = mktime(&tm);
if (NULL == timer) {
return t;
}
else {
*timer = t;
return t;
}
}
#endif /* (RTC_STDC_TIME == 3) */
static uint8_t prvDs1338ReadTime(DsTime_t *time)
{
uint8_t buf[7];
I2C_ReadData(DS1338_ADDR, DS1338_REG_SECONDS, &buf[0], 1);
I2C_ReadData(DS1338_ADDR, DS1338_REG_MINUTES, &buf[1], 1);
I2C_ReadData(DS1338_ADDR, DS1338_REG_HOURS, &buf[2], 1);
I2C_ReadData(DS1338_ADDR, DS1338_REG_DAY, &buf[3], 1);
I2C_ReadData(DS1338_ADDR, DS1338_REG_DATE, &buf[4], 1);
I2C_ReadData(DS1338_ADDR, DS1338_REG_MONTH, &buf[5], 1);
I2C_ReadData(DS1338_ADDR, DS1338_REG_YEAR, &buf[6], 1);
time->ucSec = prvBcdToDec(buf[0]);
time->ucMin = prvBcdToDec(buf[1]);
if (buf[2] & DS1338_HOUR_12)
{
time->ucHour = ((buf[2] >> 4) & 0x01) * 12 + ((buf[2] >> 5) & 0x01) * 12;
}
else
{
time->ucHour = prvBcdToDec(buf[2]);
}
time->ucDay = prvBcdToDec(buf[4]);
time->ucMon = prvBcdToDec(buf[5] & 0x1F);
time->ucYear = prvBcdToDec(buf[6]);
return 0;
}
static uint8_t prvDs1338WriteTime(DsTime_t *time)
{
uint8_t buf[7];
buf[0] = prvDecToBcd(time->ucSec);
buf[1] = prvDecToBcd(time->ucMin);
buf[2] = prvDecToBcd(time->ucHour); // Time always stored in 24-hour format
buf[3] = 1; // Not used
buf[4] = prvDecToBcd(time->ucDay);
buf[5] = prvDecToBcd(time->ucMon);
buf[6] = prvDecToBcd(time->ucYear);
I2C_WriteData(DS1338_ADDR, DS1338_REG_SECONDS, &buf[0], 1);
I2C_WriteData(DS1338_ADDR, DS1338_REG_MINUTES, &buf[1], 1);
I2C_WriteData(DS1338_ADDR, DS1338_REG_HOURS, &buf[2], 1);
I2C_WriteData(DS1338_ADDR, DS1338_REG_DAY, &buf[3], 1);
I2C_WriteData(DS1338_ADDR, DS1338_REG_DATE, &buf[4], 1);
I2C_WriteData(DS1338_ADDR, DS1338_REG_MONTH, &buf[5], 1);
I2C_WriteData(DS1338_ADDR, DS1338_REG_YEAR, &buf[6], 1);
return 0;
}
static Time_t prvDs1338ToStdCTime(DsTime_t* pxDsTm)
{
Time_t cTm;
cTm.tm_sec = (pxDsTm->ucSec); /* seconds after the minute, 0 to 60 (0 - 60 allows for the occasional leap second) */
cTm.tm_min = (pxDsTm->ucMin); /* minutes after the hour, 0 to 59 */
cTm.tm_hour = (pxDsTm->ucHour); /* hours since midnight, 0 to 23 */
cTm.tm_mday = (pxDsTm->ucDay); /* day of the month, 1 to 31 */
cTm.tm_mon = (pxDsTm->ucMon)-1; /* months since January, 0 to 11 */
cTm.tm_year = (pxDsTm->ucYear)+100; /* years since 1900 */
cTm.tm_wday = (pxDsTm->ucWeek)-1; /* days since Sunday, 0 to 6 */
cTm.tm_yday = (0); /* days since January 1, 0 to 365 */
cTm.tm_isdst = (0); /* Daylight Savings Time flag */
return cTm;
}
static DsTime_t prvStdCToDs1338Time(Time_t* pxTm)
{
DsTime_t xDsTm;
xDsTm.ucYear = (pxTm->tm_year-100); /* 0~99 */
xDsTm.ucMon = (pxTm->tm_mon+1); /* 1~12 */
xDsTm.ucDay = (pxTm->tm_mday); /* 1~31 */
xDsTm.ucWeek = (pxTm->tm_wday+1); /* 1~7 */
xDsTm.ucHour = (pxTm->tm_hour); /* 1~12 / 0~23 */
xDsTm.ucMin = (pxTm->tm_min); /* 0~59 */
xDsTm.ucSec = (pxTm->tm_sec); /* 0~59 */
return xDsTm;
}
static uint8_t prvBcdToDec(uint8_t ucBcd)
{
return ((ucBcd >> 4) * 10 + (ucBcd & 0x0F));
}
static uint8_t prvDecToBcd(uint8_t ucDec)
{
return ((((ucDec / 10) & 0x0F) << 4) + (ucDec % 10));
}
static Status_t prvPrintDs1338Time(DsTime_t *pxDsTm)
{
TRACE("prvPrintDs1302Time:\n");
TRACE(" ucYear: %02X\n", pxDsTm->ucYear);
TRACE(" ucMon: %02X\n", pxDsTm->ucMon);
TRACE(" ucDay: %02X\n", pxDsTm->ucDay);
TRACE(" ucWeek: %02X\n", pxDsTm->ucWeek);
TRACE(" ucHour: %02X\n", pxDsTm->ucHour);
TRACE(" ucMin: %02X\n", pxDsTm->ucMin);
TRACE(" ucSec: %02X\n", pxDsTm->ucSec);
return STATUS_OK;
}
static Status_t prvPrintStdCTime(Time_t *pxTm)
{
TRACE("prvPrintStdCTime:\n");
TRACE(" tm_year: %d\n", pxTm->tm_year);
TRACE(" tm_mon: %d\n", pxTm->tm_mon);
TRACE(" tm_mday: %d\n", pxTm->tm_mday);
TRACE(" tm_wday: %d\n", pxTm->tm_wday);
TRACE(" tm_yday: %d\n", pxTm->tm_yday);
TRACE(" tm_hour: %d\n", pxTm->tm_hour);
TRACE(" tm_min: %d\n", pxTm->tm_min);
TRACE(" tm_sec: %d\n", pxTm->tm_sec);
TRACE(" tm_isdst: %d\n", pxTm->tm_isdst);
return STATUS_OK;
}
#endif /* RTC_ENABLE && RTC_DS1338_ENABLE */
RtcDs1338.h
/*
RtcDs1338.h
Implementation File for Ds1338 Module
*/
/*
modification history
--------------------
01a, 20Mar24, Jasper Created
*/
#ifndef __RTC_DS1338_H__
#define __RTC_DS1338_H__
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus */
/* Includes */
#include <stdint.h>
#include <stm32f1xx_hal.h>
#include "Include/Include.h"
#include "Rtc/RtcConfig.h"
// Device address
#define DS1338_ADDR 0x68
/**
If set, in an hour register (DS1338_REG_HOURS, DS1338_REG_A1_HOUR,
DS1338_REG_A2_HOUR, the hour is between 0 and 12, and the
(!AM)/PM bit indicates AM or PM.
If not set, the hour is between 0 and 23.
*/
#define DS1338_HOUR_12 (0x01 << 6)
/**
If DS1338_HOUR_12 is set:
- If set, indicates PM
- If not set, indicates AM
*/
#define DS1338_PM_MASK (0x01 << 5)
// If set, the oscillator has stopped since the last time
// this bit was cleared.
#define DS1338_OSC_STOP_FLAG (0x01 << 5)
// Set to disable the oscillator
#define DS1338_OSC_DISABLE (0x01 << 7)
/**
These options control the behavior of the SQW/(!INTB) pin.
*/
#define DS1338_SQWE_FLAG (0x01 << 4)
#define DS1338_SQW_MASK (0x03)
#define DS1338_SQW_32768HZ (0x03)
#define DS1338_SQW_8192HZ (0x02)
#define DS1338_SQW_4096HZ (0x01)
#define DS1338_SQW_1HZ (0x00)
// Occurs when the number of I2C bytes available is less than the number requested.
#define READ_ERROR 5
#define decode_bcd(x) ((x >> 4) * 10 + (x & 0x0F))
#define encode_bcd(x) ((((x / 10) & 0x0F) << 4) + (x % 10))
/* Functions */
Time_t RtcDs1338ReadTime(void);
Status_t RtcDs1338WriteTime(Time_t xTm);
Status_t RtcDs1338Init(void);
#if (RTC_STDC_TIME == 2)
time_t time(time_t* timer);
#endif /* (RTC_STDC_TIME == 2) */
#ifdef __cplusplus
}
#endif /*__cplusplus */
#endif /* __RTC_DS1302_H__ */