当前位置:首页 > 技术 > 正文内容

RT-Thread 实时时钟 (RTC) 设备驱动开发指南

访客 技术 2026年7月17日 1

实时时钟 (RTC) 设备

RTC 概述

实时时钟(RTC)模块是嵌入式系统中用于维持精确时间的核心组件。它通常基于高精度晶体振荡器,能够提供年、月、日、时、分、秒等时间信息。许多 RTC 芯片还配备备用电池,以确保在主电源断电时仍能继续计时,从而保证时间信息的连续性。

在 RT-Thread 操作系统中,RTC 设备为整个系统的时间管理提供了基础服务。随着物联网(IoT)应用的普及,RTC 已成为许多产品的标准配置。在安全通信协议(如 SSL/TLS)中,精确的时间同步也是不可或缺的一环。

访问 RTC 设备

在启用 RTC 设备框架和相应驱动后,开发者可以通过包含标准头文件 <sys/time.h> 来使用 C 标准库提供的时间操作函数,例如 time()ctime()localtime() 等。这些函数的使用方式与在 Unix 或 Windows 系统中一致,是推荐的操作 RTC 的方式。

此外,RT-Thread 也提供了便捷的专用函数 rtc_set_date()rtc_set_time() 用于快速设置日期和时间。然而,这些函数在处理特殊时间点(如闰秒或年末时刻)时可能存在局限性,因此通常仅建议用于硬件测试或简单演示,不建议在核心业务逻辑中使用。

设置日期和时间

以下是用于设置 RTC 设备日期和时间的函数原型及其说明:

rt_err_t rtc_set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day);
rt_err_t rtc_set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second);
函数 描述
rtc_set_date() 设置当前时区的日期,包括年、月、日。
rtc_set_time() 设置当前时区的时间,包括时、分、秒。
参数 描述
year 目标年份
month 目标月份
day 目标日期
hour 目标小时
minute 目标分钟
second 目标秒数
返回值 描述
RT_EOK 操作成功
-RT_ERROR 失败,未找到 RTC 设备
其他错误码 操作失败

设置日期示例:

/* 将日期设置为2023年10月27日 */
rtc_set_date(2023, 10, 27);

设置时间示例:

/* 将时间设置为14点30分0秒 */
rtc_set_time(14, 30, 0);

获取当前时间

获取当前时间戳(通常为格林尼治标准时间)最常用的方法是调用 C 标准库函数 time()

time_t time(time_t *t);
参数 描述
t 指向 time_t 变量的指针,用于存储获取的时间。若为 NULL,则仅返回时间值。
返回值 描述
当前时间值 自 Epoch(通常为1970年1月1日)以来的秒数。

获取并打印时间示例:

time_t current_time; /* 用于存储获取的时间 */
/* 获取当前时间戳 */
current_time = time(RT_NULL);
/* 将时间戳转换为可读的字符串并打印 */
rt_kprintf("Current time: %s\n", ctime(&current_time));

注意: 在 RT-Thread 系统中,目前只支持一个名为 "rtc" 的 RTC 设备实例。

功能配置

启用软件模拟 RTC

对于没有硬件 RTC 或对时间精度要求不高的应用,可以在菜单配置中启用软件模拟 RTC 功能。配置路径如下:

RT-Thread Components →
    Device Drivers:
        [*] 使用 RTC 设备驱动
        [ ] 使用软件模拟 RTC 设备

启用 NTP 时间自动同步

如果 RT-Thread 系统已连接到网络,可以启用 NTP(网络时间协议)客户端来自动同步系统时间。

首先,在包管理器中开启 NTP 功能:

RT-Thread online packages →
    IoT - internet of things →
        netutils: Networking utilities for RT-Thread:
             [*] 启用 NTP(Network Time Protocol) 客户端

然后,在设备驱动配置中启用 NTP 自动同步:

RT-Thread Components →
    Device Drivers:
        [*] 使用 RTC 设备驱动
        [ ] 使用软件模拟 RTC 设备
        [*] 使用 NTP 自动同步 RTC 时间
       (30)    NTP 首次同步延时(秒)  /* 网络连接后,首次同步的等待时间 */
       (3600)  NTP 自动同步周期(秒)  /* 每隔多久同步一次时间 */

