RT-Thread 的 RTC設備為作業系統的時間系統提供了基礎服務。面對越來越多的 IoT 場景,RTC 已經成為產品的標配,甚至在諸如 SSL 的安全傳輸過程中,RTC 已經成為不可或缺的部分。
2、RTC設備操作接口RT-Thread為RTC設備提供了三個用戶層次的應用操作接口,分別是設置日期、設置時間和獲取當前時間。在RT-Thread的設備中,有且僅有一個RTC設備,設備名稱為"rtc"。
2.1 設置日期(set_date)rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
如何使用呢?
/* 設置日期為2020年5月1號 */
set_date(2020,5,1);
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
如何使用呢?
/* 設置時間為21點48分15秒 */
set_time(21, 48, 15);
time_t time(time_t *t)
如何使用呢?
/* 保存獲取的當前時間值 */
time_t now;
/* 獲取時間 */
now = time(RT_NULL);
/* 列印輸出時間信息 */
rt_kprintf("%s\n", ctime(&now));
本次實驗基於小熊派開發板:
配置finsh命令、libc以及軟體模擬rtc選項。
打開RTC模塊使能
在終端處輸入date相關的命令,可讀取和設置RTC。
溫馨提示: 由於我們沒設置RTC硬體備份,所以這個時間設置僅僅是當前有效,當重新斷電重啟的時候,又會恢復為原來最開始的時間(如下圖所示)。
以下是date命令在RT-Thread中的實現,源碼位於rtc.c
#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
static void date(uint8_t argc, char **argv)
{
if (argc == 1)
{
time_t now;
/* output current time */
now = time(RT_NULL);
rt_kprintf("%s", ctime(&now));
}
else if (argc >= 7)
{
/* set time and date */
uint16_t year;
uint8_t month, day, hour, min, sec;
year = atoi(argv[1]);
month = atoi(argv[2]);
day = atoi(argv[3]);
hour = atoi(argv[4]);
min = atoi(argv[5]);
sec = atoi(argv[6]);
if (year > 2099 || year < 2000)
{
rt_kprintf("year is out of range [2000-2099]\n");
return;
}
if (month == 0 || month > 12)
{
rt_kprintf("month is out of range [1-12]\n");
return;
}
if (day == 0 || day > 31)
{
rt_kprintf("day is out of range [1-31]\n");
return;
}
if (hour > 23)
{
rt_kprintf("hour is out of range [0-23]\n");
return;
}
if (min > 59)
{
rt_kprintf("minute is out of range [0-59]\n");
return;
}
if (sec > 59)
{
rt_kprintf("second is out of range [0-59]\n");
return;
}
set_time(hour, min, sec);
set_date(year, month, day);
}
else
{
rt_kprintf("please input: date [year month day hour min sec] or date\n");
rt_kprintf("e.g: date 2018 01 01 23 59 59 or date\n");
}
}
MSH_CMD_EXPORT(date, get date and time or set [year month day hour min sec]);
#endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
根據RTC設備API說明文檔,以及結合官方例程很容易可以實現以下demo:
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-09-09 RT-Thread first version
*/
#include <rtthread.h>
#include <board.h>
#include <rtdevice.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* PLEASE DEFINE the LED0 pin for your board, such as: PA5 */
#define LED0_PIN GET_PIN(C, 13)
/*
* 程序清單:這是一個 RTC 設備使用例程
* 例程導出了 rtc_sample 命令到控制終端
* 命令調用格式:rtc_sample
* 程序功能:設置RTC設備的日期和時間,延時一段時間後獲取當前時間並列印顯示。
*/
#include <rtthread.h>
#include <rtdevice.h>
static int rtc_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
time_t now;
/* 設置日期 */
ret = set_date(2020, 5, 2);
if (ret != RT_EOK)
{
rt_kprintf("set RTC date failed\n");
return ret;
}
/* 設置時間 */
ret = set_time(0, 21, 14);
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);
int main(void)
{
int count = 1;
/* set LED0 pin mode to output */
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
time_t now;
/* 獲取時間 */
now = time(RT_NULL);
rt_kprintf("%s\n", ctime(&now));
while (count++)
{
/* set LED0 pin level to high or low */
rt_pin_write(LED0_PIN, count % 2);
//LOG_D("Hello RT-Thread!");
rt_thread_mdelay(1000);
}
return RT_EOK;
}
導出rtc_sample命令後,就可以在終端上使用了。
如果我們要使用硬體RTC,那怎麼辦呢?看board.h的RTC配置項相關說明:
/** if you want to use rtc(hardware) you can use the following instructions.
*
* STEP 1, open rtc driver framework(hardware) support in the RT-Thread Settings file
*
* STEP 2, define macro related to the rtc
* such as BSP_USING_ONCHIP_RTC
*
* STEP 3, modify your stm32xxxx_hal_config.h file to support rtc peripherals. define macro related to the peripherals
* such as #define HAL_RTC_MODULE_ENABLED
*
*/
根據說明提示:
2 #define BSP_USING_ONCHIP_RTC
3 #define HAL_RTC_MODULE_ENABLED
配置完編譯工程下載後,看到串口的錯誤提示:
我一直以為是我哪裡寫錯了還是哪裡配置錯了,不知道問題出在哪裡,最後跟蹤調試了下代碼以及查看以前的調試筆記終於找到了問題點:
調試筆記:
STM32 使用HAL庫調試內部RTC經驗總結
跳轉到定義,最後發現它是跳轉到這裡了:
很明顯,這個地方有BUG,不應該是一個值,果斷將這個部分注釋掉!(drv_rtc.c)
這樣的話跳轉過去的就是HAL庫的函數了嘛,這不就對了嘛:
發現論壇上也有大佬討論這個問題: https://www.rt-thread.org/qa/search.php?mod=forum&searchid=191&orderby=lastpost&ascdesc=desc&searchsubmit=yes&kw=RTC
將代碼下載到板子以後,這次終於正常了:
溫馨提示:由於小熊派上沒有帶RTC備用電池,所以軟體復位後時間是可以正常跑的,但是斷電還是會恢復到原來的初始值噢!後來我拿了野火的STM32F103ZET6(帶RTC備用電池)驗證了一下是沒問題的,可以拿帶RTC備用電池的開發板嘗試一下!
大功告成!解決了問題,安心睡覺!祝各位朋友五一快樂!