開發(fā)環(huán)境:
RT-Thread Studio:v2.2.6
開發(fā)板:RA6M3 HMI Board開發(fā)板
MCU:R7FA6M3AH3CFB
1 RA6M3 RTC簡介
R7FA6M3 的RTC(Real Time Clock)外設(shè),實(shí)質(zhì)是一個(gè)掉電后還繼續(xù)運(yùn)行的定時(shí)器。從定時(shí)器的角度來說,相對于GPT外設(shè),要簡單很多 ,只有計(jì)時(shí)和觸發(fā)中斷以及輸入捕獲的功能。RTC外設(shè)的特別之處并不在于它的定時(shí)功能,而在于它掉電還繼續(xù)運(yùn)行的特性。
2 RT-Thread 的RTC簡介
RTC (Real-Time Clock)實(shí)時(shí)時(shí)鐘可以提供精確的實(shí)時(shí)時(shí)間,它可以用于產(chǎn)生年、月、日、時(shí)、分、秒等信息。目前實(shí)時(shí)時(shí)鐘芯片大多采用精度較高的晶體振蕩器作為時(shí)鐘源。有些時(shí)鐘芯片為了在主電源掉電時(shí)還可以工作,會外加電池供電,使時(shí)間信息一直保持有效。
在開啟 RTC 設(shè)備框架以及 RTC 驅(qū)動之后,應(yīng)用程序通過 RT-Thread 提供的 RTC設(shè)備管理接口來訪問 RTC 硬件,相關(guān)接口如下所示:
函數(shù) | 描述 |
---|---|
rt_device_find() | 根據(jù) RTC設(shè)備名稱查找設(shè)備獲取設(shè)備句柄 |
set_date() | 設(shè)置日期,年、月、日(當(dāng)?shù)貢r(shí)區(qū)) |
set_time() | 設(shè)置時(shí)間,時(shí)、分、秒(當(dāng)?shù)貢r(shí)區(qū)) |
另外,alarm 鬧鐘功能是基于 RTC 設(shè)備實(shí)現(xiàn)的,根據(jù)用戶設(shè)定的鬧鐘時(shí)間,當(dāng)時(shí)間到時(shí)觸發(fā) alarm 中斷,執(zhí)行鬧鐘事件。
alarm 組件提供的接口如下所示:
函數(shù) | 描述 |
---|---|
rt_alarm_create() | 創(chuàng)建鬧鐘 |
rt_alarm_start() | 啟動鬧鐘 |
rt_alarm_stop() | 停止鬧鐘 |
rt_alarm_delete() | 刪除鬧鐘 |
rt_alarm_control() | 控制alarm設(shè)備 |
rt_alarm_dump() | 打印顯示設(shè)置的鬧鐘信息 |
關(guān)于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 圖標(biāo),第一次打開需要配置正確的 FSP 安裝路徑。
- FSP配置RTC
1.添加 RTC 設(shè)備
2.配置 RTC
RT-Thread 中只是用了一個(gè) RTC 設(shè)備,所以沒有對其進(jìn)行編號,如果是新創(chuàng)建的 RTC 設(shè)備需要注意 name 字段,在驅(qū)動中默認(rèn)使用的是g_rtc,不然編譯會提示沒有相應(yīng)的設(shè)備,修改 Callback 為 rtc_callback。
- 配置RTC和alarm組件
然后打開對應(yīng)的通道
同時(shí)打開alarm組件。
4 RTC代碼實(shí)現(xiàn)
首先設(shè)置了年月日時(shí)分秒信息,然后獲取當(dāng)前時(shí)間,接著設(shè)置一個(gè)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;
/*創(chuàng)建初始化完成信號量*/
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;
}
/*尋找設(shè)備*/
device = rt_device_find(RTC_NAME);
if (!device)
{
rt_kprintf("find %s failed!", RTC_NAME);
return RT_ERROR;
}
/*初始化RTC設(shè)備*/
if(rt_device_open(device, 0) != RT_EOK)
{
rt_kprintf("open %s failed!", RTC_NAME);
return RT_ERROR;
}
/* 設(shè)置日期 */
ret = set_date(2023, 06, 21);
if (ret != RT_EOK)
{
rt_kprintf("set RTC date failed\\n");
return ret;
}
/* 設(shè)置時(shí)間 */
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);
/* 獲取時(shí)間 */
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;
/*獲取當(dāng)前時(shí)間戳,并把下一秒時(shí)間設(shè)置為鬧鐘時(shí)間 */
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