注意: 在 2021-05-09 版本之后的 RT-Thread 内核源码中,NTP 自动同步 RTC 时间的配置项已被移除。

FinSH 命令

可以通过 FinSH 命令行工具查看和设置系统时间。

查看当前时间:

msh />date
Fri Feb 16 01:11:56 2018
msh />

设置当前时间:

msh />date 2024 5 20 10 0 0
msh />

RTC 设备使用示例

以下示例代码演示了如何查找、初始化、设置 RTC 设备,并在延时后读取当前时间。

/*
 * 程序名称:RTC 设备操作示例
 * 功能:初始化 RTC 设备,设置日期和时间,然后读取并打印当前时间。
 * 命令:rtc_demo
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <time.h>

#define RTC_DEVICE_NAME "rtc"

static int rtc_demo(int argc, char *argv[])
{
    rt_err_t result;
    time_t timestamp;
    rt_device_t rtc_dev;

    /* 1. 查找并获取 RTC 设备句柄 */
    rtc_dev = rt_device_find(RTC_DEVICE_NAME);
    if (rtc_dev == RT_NULL) {
        rt_kprintf("错误:未找到 RTC 设备 '%s'\n", RTC_DEVICE_NAME);
        return -RT_ERROR;
    }

    /* 2. 以读写模式打开 RTC 设备 */
    result = rt_device_open(rtc_dev, RT_DEVICE_OFLAG_RDWR);
    if (result != RT_EOK) {
        rt_kprintf("错误:无法打开 RTC 设备\n");
        return result;
    }

    /* 3. 设置日期为 2024 年 5 月 20 日 */
    result = rtc_set_date(2024, 5, 20);
    if (result != RT_EOK) {
        rt_kprintf("设置日期失败\n");
        rt_device_close(rtc_dev);
        return result;
    }

    /* 4. 设置时间为 10 点 0 分 0 秒 */
    result = rtc_set_time(10, 0, 0);
    if (result != RT_EOK) {
        rt_kprintf("设置时间失败\n");
        rt_device_close(rtc_dev);
        return result;
    }

    /* 5. 延时 5 秒 */
    rt_thread_mdelay(5000);

    /* 6. 获取当前时间戳 */
    timestamp = time(RT_NULL);

    /* 7. 将时间戳转换为字符串并打印 */
    rt_kprintf("当前时间: %s\n", ctime(&timestamp));

    /* 8. 关闭设备 */
    rt_device_close(rtc_dev);

    return RT_EOK;
}
/* 注册为 msh 命令 */
MSH_CMD_EXPORT(rtc_demo, 演示 RTC 设备的基本操作);

Alarm (闹钟) 功能

Alarm 概述

Alarm 功能基于 RTC 设备实现,允许在特定时间点触发预定的事件。虽然硬件 RTC 本身可能只支持有限数量的硬件闹钟,但 RT-Thread 通过软件抽象层,理论上可以支持无限个闹钟。需要注意的是,每个闹钟实例最终只保留最后一次的设定有效。

要使用 Alarm 组件,必须在菜单配置中启用该功能,并且底层 RTC 驱动必须实现必要的接口(如 set_alarmget_alarm)。配置路径如下:

RT-Thread Components  --->
    Device Drivers  --->
        [*] 使用 RTC alarm

Alarm 设备操作

应用程序通过 Alarm 组件提供的 API 来创建和管理闹钟。主要接口函数如下:

  • rtc_alarm_create(): 创建一个闹钟实例
  • rtc_alarm_start(): 启动闹钟
  • rtc_alarm_stop(): 停止闹钟
  • rtc_alarm_delete(): 删除闹钟
  • rtc_alarm_control(): 控制闹钟(如修改设置)
  • rtc_alarm_dump(): 打印所有已创建的闹钟信息

创建闹钟

使用 rtc_alarm_create() 函数创建一个新的闹钟。

