RTC,英文全称:Real-time clock,中文名称:实时时钟,是指可以像时钟一様输出实际时间的电子设备,一般会是集成电路,因此也称为时钟芯片。实时时钟芯片是日常生活中应用最为广泛的消费类电子产品之一。它为人们提供精确的实时时间,或者为电子系统提供精确的时间基准,目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。
RTC能够持续记录当前的时间,包括年、月、日、时、分、秒等,甚至可能包括星期几和时区信息(尽管时区信息通常需要用户手动设置)。通常配备电池供电系统,以提供电源备份功能。这样,即使主电源关闭,RTC也能继续运行并维护时间信息。
由于RTC通常与电池供电相关联,它被设计为具有低功耗特性,以延长电池寿命。通常提供与主机设备通信的接口,如I2C或SPI。这些接口允许主机设备读取和设置RTC的时间信息,以及执行其他相关操作。通常具有抗干扰和稳定性能,以确保其在各种环境条件下都能正常运行,并保持时间的准确性。
当前RA-Eco-RA4M2本身自带RTC外设功能,有两种计数模式,日历计数模式和二进制计数模式,通过切换寄存器设置使用。对于日历计数模式,RTC具有从2000年到2099年的100年日历,并自动调整闰年的日期。对于二进制计数模式,RTC计数秒,并保留信息作为串行值。二进制计数模式可用于公历(西历) 以外的日历。
子时钟振荡器或LOCO可以选择作为时间计数器的计数源。RTC使用128Hz的时钟,通过将计 数源除以预分频器的值获得:年、月、日、星期、上午/下午。(12/24 小时模式)、时、分、秒或32位二进制按1/128秒计数。
• 计数模式:日历计数模式和二进制计数模式。
• 时钟源:子时钟或LOCO。
• 日历计数模式:年、月、日、星期、小时、分钟、秒计数。
• 二进制计数模式:32位计二进制计数。
• 闹钟中断:在日历计数模式下,可以与年、月、日、星期、小时、分钟和秒进行比较。在 二进制计数模式下则与32位2进制计数器进行对比。
• 周期性中断:可以选择2秒、1秒、1/2秒、1/4秒、1/8 秒、1/16 秒、1/32 秒、1/64 秒、1/128秒或1/256秒作为中断周期。
• 进位中断:当从64HZ计数器到二进制计数器的进位时和当改变64Hz计数器和R64同时读取CNT寄存器时进行中断。
• 输入捕获:当检测到捕获时间输入引脚的电平发生跳变时(上升沿或者下降沿时),可以进行输入捕获。该输入捕获可以用日历计数或者二进制计数。电平跳变时可以产生中断。与GPT 相同的是,该输入捕获也能使用噪声滤波器。
• 事件关联:周期性输出事件。
• TrustZone 过滤器:可以设置安全属性。
1.打开工程配置文件,启动RTC功能。
2.创建模块,选择RTC功能。
3.配置RTC属性信息
3.生成代码。
1.设置初始时间
/********** 日期宏定义 **********/
#define RTC_YEAR_SET 2025 //年
#define RTC_MON_SET 5 //月
#define RTC_MDAY_SET 8 //日
/* 通过蔡勒公式计算星期,1~6 代表周一到周六,0 代表周日 */
#define RTC_WDAY_SET (RTC_YEAR_SET-2000 \
+ ((RTC_YEAR_SET-2000)/4) \
- 35 + (26*(RTC_MON_SET+1))/10 \
+ RTC_MDAY_SET -1 )%7
/********** 时间宏定义 **********/
#define RTC_HOUR_SET 0 //时
#define RTC_SEC_SET 0 //秒
#define RTC_MIN_SET 0 //分
2.初始化RTC模块
#include "rtc.h"
#include "../oled/oled.h"
void RTC_Init(void)
{
//初始化时设定的时间
rtc_time_t set_time =
{ .tm_sec = RTC_SEC_SET, //秒
.tm_min = RTC_MIN_SET, //分
.tm_hour = RTC_HOUR_SET, //小时
.tm_mday = RTC_MDAY_SET, //日(一个月中)
.tm_wday = RTC_WDAY_SET, //星期
.tm_mon = RTC_MON_SET - 1, //月份,0~11 代表 11~12 月
.tm_year = RTC_YEAR_SET-1900, //年份(如今年是 2008,则这里输入 2008-1900=108)
};
/* 打开 RTC 模块 */
R_RTC_Open (g_rtc0.p_ctrl, g_rtc0.p_cfg);
/* 时钟源设置,如果在 FSP Configuration 设置"Set Source Clock in Open" 为"enabled",那这一步可以被跳过 */
R_RTC_ClockSourceSet (g_rtc0.p_ctrl);
/* 若 RTC 时钟已经使用纽扣电池工作了一段时间,则可以使用这个函数获取当前日历并设置当前时间 */
//R_RTC_CalendarTimeGet(g_rtc0.p_ctrl,&set_time);
/* 这个函数至少调用一次以启动 RTC*/
R_RTC_CalendarTimeSet (g_rtc0.p_ctrl, &set_time); //设置当前时间
/* 设置周期中断的周期为 1 秒 */
R_RTC_PeriodicIrqRateSet (g_rtc0.p_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);
}
3.完善rtc回调函数
void rtc_callback(rtc_callback_args_t *p_args)
{
char buffer[50];
static rtc_time_t get_time;
static uint8_t flag=0;
switch (p_args->event)
{
//周期中断
case RTC_EVENT_PERIODIC_IRQ:
/* 获取当前时间 */
R_RTC_CalendarTimeGet (g_rtc0.p_ctrl, &get_time);
/* 打印当前时间 */
printf ("%04d/%02d/%02d %02d:%02d:%02d week %d\r\n", get_time.tm_year + 1900,
get_time.tm_mon + 1,
get_time.tm_mday,
get_time.tm_hour,
get_time.tm_min,
get_time.tm_sec,get_time.tm_wday);
flag=!flag;
snprintf(buffer,sizeof(buffer),"%02d:%02d",get_time.tm_hour,get_time.tm_min);
OLED_DisplayStr(44,2,8,16,buffer);
if(flag==0)
{
OLED_DisplayStr(44+16,2,8,16," ");
}
snprintf(buffer,sizeof(buffer),"%02d/%02d week %d",get_time.tm_mon+1,get_time.tm_mday,get_time.tm_wday);
OLED_DisplayStr(20,4,8,16,buffer);
break;
default:
break;
}
}
void hal_entry(void)
{
/* TODO: add your own code here */
//使能IO端口
R_IOPORT_Open(&g_ioport_ctrl,g_ioport.p_cfg);
USART9_Init();
Timer0_Init();
OLED_Init();
RTC_Init();//初始化RTC
//R_GPT_Start(&g_timer0_ctrl);
printf("USART9 INIT OK\r\n");
OLED_DisplayStr(28,0,8,16,"RA4M2 RTC");
uint16_t time=0;
uint8_t stat=0;
while(1)
{
if(usart9_rx_flag)
{
usart9_rx_buf[usart9_cnt]='\0';
printf("rx=%s\n",usart9_rx_buf);
//[2025/05/08 16:00:44]rx=*20250508160044
if(usart9_rx_buf[0]=='*' && usart9_cnt==15)//RTC时间校准
{
rtc_time_t set_time;
set_time.tm_year=(usart9_rx_buf[1]-'0')*1000+(usart9_rx_buf[2]-'0')*100+(usart9_rx_buf[3]-'0')*10+(usart9_rx_buf[4]-'0')*1 -1900;
set_time.tm_mon=(usart9_rx_buf[5]-'0')*10+(usart9_rx_buf[6]-'0')*1 - 1;
set_time.tm_mday=(usart9_rx_buf[7]-'0')*10+(usart9_rx_buf[8]-'0')*1;
set_time.tm_wday=(set_time.tm_year-100 + ((set_time.tm_year-100)/4) - 35 + (26*(set_time.tm_mon+2))/10 + set_time.tm_mday -1 )%7;
printf("mon:%d week %d\n",set_time.tm_mon,set_time.tm_wday);
set_time.tm_hour=(usart9_rx_buf[9]-'0')*10+(usart9_rx_buf[10]-'0')*1;
set_time.tm_min=(usart9_rx_buf[11]-'0')*10+(usart9_rx_buf[12]-'0')*1;
set_time.tm_sec=(usart9_rx_buf[13]-'0')*10+(usart9_rx_buf[14]-'0')*1;
printf("set time\r\n");
R_RTC_CalendarTimeSet (g_rtc0.p_ctrl, &set_time); //设置当前时间
}
usart9_cnt=0;
usart9_rx_flag=0;
}
time++;
R_BSP_SoftwareDelay(1,BSP_DELAY_UNITS_MILLISECONDS);
if(time>=500)
{
time=0;
stat=!stat;
LED1(stat);
}
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
更多回帖