新手入门
- 积分
- 17
- 金钱
- 17
- 注册时间
- 2019-10-22
- 在线时间
- 5 小时
|
本帖最后由 qianxilin 于 2021-7-8 09:36 编辑
STM32F103 RTC简单日历功能,这个只是日历功能,没有闹钟的功能。
STM32F103的RTC只有计数功能,虽然使用STM32CUBE可以配置日历功能,但是年月日,断电后就不能保存了。
大多折中的方法是把年月日保存到BKUP寄存器中。RTC开启秒中断,读取date然后保存年月日。
这种方法,如果断电太久,日期就会对比上。原子大哥的例程有实现日历的功能,并且带了闹钟。
实现原理都一样。
借用了<time.h>中的函数,保存到RTC计数器里面的值是时间戳。因此使用localtime()和mktime()函数来相互转换。
就不需要自己写代码去做年月日时分秒的计算了,如果要保存日期的话,直接用一个U32保存时间戳就行,用的时候用localtime()来转换就可以了。
操作RTC的一些函数在库里面是静态的,不能直接调用,我把代码考出来用。
主要代码:
- static void MX_RTC_Init(void)
- {
- /* USER CODE BEGIN RTC_Init 0 */
- /* USER CODE END RTC_Init 0 */
- RTC_TimeTypeDef sTime = {0};
- RTC_DateTypeDef DateToUpdate = {0};
- /* USER CODE BEGIN RTC_Init 1 */
- /* USER CODE END RTC_Init 1 */
- /** Initialize RTC Only
- */
- hrtc.Instance = RTC;
- hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
- hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
- if (HAL_RTC_Init(&hrtc) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN Check_RTC_BKUP */
- if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!= 0x5051)
- {
- #if 0
- /* USER CODE END Check_RTC_BKUP */
- /** Initialize RTC and set the Time and Date
- */
- sTime.Hours = 0;
- sTime.Minutes = 0;
- sTime.Seconds = 0;
- if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
- {
- Error_Handler();
- }
- DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
- DateToUpdate.Month = RTC_MONTH_JANUARY;
- DateToUpdate.Date = 1;
- DateToUpdate.Year = 21;
- if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN RTC_Init 2 */
- #endif
- DateTimeSet(2021,7,7,18,55,40);
- HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x5051);//向指定的后备区域寄存器写入数据
- }
复制代码
#include "MyRtc.h"
#define TIME_UTC_DF (8*60*60) //和格林威治时间相差8小时-北京时间要减去8小时
extern RTC_HandleTypeDef hrtc;
static HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef *hrtc)
{
uint32_t tickstart = 0U;
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
return HAL_OK;
}
static HAL_StatusTypeDef RTC_ExitInitMode(RTC_HandleTypeDef *hrtc)
{
uint32_t tickstart = 0U;
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
return HAL_OK;
}
static HAL_StatusTypeDef My_RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter)
{
HAL_StatusTypeDef status = HAL_OK;
__HAL_LOCK(hrtc);
/* Set Initialization mode */
if (RTC_EnterInitMode(hrtc) != HAL_OK)
{
status = HAL_ERROR;
}
else
{
/* Set RTC COUNTER MSB word */
WRITE_REG(hrtc->Instance->CNTH, (TimeCounter >> 16U));
/* Set RTC COUNTER LSB word */
WRITE_REG(hrtc->Instance->CNTL, (TimeCounter & RTC_CNTL_RTC_CNT));
/* Wait for synchro */
if (RTC_ExitInitMode(hrtc) != HAL_OK)
{
status = HAL_ERROR;
}
}
__HAL_UNLOCK(hrtc);
return status;
}
uint32_t My_RTC_ReadTimeCounter(RTC_HandleTypeDef *hrtc)
{
uint16_t high1 = 0U, high2 = 0U, low = 0U;
uint32_t timecounter = 0U;
high1 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
low = READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT);
high2 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
if (high1 != high2)
{
/* In this case the counter roll over during reading of CNTL and CNTH registers,
read again CNTL register then return the counter value */
timecounter = (((uint32_t) high2 << 16U) | READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT));
}
else
{
/* No counter roll over during reading of CNTL and CNTH registers, counter
value is equal to first value of CNTL and CNTH */
timecounter = (((uint32_t) high1 << 16U) | low);
}
return timecounter;
}
//初始化系统时间 也就是把时间转换为时间戳
void DateTimeSet(int year, int month, int day, int hour, int min, int sec)
{
time_t rawtime;
struct tm * timeinfo;
rawtime = 1577808000; //2020-1-1 00:00:00
timeinfo = localtime ( &rawtime );
timeinfo->tm_year = year - 1900;
timeinfo->tm_mon = month - 1;
timeinfo->tm_mday = day;
timeinfo->tm_hour = hour;
timeinfo->tm_min = min;
timeinfo->tm_sec = sec;
rawtime=mktime(timeinfo);
rawtime-=TIME_UTC_DF;
//LL_RTC_TIME_SetCounter(RTC,rawtime);
My_RTC_WriteTimeCounter(&hrtc,rawtime);
}
struct tm * GetDateTime(void)
{
time_t rawtime;
rawtime=My_RTC_ReadTimeCounter(&hrtc)+TIME_UTC_DF;//LL_RTC_TIME_Get(RTC)+TIME_UTC_DF;
return localtime(&rawtime);
}
调用方法:
struct tm * timeinfo;
for(;;)
{
timeinfo = GetDateTime();
timeinfo->tm_year+=1900;
timeinfo->tm_mon+=1;
osDelay(1000);
}
|
|