1161|2

206

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

[极海M3内核 APM32E103VET6S MINI开发板]03.RTC&日历功能 [复制链接]

 

APM32E103VET6S微控制器带有一个RTC实时时钟单元,它可以应用在我们需要显示日期或者时间的应用场合,通过内部或者外部的时钟源实现精确走时,相比于定时器实现的RTC要准确得多。本方通过RTC的秒中断功能,再结合软件处理实现日期和时间的打印输出,具体步骤如下:

  • 定义一个日期、时间结构体及结构体全局变量,定义一个基础月份对应的天数数组:
typedef struct
{
    uint16_t year;
    uint8_t  month;
    uint8_t  day;
    uint8_t  week;
    uint8_t  hour;
    uint8_t  minute;
    uint8_t  second;
} CALENDAR_TypeDef;

const uint8_t    RTC_DayOfMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
CALENDAR_TypeDef RTC_Calendar;
  • 闰年判断函数:
/*******************************************************************************
 * [url=home.php?mod=space&uid=159083]@brief[/url] * @param       
 * @retval      
 * [url=home.php?mod=space&uid=1020061]@attention[/url] *******************************************************************************/
uint8_t RTC_LeapYear(uint16_t Year)
{
    if(
        (((Year % 400) == 0)                     ) ||   /* Century Leap Year */
        (((Year % 100) != 0) && ((Year % 4) == 0))      /* Normal  Leay Year */
    )
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
  • 通过蔡勒公式获取当前日期对应的是星期几:
/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day)
{
    int w, c, y;

    /* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */
    if((Month == 1) || (Month == 2))
    {
        Month += 12;
        Year  -= 1;
    }

    w = 0;          /* Weekday */
    c = Year / 100; /* Century */
    y = Year % 100; /* Year    */

    w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1;

    while(w < 0) w += 7;

    w %= 7;

    return w;
}
  • 通过读取当前RTC计数器的累加值,将其转换为对应的日期和时间信息:
