GD32F3系列RTC,显示时间,并修改时间

首先,要明白的时,RTC要想显示一个日期和时间的话,必须要明白RTC的工作原理

RTC也是一个定时器,我们可以把RTC配置为定时1s的定时器

其次,我们需要一个基准时间,比如1970年1月1日,8:00:00分,这是我们的时间基准,然后我们在这个基准上让RTC定时,当RTC在基准时间上跑了60s时,那么此时的时间就是1970年1月1日,8:01:00分

接下来讲一下,什么时间戳,时间戳就是指一种记录时间的方式,简单的说,时间戳就是一串数字,表示从某个固定时间点开始到现在的时间长度,通常以秒为单位计算。如果以1970年1月1日,8:00:00分为基准时间的话,那么1970年1月1日,8:01:00分的时间戳就是60

配置好RTC的底层代码,让RTC跑起来

#include "bsp_rtc.h"

#ifndef __BSP_RTC_H__
#define __BSP_RTC_H__



#include "gd32f30x.h"
#include <stdio.h>

typedef struct _date_time{
	uint16_t year;
	uint16_t month;
	uint16_t day;
	uint16_t hour;
	uint16_t min;
	uint16_t second;
}date_time_t;
/*测试函数*/

void RTC_init(void);
void time_adjust(uint32_t current_senconds);
uint16_t fml_leap_year(uint16_t year);
uint32_t fml_time_to_stamp(date_time_t date);
uint32_t fml_stamp_to_time( uint32_t timep, date_time_t *date);

配置RTC

#include "bsp_rtc.h"


/* 秒中断标志 */
uint8_t time_interrupt_flag;
//当前日期时间
date_time_t date_time;
date_time_t setting_date_time;
/*
	使能中断管理器并分配优先级
*/


/*
	配置RTC
*/
void rtc_configuration(void)
{
    /* 备份区域的时钟使能*/
    rcu_periph_clock_enable(RCU_BKPI);
	
    //电源管理时钟使能
    rcu_periph_clock_enable(RCU_PMU);
	
    /* 备份区允许访问 */
    pmu_backup_write_enable();

    /* 备份域复位 */
    bkp_deinit();

    /* 使能外部低速时钟 */
    rcu_osci_on(RCU_LXTAL);
    /* 等待低速晶体振荡器稳定 */
    rcu_osci_stab_wait(RCU_LXTAL);

    /* RTC 时钟源选择 */
    rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);

    /* 使能RTC时钟 */
    rcu_periph_clock_enable(RCU_RTC);

    /* 等待寄存器与APB1时钟同步 */
    rtc_register_sync_wait();

    /* 等待最后一次操作完成 */
    rtc_lwoff_wait();

    /* 使能RTC秒中断*/
    rtc_interrupt_enable(RTC_INT_SECOND);

    /* 等待最后一次操作完成*/
    rtc_lwoff_wait();

    /*设置预分频 外部时钟是32.768Hz 分频后就是 1S*/
    rtc_prescaler_set(32767);

    /* 等待最后一次操作完成 */
    rtc_lwoff_wait();
}

void nvic_rtc_configuration(void)
{
    nvic_irq_enable(RTC_IRQn, 1, 1);
}

初始化RTC

void RTC_init(void)
{
	/* NVIC configure */
    nvic_rtc_configuration();

    printf( "This is a RTC demo...... \r\n" );

    //读取备份区寄存器0的数据,也就是 查看时间是否已经配置
    if (bkp_read_data(BKP_DATA_0) != 0xA5A5)
    {
        /* 备份寄存器的值不是0xa5a5,说明RTC没有配置过 */
        printf("This is a RTC demo!\r\n");
        printf("RTC not yet configured....\r\n");

        /* 配置 */
        rtc_configuration();

        printf("RTC configured ok\r\n");

        /* 首次调整时间  传入一个时间戳*/
        time_adjust(946659660);
        bkp_write_data(BKP_DATA_0, 0xA5A5);
    }
    else//不需要更新时间
    {
        /* 检查是否是电源复位标志 */
        if (rcu_flag_get(RCU_FLAG_PORRST) != RESET)
        {
            printf("\r\n\n Power On Reset occurred....");
        }
				 /* 检查是否是软件复位 */
        else if (rcu_flag_get(RCU_FLAG_SWRST) != RESET)
        {
           
            printf("\r\n\n External Reset occurred....");
        }
				 /* 检查复位是否是外部引脚复位 */
        else if (rcu_flag_get(RCU_FLAG_EPRST) != RESET)
        {
           
            printf("\r\n\n External Reset Pin....");
        }

        /* 允许访问备份区域 */
        //rcu_periph_clock_enable(RCU_PMU);
        //pmu_backup_write_enable();

        printf("\r\n No need to configure RTC....");
        /* 等待寄存器与APB1时钟同步 */
        rtc_register_sync_wait();

        /* 使能秒中断 */
        rtc_interrupt_enable(RTC_INT_SECOND);

        /*等待配置完成 */
        rtc_lwoff_wait();
    }

    #ifdef RTCCLOCKOUTPUT_ENABLE
    /* enable PMU and BKPI clocks */
    rcu_periph_clock_enable(RCU_BKPI);
    rcu_periph_clock_enable(RCU_PMU);
    /* 允许操作备份区*/
    pmu_backup_write_enable();

    /* 关闭侵入引脚 */
    bkp_tamper_detection_disable();

    /* 使能时钟输出 */
    bkp_rtc_calibration_output_enable();
    #endif

    /* 清除所有标志 */
    rcu_all_reset_flag_clear();
}

设置时间的函数

/*
    设置时间
    current_senconds:当前时间戳
*/
void time_adjust(uint32_t current_senconds)
{

    rcu_periph_clock_enable(RCU_BKPI);
    rcu_periph_clock_enable(RCU_PMU);
    pmu_backup_write_enable();
    
    /* 等待最后一次操作完成*/
    rtc_lwoff_wait();
    
    /* 改变当前时间 */
    rtc_counter_set(current_senconds);
    
    /*等待最后一次操作完成 */
    rtc_lwoff_wait();

}

时间转换为时间戳

 /*****时间日历转换时间戳*****/
const uint16_t month_days_table[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

uint32_t fml_time_to_stamp(date_time_t date)
{
    static  uint32_t dax = 0;
    static  uint32_t day_count = 0;
    uint16_t leap_year_count = 0;
    uint16_t i;
 
    // 计算闰年数
    for (i = 1970; i < date.year; i++)
    {
        if (fml_leap_year(i))
        {
            leap_year_count++;
        }
    }
 
    // 计算年的总天数
    day_count = leap_year_count * 366 + (date.year - 1970 - leap_year_count) * 365;
 
    // 累加计算当年所有月的天数
    for (i = 1; i < date.month; i++)
    {
        if ((2 == i) && (fml_leap_year(date.year)))
        {
            day_count += 29;
        }
        else
        {
            day_count += month_days_table[i];
        }
    }
 
    // 累加计算当月的天数
    day_count += (date.day - 1);
 
    dax = (uint32_t)(day_count * 86400) + (uint32_t)((uint32_t)date.hour * 3600) + (uint32_t)((uint32_t)date.min * 60) + (uint32_t)date.second;
 
    /* 北京时间补偿 */
    dax = dax - 8*60*60;
 
    return dax;
}

uint16_t fml_leap_year(uint16_t year)
{
    return (((year % 4 == 0)&&(year % 100 != 0)) || (year % 400 == 0));
}
 

时间戳转换为时间


/*****************时间戳日历转换****************/


uint32_t fml_stamp_to_time( uint32_t timep, date_time_t *date)
{
    uint32_t days = 0;
    uint32_t rem = 0;
 
    /* 北京时间补偿 */
    timep = timep + 8*60*60;
 
    // 计算天数
    days = (uint32_t)(timep / 86400);
    rem = (uint32_t)(timep % 86400);
 
 
    // 计算年份
    uint16_t year;
    for (year = 1970; ; ++year)
    {
        uint16_t leap = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
        uint16_t ydays = leap ? 366 : 365;
        if (days < ydays)
        {
            break;
        }
        days -= ydays;
    }
    date->year  =  year;
 
 
    // 计算月份
    static const uint16_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    uint16_t month;
    for (month = 0; month < 12; month++)
    {
        uint16_t mdays = days_in_month[month];
        if (month == 1 && ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
        {
            mdays = 29;
        }
        if (days < mdays)
        {
            break;
        }
        days -= mdays;
    }
    date->month = month;
    date->month += 1;
 
    // 计算日期
    date->day = days + 1;
 
    // 计算时间
    date->hour = rem / 3600;
    rem %= 3600;
    date->min = rem / 60;
    date->second = rem % 60;
 
    return 0;
}

主函数

extern uint8_t time_interrupt_flag;

extern date_time_t date_time;
extern date_time_t setting_date_time;

void mian(void)
{
    RTC_init();void
    
    while(1)
    {
                /* 中断通知 */
        if (time_interrupt_flag == 1)
        {
            /*获取rtc时间戳 */
            int curent_s = rtc_counter_get();
            printf("%d:%d:%d %d:%d:%d\r\n", date_time.year, date_time.month, date_time.day, date_time.hour, date_time.min, date_time.second);
            fml_stamp_to_time( curent_s, &date_time);

            time_interrupt_flag = 0;
        } 
        
//        time_stamp = fml_time_to_stamp(date_time);
//        printf ("time_stamp is %d",time_stamp);
        
        vTaskDelay(1000);
    }
}

修改当前的时间

//如果设置时间的话,修改setting_date_time结构体里面的值,再调用以下函数,把setting_date_time结构体里面的时间转换为时间戳

uint32_t seting_time_stamp = fml_time_to_stamp(setting_date_time);  //得到时间戳
time_adjust(seting_time_stamp);                                     //修改当前的时间戳


void time_adjust(uint32_t current_senconds)
{

    rcu_periph_clock_enable(RCU_BKPI);     //每次修改时间戳时,必须重新使能备份区域的时钟
    rcu_periph_clock_enable(RCU_PMU);      //每次修改时间戳时,必须重新使能电源管理时钟
    pmu_backup_write_enable();             //每次修改时间戳时,必须使能备份区允许访问
    
    /* 等待最后一次操作完成*/
    rtc_lwoff_wait();
    
    /* 改变当前时间 */
    rtc_counter_set(current_senconds);
    
    /*等待最后一次操作完成 */
    rtc_lwoff_wait();

}

时间戳转换时间,时间转换为时间戳部分,转载:(34条消息) 通俗易懂----C语言时间日期与时间戳互相转化_骚气小飞猪的博客-CSDN博客

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值