rt_alarm_t rtc_alarm_create(rt_alarm_callback_t callback, struct rt_alarm_setup *setup);
参数 描述
callback 闹钟触发时调用的回调函数指针。
setup 指向 struct rt_alarm_setup 的指针,用于配置闹钟的时间和模式。
返回值 描述
非 NULL 成功,返回闹钟句柄。
RT_NULL 失败。

struct rt_alarm_setup 结构体定义了闹钟的触发时间和模式:

struct rt_alarm_setup
{
    rt_uint32_t flag;                /* 闹钟模式标志 */
    struct tm wktime;                /* 闹钟触发的具体日期和时间 */
};

闹钟模式通过 flag 字段设置,可组合使用:

#define RTC_ALARM_ONESHOT       0x000  /* 单次闹钟 */
#define RTC_ALARM_DAILY         0x100  /* 每天重复 */
#define RTC_ALARM_WEEKLY        0x200  /* 每周重复 (指定星期) */
#define RTC_ALARM_MONTHLY       0x400  /* 每月重复 (指定日期) */
#define RTC_ALARM_YEARLY        0x800  /* 每年重复 (指定日期) */
#define RTC_ALARM_HOUR          0x1000 /* 每小时重复 (指定分钟:秒) */
#define RTC_ALARM_MINUTE       0x2000  /* 每分钟重复 (指定秒) */
#define RTC_ALARM_SECOND       0x4000  /* 每秒重复 */

注意: 闹钟创建后处于停止状态,需要显式启动。

启动、停止和删除闹钟

/* 启动闹钟 */
rt_err_t rtc_alarm_start(rt_alarm_t alarm);

/* 停止闹钟 */
rt_err_t rtc_alarm_stop(rt_alarm_t alarm);

/* 删除闹钟 */
rt_err_t rtc_alarm_delete(rt_alarm_t alarm);

控制闹钟

可以使用 rtc_alarm_control() 函数修改已创建闹钟的设置。

rt_err_t rtc_alarm_control(rt_alarm_t alarm, int cmd, void *arg);
参数 描述
alarm 要控制的闹钟句柄。
cmd 控制命令,目前支持 RTC_ALARM_CTRL_MODIFY(修改设置)。
arg 指向 struct rt_alarm_setup 的指针,包含新的设置。

注意: 修改设置后,闹钟不会自动重启,需要调用 rtc_alarm_start()

Alarm 使用示例

以下示例创建一个每秒触发一次的闹钟,并在回调函数中打印信息。

/*
 * 程序名称:Alarm 功能示例
 * 功能:创建一个每秒触发一次的闹钟,并打印触发信息。
 * 命令:alarm_demo
 */

#include <rtthread.h>
#include <rtdevice.h>

/* 闹钟回调函数 */
void alarm_callback(rt_alarm_t alarm, time_t timestamp)
{
    rt_kprintf("闹钟触发!当前时间: %s", ctime(&timestamp));
}

void alarm_demo(void)
{
    rt_device_t rtc_dev;
    struct rt_alarm_setup alarm_cfg;
    struct rt_alarm *my_alarm;
    time_t now;
    struct tm current_tm;

    /* 查找 RTC 设备 */
    rtc_dev = rt_device_find("rtc");
    if (rtc_dev == RT_NULL) {
        rt_kprintf("错误:未找到 RTC 设备\n");
        return;
    }

    /* 获取当前时间,并设置为下一秒 */
    now = time(RT_NULL) + 1;
    gmtime_r(&now, &current_tm);

    /* 配置闹钟:每秒触发 */
    alarm_cfg.flag = RTC_ALARM_SECOND;
    alarm_cfg.wktime = current_tm;

    /* 创建闹钟 */
    my_alarm = rtc_alarm_create(alarm_callback, &alarm_cfg);
    if (my_alarm != RT_NULL) {
        /* 启动闹钟 */
        rtc_alarm_start(my_alarm);
        rt_kprintf("闹钟已启动,将持续打印信息...\n");
    } else {
        rt_kprintf("创建闹钟失败\n");
    }
}
/* 注册为 msh 命令 */
MSH_CMD_EXPORT(alarm_demo, 演示 Alarm 功能的使用);

执行该命令后,控制台会每秒打印一次 "闹钟触发!" 的信息。

标签: RT-Thread

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。