本文将讲解如何驱动RTC获取高精度时间并将时间通过OLED显示出来,关于OLED驱动可以参考我的上一篇帖子。
之前的帖子可以参考:
【GD32L233C-START评测】3.移植FreeRTOS到GD32L233
【GD32L233C-START评测】4. 移植RT-Thread到GD32L233
【GD32L233C-START评测】5. IIC驱动OLED
1. 新建文件
新建app_rtc.c以及app_rtc.h并放到app文件夹下,将这两个文件添加到app组下
RTC相关的库文件主要存放在gd32l23x_rtc.c这个文件下。
2. RTC相关初始化与时间获取代码编写
初始化RTC需要时能RCU PMU和BKP时,并且配置RTC时钟为32KHz,还需要初始化时间,本例中初始化时间设置的为2022年1月23号17点40分0秒
注意:初始化的时间日期都需要使用16进制
下面是源代码,我单独编写了一个函数获取年月日时分秒,该函数为rtc_getDateAndTime(),可以给外部使用,主要是用来给OLED显示时间使用。
app_rtc.c
#include <stdio.h>
#include "bmp.h"
#include "app_oled.h"
#include "systick.h"
#include "app_rtc.h"
#include "gd32l23x_rtc.h"
#define RTC_CLOCK_SOURCE_IRC32K
//#define RTC_CLOCK_SOURCE_LXTAL
#define BKP_VALUE 0x32F0
/* setup RTC time value */
/* Initial Date and Time */
DataTimeType InitTime = {
.year = 0x22,
.month = 0x1,
.day = 0x23,
.hour = 0x17,
.min = 0x40,
.sec = 0x00
};
/* Current Time */
DataTimeType rtc_currentTime;
static rtc_parameter_struct rtc_initpara;
static uint32_t prescaler_a = 0, prescaler_s = 0;
static void rtc_pre_config(void);
static void rtc_setup(void);
void RTC_Init(void)
{
/* enable PMU and BKP clock */
rcu_periph_clock_enable(RCU_PMU);
rcu_periph_clock_enable(RCU_BKP);
/* enable the access of the RTC registers */
pmu_backup_write_enable();
rtc_pre_config();
rtc_setup();
/* check if RTC has aready been configured */
// if (BKP_VALUE != RTC_BKP0){
// rtc_setup();
// }else{
// /* detect the reset source */
// if (RESET != rcu_flag_get(RCU_FLAG_PORRST)){
// printf("power on reset occurred....\n\r");
// }else if (RESET != rcu_flag_get(RCU_FLAG_EPRST)){
// printf("external reset occurred....\n\r");
// }
// printf("no need to configure RTC....\n\r");
//
// rtc_show_time();
// }
rcu_all_reset_flag_clear();
}
/*!
\brief RTC configuration function
\param[in] none
\param[out] none
\retval none
*/
static void rtc_pre_config(void)
{
#if defined (RTC_CLOCK_SOURCE_IRC32K)
rcu_osci_on(RCU_IRC32K);
rcu_osci_stab_wait(RCU_IRC32K);
rcu_rtc_clock_config(RCU_RTCSRC_IRC32K);
prescaler_s = 0x13F;
prescaler_a = 0x63;
#elif defined (RTC_CLOCK_SOURCE_LXTAL)
rcu_osci_on(RCU_LXTAL);
rcu_osci_stab_wait(RCU_LXTAL);
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
prescaler_s = 0xFF;
prescaler_a = 0x7F;
#else
#error RTC clock source should be defined.
#endif /* RTC_CLOCK_SOURCE_IRC32K */
rcu_periph_clock_enable(RCU_RTC);
rtc_register_sync_wait();
}
/*!
\brief use hyperterminal to setup RTC time and alarm
\param[in] none
\param[out] none
\retval none
*/
static void rtc_setup(void)
{
/* current time input */
printf("=======Configure RTC Time========\n\r");
rtc_initpara.factor_asyn = prescaler_a;
rtc_initpara.factor_syn = prescaler_s;
rtc_initpara.year = InitTime.year;
rtc_initpara.day_of_week = RTC_SUNDAY;
rtc_initpara.month = InitTime.month;
rtc_initpara.date = InitTime.day;
rtc_initpara.display_format = RTC_24HOUR;
rtc_initpara.am_pm = RTC_PM;
rtc_initpara.hour = InitTime.hour;
rtc_initpara.minute = InitTime.min;
rtc_initpara.second = InitTime.sec;
if(ERROR == rtc_init(&rtc_initpara))
{
printf("\n\r** RTC time configuration failed! **\n\r");
}else
{
printf("\n\r** RTC time configuration success! **\n\r");
rtc_show_time();
RTC_BKP0 = BKP_VALUE;
}
}
/*!
\brief display the current time
\param[in] none
\param[out] none
\retval none
*/
void rtc_show_time(void)
{
rtc_current_time_get(&rtc_initpara);
printf("Time:20%0.2x-%0.2x-%0.2x %0.2x:%0.2x:%0.2x\n", \
rtc_initpara.year, rtc_initpara.month , rtc_initpara.date,\
rtc_initpara.hour, rtc_initpara.minute, rtc_initpara.second);
}
/* Get Current Date-Time */
DataTimeType rtc_getDateAndTime(void)
{
rtc_current_time_get(&rtc_initpara);
rtc_currentTime.year = rtc_initpara.year;
rtc_currentTime.month = rtc_initpara.month;
rtc_currentTime.day = rtc_initpara.date;
rtc_currentTime.hour = rtc_initpara.hour;
rtc_currentTime.min = rtc_initpara.minute;
rtc_currentTime.sec = rtc_initpara.second;
return rtc_currentTime;
}
app_rtc.h
#ifndef __APP_RTC_H__
#define __APP_RTC_H__
#include <stdint.h>
/* Type for year, month, day, hour, min, sec */
typedef struct
{
uint8_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
} DataTimeType;
extern void RTC_Init(void);
extern DataTimeType rtc_getDateAndTime(void);
extern void rtc_show_time(void);
#endif
3. OLED显示
OLED显示我是在main.c中做的
main.c中需要包含app_rtc.h
编写了一个静态函数,获取最新时间,然后使用sprintf()格式化在写到OLED中,通过OLED显示出时间。
static void OLED_ShowTime(void)
{
char currentDate[12];
char currentTime[12];
DataTimeType DateTime;
DateTime = rtc_getDateAndTime();
sprintf(currentDate, "20%0.2x-%0.2x-%0.2x", \
DateTime.year, DateTime.month , DateTime.day);
sprintf(currentTime, "%0.2x:%0.2x:%0.2x\n\r", \
DateTime.hour, DateTime.min, DateTime.sec);
OLED_ShowString(24, 32, (const uint8_t *)currentDate, 16, 1);
OLED_ShowString(24, 48, (const uint8_t *)currentTime, 16, 1);
OLED_Refresh_Gram();
}
mian()函数实现如下:
先初始化RTC,然后每500ms刷新一次OLED,其实1s刷新一次就可以了。
int main(void)
{
/* configure systick */
systick_config();
/* initilize the LEDs, USART and key */
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
gd_eval_com_init(EVAL_COM);
RTC_Init();
IIC_Init();
OLED_Init();
OLED_ShowString(0, 0, (const unsigned char*)"GD32L233C-START", 16, 1);
OLED_ShowString(24, 16, (const unsigned char*)"EEWORLD", 16, 1);
OLED_Refresh_Gram();
while(1)
{
OLED_ShowTime();
//rtc_show_time();
delay_1ms(500);
}
}
4. 显示效果: