在 STM32F103 单片机上基于 RT-Thread 使用 RTC(实时时钟)的配置介绍。
1. 配置 RTC 驱动
在 RT-Thread 中启用 RTC 主要分两步:打开驱动框架 和在板级支持包中使能。
- 第一步:通过 menuconfig 开启驱动
- 进入图形化配置界面,配置开启RTC
- 第二步:确保 STM32 的 HAL 库配置正确
- 打开
stm32f1xx_hal_conf.h文件,确保HAL_RTC_MODULE_ENABLED已经被定义,以启用 RTC 的 HAL 驱动。
- 打开


2. 检查硬件初始化
RTC 属于 STM32 的备份域,需要特殊的电源管理和时钟配置。如果这部分没配好,RTC 会无法正常工作。
- 备份域访问权限:在写入 RTC 寄存器前,必须使能电源时钟和备份时钟,并取消备份域写保护。
- 时钟源选择 :F103 的 RTC 通常使用**外部低速晶振(LSE,32.768kHz)**来保证走时精度和低功耗。确保
stm32f1xx_hal_msp.c中的HAL_RTC_MspInit()函数已经正确配置了 LSE 时钟。 - 备用寄存器标志 :为了避免每次复位都重新初始化 RTC,驱动通常会使用备份寄存器(如
BKP_DR1)来存储初始化标志。检查drv_rtc.c中是否有类似读写备份寄存器的代码。
c
//系统时钟配置
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE
|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_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 busses 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();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_ADC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
stm32f1xx_hal_msp.c 中的 HAL_RTC_MspInit() 函数如下,此函数可以屏蔽掉,不配置,在rt-thread 的 drv_rtc.c 驱动文件中,会有相关的配置,具体可查看rt_rtc_config 函数。函数如下:
c
/**
* @brief RTC MSP Initialization
* This function configures the hardware resources used in this example
* @param hrtc: RTC handle pointer
* @retval None
*/
void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
if(hrtc->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
/* USER CODE END RTC_MspInit 0 */
HAL_PWR_EnableBkUpAccess();
/* Enable BKP CLK enable for backup registers */
__HAL_RCC_BKP_CLK_ENABLE();
/* Peripheral clock enable */
__HAL_RCC_RTC_ENABLE();
/* USER CODE BEGIN RTC_MspInit 1 */
/* USER CODE END RTC_MspInit 1 */
}
}
/**
* @brief RTC MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hrtc: RTC handle pointer
* @retval None
*/
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* hrtc)
{
if(hrtc->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspDeInit 0 */
/* USER CODE END RTC_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_RTC_DISABLE();
/* USER CODE BEGIN RTC_MspDeInit 1 */
/* USER CODE END RTC_MspDeInit 1 */
}
}
3. 应用层使用 RTC
一旦驱动注册成功,RTC 设备(设备名为 "rtc")就会被系统找到。RT-Thread 提供了非常方便的调用方式。
3.1 通过 FinSH/MSH 命令调试
这是最直接的验证方法。连接上串口终端后:
- 查看时间 :输入
date,系统会打印当前时间和日期。 - 设置时间 :输入
date 2026 02 24 18 30 00(年 月 日 时 分 秒),即可设置系统时间。
3.2 参考代码
RT-Thread 提供的参考代码:
c
/*
* 程序清单:这是一个 RTC 设备使用例程
* 例程导出了 rtc_sample 命令到控制终端
* 命令调用格式:rtc_sample
* 程序功能:设置RTC设备的日期和时间,延时一段时间后获取当前时间并打印显示。
*/
#include <rtthread.h>
#include <rtdevice.h>
#define RTC_NAME "rtc"
static int rtc_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
time_t now;
rt_device_t device = RT_NULL;
/*寻找设备*/
device = rt_device_find(RTC_NAME);
if (!device)
{
LOG_E("find %s failed!", RTC_NAME);
return RT_ERROR;
}
/*初始化RTC设备*/
if(rt_device_open(device, 0) != RT_EOK)
{
LOG_E("open %s failed!", RTC_NAME);
return RT_ERROR;
}
/* 设置日期 */
ret = set_date(2018, 12, 3);
if (ret != RT_EOK)
{
rt_kprintf("set RTC date failed\n");
return ret;
}
/* 设置时间 */
ret = set_time(11, 15, 50);
if (ret != RT_EOK)
{
rt_kprintf("set RTC time failed\n");
return ret;
}
/* 延时3秒 */
rt_thread_mdelay(3000);
/* 获取时间 */
now = time(RT_NULL);
rt_kprintf("%s\n", ctime(&now));
return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(rtc_sample, rtc sample);
4. 硬件掉电保存问题
- VBAT 供电 :如果希望主电源断电后 RTC 依然运行,必须给
VBAT引脚接上电池(如 CR2032)或大电容。否则,每次断电时间都会复位。 - 备份寄存器 :如前所述,检查备份寄存器(如
BKP_DR1)的值是判断是否是首次上电 的通用方法。如果该值不是预设的魔术数(如0xA5A5),说明是冷启动,需要重新配置分频器;否则直接读取计数器即可。
注意
使用rtc设备,需要先进行 rtc的初始化配置 - rt_rtc_config,系统自动注册设备时不会进行初始化配置,需要手动调用初始化配置函数。