/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void RTC_UpdateCalendar(void)
{
    static uint32_t PreTotalDay = 0;

    uint32_t TotalSecond = 0;
    uint32_t TotalDay    = 0;

    uint16_t Year  = 1970;
    uint8_t  Month = 0;

    /* Get The RTC Counter Value */
    TotalSecond = RTC_ReadCounter();
    TotalDay    = TotalSecond / 86400;

    if(PreTotalDay != TotalDay)
    {
        PreTotalDay = TotalDay;

        while(TotalDay >= 365)
        {
            if(RTC_LeapYear(Year) == 1)
            {
                if(TotalDay >= 366)
                {
                    TotalDay -= 366;
                }
                else
                {
                    break;
                }
            }
            else
            {
                TotalDay -= 365;
            }

            Year++;
        }

        RTC_Calendar.year = Year;

        while(TotalDay >= 28)
        {
            if((Month == 1) && (RTC_LeapYear(RTC_Calendar.year) == 1))
            {
                if(TotalDay >= 29)
                {
                    TotalDay -= 29;
                }
                else
                {
                    break;
                }
            }
            else
            {
                if(TotalDay >= RTC_DayOfMonth[Month])
                {
                    TotalDay -= RTC_DayOfMonth[Month];
                }
                else
                {
                    break;
                }
            }

            Month++;
        }

        RTC_Calendar.month = Month    + 1;
        RTC_Calendar.day   = TotalDay + 1;

        RTC_Calendar.week  = RTC_GetWeek(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
    }

    RTC_Calendar.hour   =  (TotalSecond % 86400) / 3600;
    RTC_Calendar.minute = ((TotalSecond % 86400) % 3600) / 60;
    RTC_Calendar.second = ((TotalSecond % 86400) % 3600) % 60;
}
  • 通过日期和时间信息将其转换为RTC的计数值,并将计数值设置到RTC中:
/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void RTC_SetDateTime(uint16_t Year, uint8_t Month, uint8_t Day,
                     uint8_t  Hour, uint8_t Min,   uint8_t Sec)
{
    uint32_t TotalSecond = 0;

    uint16_t y = 0;
    uint8_t  m = 0;

    if((Year >= 1970) && (Year <= 2099))
    {
        for(y = 1970;  y < Year; y++)
        {
            if(RTC_LeapYear(y) == 1)
            {
                TotalSecond += 31622400;    /* Total Seconds Of Leap   Year */
            }
            else
            {
                TotalSecond += 31536000;    /* Total Seconds Of Normal Year */
            }
        }

        for(m = 0; m < (Month - 1); m++)
        {
            TotalSecond += RTC_DayOfMonth[m] * 86400;   /* Total Seconds Of Month */

            if((RTC_LeapYear(Year) == 1) && (m == 1))
            {
                TotalSecond += 86400;
            }
        }

        TotalSecond += (uint32_t)(Day - 1) * 86400; /* Total Seconds Of Day    */
        TotalSecond += (uint32_t)Hour      * 3600;  /* Total Seconds Of Hour   */
        TotalSecond += (uint32_t)Min       * 60;    /* Total Seconds Of Minute */
        TotalSecond += Sec;

        RTC_ConfigCounter(TotalSecond);
        RTC_WaitForLastTask();
    }
    else
    {
        printf("\r\nError Date & Time!!!\r\n");
    }
}
  • 打印日期和时间信息:
/******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
******************************************************************************/
void RTC_PrintDateTime(void)
{
    printf("\r\n%04d-%02d-%02d", RTC_Calendar.year, RTC_Calendar.month,  RTC_Calendar.day);

    switch(RTC_Calendar.week)
    {
        case 0 : printf(" SUN "); break;
        case 1 : printf(" MON "); break;
        case 2 : printf(" TUE "); break;
        case 3 : printf(" WED "); break;
        case 4 : printf(" THU "); break;
        case 5 : printf(" FRI "); break;
        case 6 : printf(" SAT "); break;
        default: break;
    }

    printf("%02d:%02d:%02d\r\n", RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
}
  • 自动加载并提取当前工程编译生成时的日期和时间信息,用于后面初始化日期和时间用:
/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void RTC_LoadDefault(void)
{
    char    date[20], time[20];
    char    text[6][5];
    uint8_t index = 0, month = 0;

    memset(date, 0, sizeof(date));
    memset(time, 0, sizeof(time));
    memset(text, 0, sizeof(text)); 

    memcpy(date, __DATE__, sizeof(__DATE__));
    memcpy(time, __TIME__, sizeof(__TIME__));

    char *str;

    str = strtok(date, " ");

    while(str != NULL)
    {
        memcpy(text[index], str, strlen(str));
        index++;

        str = strtok(NULL, " ");
    }

    str = strtok(time, ":");

    while(str != NULL)
    {
        memcpy(text[index], str, strlen(str));
        index++;

        str = strtok(NULL, ":");
    }

#if 0
    for(uint8_t i = 0; i < index; i++)
    {
        printf("\r\n->%s", text[i]);
    }
#endif

    char *strMonth[12] =
    {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    };

    for(uint8_t i = 0; i < 12; i++)
    {
        if(strcmp(text[0], strMonth[i]) == 0)
        {
            month = i + 1;
        }
    }

    RTC_Calendar.day    = atoi(text[1]);
    RTC_Calendar.month  = month;
    RTC_Calendar.year   = atoi(text[2]);
    RTC_Calendar.week   = RTC_GetWeek(RTC_Calendar.year,
                                      RTC_Calendar.month,
                                      RTC_Calendar.day);

    RTC_Calendar.hour   = atoi(text[3]);
    RTC_Calendar.minute = atoi(text[4]);
    RTC_Calendar.second = atoi(text[5]);
}
  • RTC初始化及中断处理实现:
/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void RTC_Init(void)
{
    RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
    PMU_EnableBackupAccess();

    RCM_EnableLSI();
    while(RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);

    RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
    RCM_EnableRTCCLK();

    RTC_WaitForSynchro();
    RTC_WaitForLastTask();

    RTC_EnableInterrupt(RTC_INT_SEC);
    RTC_WaitForLastTask();

    RTC_ConfigPrescaler(32767);
    RTC_WaitForLastTask();

    RTC_LoadDefault();
    RTC_SetDateTime(RTC_Calendar.year, RTC_Calendar.month,  RTC_Calendar.day,
                    RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
    RTC_WaitForLastTask();

    NVIC_EnableIRQRequest(RTC_IRQn, 0, 0);
}


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void RTC_IRQHandler(void)
{
    if(RTC_ReadIntFlag(RTC_INT_SEC) != RESET) 
    {
        RTC_UpdateCalendar();

        RTC_PrintDateTime();
    }

    RTC_ClearIntFlag(RTC_INT_SEC | RTC_INT_OVR);
    RTC_WaitForLastTask();
}

 

 

运行结果:

 

软件工程源代码:

Project.zip (293.36 KB, 下载次数: 10)

最新回复

楼主的RTC示例写得非常清晰明了,感分享!   详情 回复 发表于 2022-9-27 15:03
点赞 关注
个人签名We are a team and we work as a team !
 
 

回复
举报

206

帖子

0

TA的资源

纯净的硅(初级)

沙发
 
本帖最后由 xld0932 于 2022-9-28 09:00 编辑
  • RTC使用使用LSI或者是LSE作为时钟源的配置:
/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void RTC_Init(void)
{
#if 0
    RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
    PMU_EnableBackupAccess();

    RCM_EnableLSI();
    while(RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);

    RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
    RCM_EnableRTCCLK();
#else
    RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
    PMU_EnableBackupAccess();

    BAKPR_Reset();

    RCM_ConfigLSE(RCM_LSE_OPEN);
    while(RCM_ReadStatusFlag(RCM_FLAG_LSERDY) == RESET);

    RCM_ConfigRTCCLK(RCM_RTCCLK_LSE);
    RCM_EnableRTCCLK();
#endif

    RTC_WaitForSynchro();
    RTC_WaitForLastTask();

    RTC_EnableInterrupt(RTC_INT_SEC);
    RTC_WaitForLastTask();

    RTC_ConfigPrescaler(32767);
    RTC_WaitForLastTask();

    RTC_LoadDefault();
    RTC_SetDateTime(RTC_Calendar.year, RTC_Calendar.month,  RTC_Calendar.day,
                    RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
    RTC_WaitForLastTask();

    NVIC_EnableIRQRequest(RTC_IRQn, 0, 0);
}

 

个人签名We are a team and we work as a team !
 
 
 

回复

6960

帖子

11

TA的资源

版主

板凳
 

楼主的RTC示例写得非常清晰明了,感分享!

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表