当前位置: 首页 > news >正文

32HAL——RTC时钟

一、RTC简介

RTC(Real Time Clock),即实时时钟,类似于钟表一般,能够持续记录时间,为程序提供精确的日期和时间信息,即使在断电期间也能确保准确运行。

二、 原理和特点

  • 在STM32中,存在两个时钟源:高速时钟(8 MHz)和低速时钟(32.768 kHz)。高速时钟用于驱动CPU、外设和定时器等核心组件,而低速时钟则负责管理看门狗和RTC等功能。
  • RTC依赖低速时钟运行。
  • RTC模块内部包含了一个独立的32位寄存器来保存当前的时间戳信息。
  • 低速时钟以极低的功耗运行,即使在断电情况下,通过备用电源(如纽扣电池),RTC也能持续运行以确保时间准确性。

三、cubeMx相关配置

1. 开启外部晶振

低速时钟选用外部晶振

2. 配置RTC时钟频率

选用外部低速晶振(LSE)

3. 激活RTC

四、重写RTC库

myRTC.c

#include "myRTC.h"/*** @brief  Enters the RTC Initialization mode.* @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains*                the configuration information for RTC.* @retval HAL status*/
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;
}/*** @brief  Exit the RTC Initialization mode.* @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains*                the configuration information for RTC.* @retval HAL status*/
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;
}/*** @brief  Read the time counter available in RTC_CNT registers.* @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains*                the configuration information for RTC.* @retval Time counter*/
static uint32_t 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, countervalue is equal to first value of CNTL and CNTH */timecounter = (((uint32_t) high1 << 16U) | low);}return timecounter;
}/*** @brief  Write the time counter in RTC_CNT registers.* @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains*                the configuration information for RTC.* @param  TimeCounter: Counter to write in RTC_CNT registers* @retval HAL status*/
static HAL_StatusTypeDef RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter)
{HAL_StatusTypeDef status = HAL_OK;/* 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;}}return status;
}//设置RTC时间
HAL_StatusTypeDef myRTC_SetTime(struct tm *time) {uint32_t unixTime = mktime(time);   // 将实际时间转换为时间戳return RTC_WriteTimeCounter(&hrtc, unixTime);
}//获取RTC时间
struct tm *myRTC_GetTime(void) {time_t unixTime = RTC_ReadTimeCounter(&hrtc);   //将时间戳转换为实际时间return gmtime(&unixTime);
}void myRTC_Init(void) {// 先获取初始化标志位uint32_t initFlag = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);// 如果初始化标志位是我们设定的值,说明已经初始化过一次了,则直接跳出初始化if (initFlag == RTC_INIT_FLAG)  return;// cubeMx生成的RTC初始化代码if (HAL_RTC_Init(&hrtc) != HAL_OK){Error_Handler();}// 如果第一次初始化则给时间赋初始值, 这里使用结构体, 跟time.h一样struct tm time = {.tm_year = 2025 - 1900,     // 注意这里的年是当前年与1900的差值.tm_mon = 11 - 1,            // 这里的月是0-11,所以实际月份要减1.tm_mday = 7,.tm_hour = 16,.tm_min = 53,.tm_sec = 55,};//将时间存入RTCmyRTC_SetTime(&time);//运行到这里说明是第一次初始化,所以要把设定好的初始化标志位存进BKP, 防止下次时间被重新赋值HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, RTC_INIT_FLAG);
}

myRTC.h

//
// Created by Mood on 2025/11/7.
//#ifndef RTC_DEMO_MYRTC_H
#define RTC_DEMO_MYRTC_H#include "stm32f1xx_hal.h"
#include "rtc.h"
#include <time.h>#define RTC_INIT_FLAG 0x2333HAL_StatusTypeDef myRTC_SetTime(struct tm *time);
struct tm *myRTC_GetTime(void);
void myRTC_Init(void);#endif //RTC_DEMO_MYRTC_H

注:每次复位时代码均要进行一次初始化,cubeMx生成的RTC初始化代码中有一部分每次都会消耗一定时间,导致实时时间会偏慢,所以我们只在第一次初始化,后面复位均跳过此初始化。

void MX_RTC_Init(void)
{/* USER CODE BEGIN RTC_Init 0 */hrtc.Instance = RTC;hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;myRTC_Init();return;/* USER CODE END RTC_Init 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_ALARM;// 该初始化代码,每次复位时均会消耗一段时间,导致时间偏慢,所以我们在自己的初始化函数中,将其设置为只有第一次初始化才会调用此函数,后面每次复位// 均会跳过if (HAL_RTC_Init(&hrtc) != HAL_OK){Error_Handler();}/* USER CODE BEGIN RTC_Init 2 *//* USER CODE END RTC_Init 2 */}

五、示例程序

该代码实现了实时时钟,并且具有掉电不丢失功能,当然初始时间需自己在myRTC_Init()函数中设置。

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2025 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 "i2c.h"
#include "rtc.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "oled.h"
#include <stdio.h>
#include "myRTC.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* 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_I2C2_Init();MX_RTC_Init();/* USER CODE BEGIN 2 */HAL_Delay(20);OLED_Init();char message[50];struct tm *now;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){OLED_NewFrame();now = myRTC_GetTime();sprintf(message, "%d-%d-%d %d:%d:%d", now->tm_year, now->tm_mon, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);OLED_PrintASCIIString(0, 0, message, &afont12x6, OLED_COLOR_NORMAL);OLED_ShowFrame();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

注:上述相关资料均来自ksysking

http://www.dtcms.com/a/585863.html

相关文章:

  • C#知识补充(一)——ref和out、成员属性、万物之父和装箱拆箱、抽象类和抽象方法、接口
  • 专业的设计网站建设网站做地区定位跳转
  • 网站做三层结构南京建设网站哪家好
  • pyautocad 获取选择线段的近似最小包围盒 (OBB) 三分搜索
  • Git Commit 高频提示详解:用户名邮箱配置及其他常见提示解决方案
  • 打开网站图片弹入指定位置代码网络域名备案查询
  • 豆包 Spring 常用注解详解及分类
  • 企业网站建设收费最大的网站开发公司
  • 服务器运维(六)跨域配置 Preflight 问题——东方仙化神期
  • 第三次作业-第四章网站搭建
  • React 17
  • Linux:多路转接
  • 为什么国内禁用docker呢?
  • 石家庄行业网站深圳建筑工地招工招聘信息
  • 云溪网络建站宝盒wordpress发文章套模版
  • 人在虚弱的时候真的能看到鬼
  • zabbix原生高可用集群应用实战
  • flink1.20.2环境部署和实验-1
  • 网站主目录程序开发步骤不包括
  • 云手机技术是如何实现的?
  • 现有rest api转换为MCP工具 存量api改造为MCP Server
  • MyBatis:性能优化实战 - 从 SQL 优化到索引设计
  • 【Golang】常见数据结构原理剖析
  • 做百度推广得用网站是吗做小说网站做国外域名还是国内的好处
  • Ubuntu 复制王者:rsync -av 终极指南 —— 进度可视化 + 无损同步,效率甩 cp 几条街!
  • ubuntu磁盘管理、磁盘扩容
  • 专业设计网站排名百达翡丽手表网站
  • 广度优先搜索
  • 高端网站建设公司名称动物自己做的网站
  • 编译OpenCV