【物联网学习笔记】RTC

前言

本文是本人备赛物联网赛项的学习笔记,主要供本人学习、复习,不是经验分享或教学,若有错误,大佬轻喷。

一、RTC 基础概念扫盲

1.1 什么是 RTC?

RTC(Real-Time Clock,实时时钟)是 STM32 芯片内置的独立外设,核心作用是:

  • 精准记录年、月、日、星期、时、分、秒
  • 系统掉电后,可通过备用电池(如 CR2032 纽扣电池)持续走时,重新上电无需重新设置时间。

注意 :RTC 是芯片内部功能,没有和任何 GPIO 引脚相连,无需配置 GPIO 即可使用!


二、CubeMX 全流程配置(保姆级步骤)

2.1 新建基础工程

  1. 打开 STM32CubeMX,点击ACCESS TO MCU SELECTOR
  2. 搜索框输入STM32WLE5CCU6,选中芯片后点击Start Project

2.2 配置 RCC(外部晶振,RTC 精准走时的关键)

RTC 的精准走时依赖外部低速晶振(LSE),必须配置:

  1. 左侧Pinout & Configuration → System Core → RCC
  2. Low Speed Clock (LSE) 选择Crystal/Ceramic Resonator(外部晶振模式);
  3. High Speed Clock (HSE) 根据开发板硬件选择对应模式即可

2.3 配置 USART2(用于串口打印验证)

为了后续能通过串口查看 RTC 时间,先配置基础串口:

  1. Connectivity → USART2
  2. Mode 选择Asynchronous(异步通信);
  3. Parameter Settings 保持默认:波特率 115200 Bits/s,数据位 8,停止位 1,无校验。

2.4 RTC 核心功能配置(重点!)

这是 RTC 正常工作的核心步骤,一步都不能错:

  1. Timers → RTC
  2. Mode 模式配置
    • 勾选Activate Clock Source(激活 RTC 时钟源);
    • 勾选Activate Calendar(激活日历功能);
  3. Parameter Settings 参数配置
    • Hour Format :选择Hour Format 24(24 小时制,新手友好);
    • Asynchronous/Synchronous Predivider:保持默认值(异步 127、同步 255,32768kHz 晶振分频后刚好 1Hz 秒计数);
    • Data Format :选择BIN(二进制格式,方便代码读取);
    • Calendar Time :Hours/Minutes/Seconds 为上电默认时间,直接修改这里的数值即可设置初始时间;
    • Calendar Date :Year/Month/Date/WeekDay 为默认日期,新手先保持默认,实际项目按需修改。

2.5 时钟树配置

  1. 顶部Clock Configuration
  2. 确认 RTC 时钟源选择为LSE(外部低速晶振,确保走时精准);
  3. 其他参数保持默认,点击空白处自动完成时钟树计算。

2.6 工程生成配置

  1. 顶部Project Manager
    • Project 选项卡 :设置工程名称、存放路径(重点:路径绝对不能有中文、空格、特殊字符! ),Toolchain/IDE 选择MDK-ARM V5
    • Code Generator 选项卡 :勾选Generate peripheral initialization as a pair of '.c/.h' files per peripheral(每个外设生成独立文件,代码更清晰)。
  2. 点击右上角GENERATE CODE 生成代码,弹出提示后点击Open Project打开 Keil 工程。

三、逐行注释代码实现(仅聚焦 RTC)

我们创建两个独立文件app.happ.c(将原讲义的zsdz统一替换为通用的app),完全解耦 CubeMX 生成的代码,重新生成 CubeMX 代码不会被覆盖。

3.1 编写 app.h 头文件

头文件核心作用是定义 RTC 时间结构体声明全局变量与函数,防止头文件重复包含。

cpp 复制代码
#ifndef __APP_H  // 防止头文件被重复包含的宏定义
#define __APP_H  

#include "string.h"  // 引入字符串操作头文件(基础依赖)
#include "stdio.h"   // 引入标准输入输出头文件(printf串口打印依赖)
#include "gpio.h"    // 引入GPIO驱动头文件(基础依赖)

// 定义RTC时间存储结构体:统一封装年月日周、时分秒
typedef struct
{
    unsigned char Year;     // 存储RTC读取的年份值
    unsigned char Month;    // 存储RTC读取的月份值(范围1-12)
    unsigned char WeekDay;  // 存储RTC读取的星期值(范围1-7)
    unsigned char Date;     // 存储RTC读取的日期值(范围1-31)
    unsigned char Hours;    // 存储RTC读取的小时值(范围0-23)
    unsigned char Minutes;  // 存储RTC读取的分钟值(范围0-59)
    unsigned char Seconds;  // 存储RTC读取的秒数值(范围0-59)
}RTC_APP;

extern RTC_APP rtc_value;  // 声明全局RTC结构体变量,供其他文件(如main.c)直接调用

void app_read_RTC(void);   // 声明RTC时间读取核心函数

#endif  // 头文件结束标记

3.2 编写 app.c 源文件

源文件实现头文件中声明的函数,核心是RTC 时间的读取逻辑

cpp 复制代码
#include "app.h"  // 包含自定义头文件,获取RTC结构体和函数声明

RTC_APP rtc_value;  // 定义全局RTC结构体变量,实际存储读取到的RTC时间

// 函数功能:从RTC外设读取当前时间日期,存入全局结构体rtc_value中
// 入口参数:无
// 返回值:无
// 备注:必须先读时间,再读日期,顺序不能反!
void app_read_RTC(void)
{
    extern RTC_HandleTypeDef hrtc;  // 声明外部RTC句柄(由CubeMX生成,定义在rtc.c中)
	
    RTC_DateTypeDef data_value;  // 定义HAL库标准日期结构体,临时存储日期数据
    RTC_TimeTypeDef time_value;  // 定义HAL库标准时间结构体,临时存储时间数据
	
    // 【新手必记坑点】必须先调用HAL_RTC_GetTime读取时间
    // 参数1:RTC句柄;参数2:时间存储结构体;参数3:数据格式(RTC_FORMAT_BIN=二进制)
    HAL_RTC_GetTime(&hrtc, &time_value, RTC_FORMAT_BIN);
    // 【新手必记坑点】必须再调用HAL_RTC_GetDate读取日期,两个函数必须成对调用
    HAL_RTC_GetDate(&hrtc, &data_value, RTC_FORMAT_BIN);
	
    // 将读取到的日期数据赋值给全局RTC结构体
    rtc_value.Year    = data_value.Year;     // 年份赋值
    rtc_value.Month   = data_value.Month;    // 月份赋值
    rtc_value.WeekDay = data_value.WeekDay;  // 星期赋值
    rtc_value.Date    = data_value.Date;      // 日期赋值
	
    // 将读取到的时间数据赋值给全局RTC结构体
    rtc_value.Hours   = time_value.Hours;     // 小时赋值
    rtc_value.Minutes = time_value.Minutes;   // 分钟赋值
    rtc_value.Seconds = time_value.Seconds;   // 秒数赋值
}

3.3 修改 main.c 主函数

重点提醒 :所有用户代码必须写在USER CODE BEGIN XUSER CODE END X之间,否则重新生成 CubeMX 代码时会被覆盖!

步骤 1:引入头文件

找到USER CODE BEGIN Includes代码段,添加如下代码:

cpp 复制代码
/* USER CODE BEGIN Includes */
#include "app.h"   // 引入我们自定义的RTC头文件
#include "stdio.h" // 引入标准输入输出头文件(printf依赖)
/* USER CODE END Includes */
步骤 2:添加 printf 重定向代码

找到USER CODE BEGIN 0代码段,添加串口 printf 重定向代码,否则无法通过串口打印时间:

cpp 复制代码
/* USER CODE BEGIN 0 */
// printf串口重定向函数:将printf的输出重定向到USART2
int fputc(int ch, FILE *f)
{
    extern UART_HandleTypeDef huart2;  // 声明外部USART2句柄(由CubeMX生成)
    // 通过USART2发送一个字符,参数1:USART2句柄;参数2:字符指针;参数3:发送长度;参数4:超时时间
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;  // 返回发送的字符
}
/* USER CODE END 0 */
步骤 3:主循环添加 RTC 读取与打印

找到 while (1) 主循环中的USER CODE BEGIN WHILE代码段,添加核心逻辑:

cpp 复制代码
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    app_read_RTC();  // 调用自定义函数,读取RTC当前时间到全局rtc_value
	
    // 串口格式化打印RTC时间,%02d表示两位数显示,不足补0,格式更规范
    printf("RTC实时时间:%02d-%02d-%02d 星期%d %02d:%02d:%02d\r\n",
           rtc_value.Year,    // 打印年份
           rtc_value.Month,   // 打印月份
           rtc_value.Date,    // 打印日期
           rtc_value.WeekDay, // 打印星期
           rtc_value.Hours,   // 打印小时
           rtc_value.Minutes, // 打印分钟
           rtc_value.Seconds);// 打印秒数
	
    HAL_Delay(500);  // 延时500ms,控制打印频率,避免串口刷屏
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

四、编译下载与效果验证

  1. 编译工程 :点击 Keil 左侧Rebuild 按钮,全量编译,出现0 Error(s), 0 Warning(s)即为成功;
  2. 下载程序 :连接 ST-Link 仿真器,点击Load按钮下载程序,下载完成后按下开发板复位键;
  3. 串口验证:打开串口助手,选择对应串口号,配置波特率 115200、数据位 8、停止位 1、无校验,打开串口即可看到 RTC 实时时间每秒自动更新!
相关推荐
早起CaiCai2 小时前
【综述 + 2018】内重力波
笔记
菜鸡儿齐2 小时前
ConcurrentHashMap源码学习
学习·哈希算法·散列表
Amnesia0_02 小时前
C++的异常
开发语言·c++·学习
YY_Share2 小时前
Console 接口介绍及电路设计
嵌入式硬件·硬件工程
金山几座2 小时前
C#学习记录-泛型
开发语言·学习·c#
zzh0812 小时前
Nginx性能优化与监控笔记
笔记·nginx·性能优化
盐焗西兰花2 小时前
鸿蒙学习实战之路-Share Kit系列(13/17)-配置目标应用名单(企业应用)
学习·华为·harmonyos
是店小二呀2 小时前
工业物联网实时分析痛点与 DolphinDB 核心解决方案深度解析
物联网
2601_948606182 小时前
LaTeX学习笔记:开场白与索引
笔记·学习