瑞萨单片机论坛
直播中

wang123a

7年用户 127经验值
擅长:嵌入式技术 控制/MCU RF/无线
私信 关注
[经验]

【RA-Eco-RA4M2开发板评测】RTC电子钟

RTC电子钟

  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秒计数。

3.1 RTC特性

  • 计数模式:日历计数模式和二进制计数模式。

  • 时钟源:子时钟或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 过滤器:可以设置安全属性。

3.2 RTC配置

  1.打开工程配置文件,启动RTC功能。
image.png

  2.创建模块,选择RTC功能。
image.png

  3.配置RTC属性信息
image.png
image.png

  3.生成代码。

3.3 初始化RTC模块

  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;
    }
}

3.4 RTC模块测试

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
}

3.5 运行效果

image.png
image.png

更多回帖

发帖
×
20
完善资料,
赚取积分