開發環境:
RT-Thread Studio:v2.2.6
開發板:RA6M3 HMI Board開發板
MCU:R7FA6M3AH3CFB
1 RA6M3 RTC簡介
R7FA6M3 的RTC(Real Time Clock)外設,實質是一個掉電后還繼續運行的定時器。從定時器的角度來說,相對于GPT外設,要簡單很多 ,只有計時和觸發中斷以及輸入捕獲的功能。RTC外設的特別之處并不在于它的定時功能,而在于它掉電還繼續運行的特性。
2 RT-Thread 的RTC簡介
RTC (Real-Time Clock)實時時鐘可以提供精確的實時時間,它可以用于產生年、月、日、時、分、秒等信息。目前實時時鐘芯片大多采用精度較高的晶體振蕩器作為時鐘源。有些時鐘芯片為了在主電源掉電時還可以工作,會外加電池供電,使時間信息一直保持有效。
在開啟 RTC 設備框架以及 RTC 驅動之后,應用程序通過 RT-Thread 提供的 RTC設備管理接口來訪問 RTC 硬件,相關接口如下所示:
函數 | 描述 |
---|---|
rt_device_find() | 根據 RTC設備名稱查找設備獲取設備句柄 |
set_date() | 設置日期,年、月、日(當地時區) |
set_time() | 設置時間,時、分、秒(當地時區) |
另外,alarm 鬧鐘功能是基于 RTC 設備實現的,根據用戶設定的鬧鐘時間,當時間到時觸發 alarm 中斷,執行鬧鐘事件。
alarm 組件提供的接口如下所示:
函數 | 描述 |
---|---|
rt_alarm_create() | 創建鬧鐘 |
rt_alarm_start() | 啟動鬧鐘 |
rt_alarm_stop() | 停止鬧鐘 |
rt_alarm_delete() | 刪除鬧鐘 |
rt_alarm_control() | 控制alarm設備 |
rt_alarm_dump() | 打印顯示設置的鬧鐘信息 |
關于RTC的更多資料請參看RT-Thread官方手冊:
https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/rtc/rtc
3 RA6M3 RTC配置
接下來配置RTC,只需要簡單配置就可使用。雙擊工程中的 RA Smart Configurator 圖標,第一次打開需要配置正確的 FSP 安裝路徑。
- FSP配置RTC
1.添加 RTC 設備
2.配置 RTC
RT-Thread 中只是用了一個 RTC 設備,所以沒有對其進行編號,如果是新創建的 RTC 設備需要注意 name 字段,在驅動中默認使用的是g_rtc,不然編譯會提示沒有相應的設備,修改 Callback 為 rtc_callback。
- 配置RTC和alarm組件
然后打開對應的通道
同時打開alarm組件。
4 RTC代碼實現
首先設置了年月日時分秒信息,然后獲取當前時間,接著設置一個alarm,值得注意的是,alarm是基于RTC的,因此需要先將RTC初始化,然后才能開啟alarm事件。核心代碼如下:
#include < rtthread.h >
#include < rtdevice.h >
#include < time.h >
#define DBG_LEVEL DBG_LOG
#define DBG_SECTION_NAME "rtc"
#include < rtdbg.h >
#define RTC_NAME "rtc"
rt_sem_t rtc_init_sem = RT_NULL;
static int uesr_rtc_init(void)
{
rt_err_t ret = RT_EOK;
time_t now;
rt_device_t device = RT_NULL;
/*創建初始化完成信號量*/
rtc_init_sem = rt_sem_create("rtc init flag", 0, 0);
if(rtc_init_sem == RT_NULL)
{
rt_kprintf("rtc sem init failed!");
return RT_ERROR;
}
/*尋找設備*/
device = rt_device_find(RTC_NAME);
if (!device)
{
rt_kprintf("find %s failed!", RTC_NAME);
return RT_ERROR;
}
/*初始化RTC設備*/
if(rt_device_open(device, 0) != RT_EOK)
{
rt_kprintf("open %s failed!", RTC_NAME);
return RT_ERROR;
}
/* 設置日期 */
ret = set_date(2023, 06, 21);
if (ret != RT_EOK)
{
rt_kprintf("set RTC date failed\\n");
return ret;
}
/* 設置時間 */
ret = set_time(20, 57, 50);
if (ret != RT_EOK)
{
rt_kprintf("set RTC time failed\\n");
return ret;
}
rt_sem_release(rtc_init_sem);
/* 獲取時間 */
now = time(RT_NULL);
rt_kprintf("RTC device init success,now time is %s\\n", ctime(&now));
return ret;
}
/*作為用戶APP初始化*/
INIT_APP_EXPORT(uesr_rtc_init);
static time_t now;
void user_alarm_callback(rt_alarm_t alarm, time_t timestamp)
{
now = time(RT_NULL);
rt_kprintf("The alarm clock rings, now time is %s\\n", ctime(&now));
rt_alarm_stop(alarm);
}
void alarm_test(void)
{
if(rt_sem_trytake(rtc_init_sem) != RT_EOK)
{
rt_kprintf("please init rtc first");
return ;
}
struct rt_alarm_setup setup;
struct rt_alarm * alarm = RT_NULL;
static time_t now;
struct tm p_tm;
if (alarm != RT_NULL)
return;
/*獲取當前時間戳,并把下一秒時間設置為鬧鐘時間 */
now = time(NULL) + 5;
gmtime_r(&now,&p_tm);
setup.flag = RT_ALARM_SECOND;
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