RTC设备
RTC简介
RTC(Real-Time Clock)实时时钟可以提供精确的实时时间,它可以用于产生年、月、日、时、分、秒等信息。UC8288采用内部32.768KHz时钟作为RTC时钟源。并且添加RTC报警功能,设置RTC报警日期和时间后在RTC设备计时到达后会产生一个RTC报警中断。
驱动支持
访问RTC设备前,需要保证相关驱动配置已选中。
Windows环境:利用RT-Thread官方env工具直接在代码根目录下执行menuconfig进入配置。
Linux环境:在代码根目录下执行scons --menuconfig进入配置。
RTC驱动所在路径如下:
RT-Thread Components -> Device Drivers -> Using RTC device drivers
访问 RTC 设备
在开启 RTC 设备框架以及 RTC 驱动之后,用户可以 #include <sys/time.h>
用来引用标准的时间操作函数(例如 time、ctime、stime、mktime等,具体使用方法可以百度)。在Unix系统或者Windows系统下怎么使用 <time.h>
里边的函数,在RT-Thread下就怎么使用。建议用户采用标准库时间函数来操作 RTC。
此外,RTC 设备框架也提供了 set_date()
和 set_time()
函数,方便用户快速修改时间和日期,但是该函数在例如一些特殊时刻设置时间、日期(例如2023年12月31日23时59分59秒)时可能会导致错误,因此一般用于测试 RTC 硬件是否工作正常和一些简单的演示时使用,不建议在业务代码中使用。
函数 | 描述 |
---|---|
set_date() | 设置日期,年、月、日(当地时区) |
set_time() | 设置时间,时、分、秒(当地时区) |
设置日期
通过如下函数设置 RTC 设备当前当地时区日期值:
rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
参数 | 描述 |
---|---|
year | 待设置生效的年份 |
month | 待设置生效的月份 |
day | 待设置生效的日 |
返回 | —— |
RT_EOK | 设置成功 |
-RT_ERROR | 失败,没有找到 rtc 设备 |
其他错误码 | 失败 |
使用示例如下所示:
/* 设置日期为2018年12月3号 */
set_date(2018, 12, 3);
设置时间
通过如下函数设置 RTC 设备当前当地时区时间值:
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
参数 | 描述 |
---|---|
hour | 待设置生效的时 |
minute | 待设置生效的分 |
second | 待设置生效的秒 |
返回 | —— |
RT_EOK | 设置成功 |
-RT_ERROR | 失败,没有找到 rtc 设备 |
其他错误码 | 失败 |
使用示例如下所示:
/* 设置时间为11点15分50秒 */
set_time(11, 15, 50);
获取当前时间
使用到 C 标准库中的时间 API 获取时间戳(格林威治时间):
time_t time(time_t *t)
参数 | 描述 |
---|---|
t | 时间数据指针 |
返回 | —— |
当前时间值 |
使用示例如下所示:
time_t now; /* 保存获取的当前时间值 */
/* 获取时间 */
now = time(RT_NULL);
/* 打印输出时间信息 */
rt_kprintf("%s\n", ctime(&now));
Note
注:目前系统内只允许存在一个 RTC 设备,且名称为 "rtc"
。
RTC使用示例
使用示例需要配置menuconfig,使能例程与外设,步骤如下:
- 使能例程
Application Example Config -> Enable RTC Example
- 使能外设驱动
Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable RTC
以下提供RTC测试实例,测试步骤如下:
- 根据RTC设备名称,获取RTC设备句柄。
- 设置RTC输出。
#include <rtthread.h>
#ifdef APP_EXAMPLE_RTC
#ifndef RT_USING_RTC
#error "Please enable rt-thread rtc device driver"
#endif
#ifndef BSP_USING_RTC
#error "Please enable on-chip peripheral rtc config"
#endif
#include <rtdevice.h>
#include "uc_rtc_app.h"
#define THREAD_STACK_SIZE 512
#define THREAD_PRIORITY 5
#define THREAD_TIMESLICE 5
#define RTC_DEVICE_NAME "rtc"
static rt_device_t rtc_device = RT_NULL;
#ifdef RT_USING_ALARM
static void user_alarm_callback(rt_alarm_t alarm, time_t timestamp)
{
rt_kprintf("user alarm callback function. alarm flag: 0x%x, timestamp: %d\n", alarm->flag, timestamp);
}
static void rtc_alarm_app_sample(void)
{
struct rt_alarm_setup setup;
struct rt_alarm *alarm = RT_NULL;
static time_t now;
struct tm p_tm;
/* 获取当前时间戳,并把下5秒时间设置为闹钟时间 */
/* 闹钟第一次响起在当前时间的1分5秒后,之后每隔1分钟响起 */
now = time(NULL) + 5;
gmtime_r(&now, &p_tm);
setup.flag = RT_ALARM_MINUTE;
setup.wktime.tm_year = p_tm.tm_year;
setup.wktime.tm_mon = p_tm.tm_mon;
setup.wktime.tm_mday = p_tm.tm_mday;
setup.wktime.tm_wday = p_tm.tm_wday;
setup.wktime.tm_hour = p_tm.tm_hour;
setup.wktime.tm_min = p_tm.tm_min;
setup.wktime.tm_sec = p_tm.tm_sec;
alarm = rt_alarm_create(user_alarm_callback, &setup);
if (alarm == RT_NULL)
{
rt_kprintf("create alarm failed.\n");
}
else
{
rt_alarm_start(alarm);
}
}
#endif
static void rtc_thread_entry(void *parameter)
{
time_t now;
while (1)
{
/* 延时5秒 */
rt_thread_mdelay(5000);
/* 获取时间 */
now = time(RT_NULL);
rt_kprintf("%s", ctime(&now));
}
}
int rtc_app_sample(void)
{
rt_err_t ret = RT_EOK;
rt_thread_t thread = RT_NULL;
rt_kprintf("rtc_app_sample\n");
/*寻找设备*/
rtc_device = rt_device_find(RTC_DEVICE_NAME);
if (!rtc_device)
{
rt_kprintf("find %s failed!\n", RTC_DEVICE_NAME);
return -RT_ERROR;
}
/*初始化RTC设备*/
if (rt_device_open(rtc_device, 0) != RT_EOK)
{
rt_kprintf("open %s failed!\n", RTC_DEVICE_NAME);
return -RT_ERROR;
}
/* 设置日期 */
ret = set_date(2020, 1, 1);
if (ret != RT_EOK)
{
rt_kprintf("set RTC date failed\n");
return ret;
}
/* 设置时间 */
ret = set_time(0, 0, 0);
if (ret != RT_EOK)
{
rt_kprintf("set RTC time failed\n");
return ret;
}
#ifdef RT_USING_ALARM
rtc_alarm_app_sample();
#endif
/* 创建线程 */
thread = rt_thread_create("rtc_app",
rtc_thread_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
/* 创建成功则启动线程 */
if (RT_NULL == thread)
{
return -RT_ERROR;
}
else
{
rt_thread_startup(thread);
}
return RT_EOK;
}
#endif