RTC试验
准备资源:
1)GD32F307C-EVL开发板一块
2)RS232串口线一根
试验目的:
当第一次配置RTC时,通过串口设定RTC时间,时间设定完成后,通过串口将时间打印出来,且后续存在备用电源的情况下无需重新配置时间,实现RTC功能。
硬件原理图
1)首先查看GD32F30x用户手册,可以看到RTC可供选择的时钟源。
2)查看开发板原理图,可以看到开发板上存在外部时钟LXTAL(32.768KHz),试验选择该时钟源作为RTC时钟。
实现代码一rtc.c文件
需要注意的是,GD32F307只有一个32位计数寄存器,没有分日历和时间进行存储,如果需要实现日历的显示,需要通过软件完成。这里没有实现日历功能,只实现简单的24小时制时间显示功能。
1)首先在rtc.h头文件声明以下几个函数
//秒中断初始化函数
void nvic_rtc_init(void);
//RTC初始化函数
void rtc_init(void);
//处理电脑端发送过来的串口数据
uint8_t usart_scanf(uint32_t value);
//输入设定时间函数
uint32_t rtc_input_time(void);
//rtc计数器寄存器设置
void rtc_register_set(void);
//时间显示函数
void rtc_time_display(uint32_t getTime);
2)rtc.c文件,程序如下:
#include "rtc.h"
#include "gd32f307c_eval.h"
//初始化一个volatile全局变量timeset:作为设置时间完成后的标志,当通过串口设置时间成功后则置为1
__IO uint32_t timeset = 0;
//RTC中断初始化
void nvic_rtc_init(void)
{
//中断优先级组配置
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
//中断使能:抢占优先级1,响应优先级0
nvic_irq_enable(RTC_IRQn,1,0);
}
//RTC初始化函数
void rtc_init(void)
{
//使能PMU、BKPI时钟
rcu_periph_clock_enable(RCU_PMU);
rcu_periph_clock_enable(RCU_BKPI);
//使能对备份域中寄存器的写访问;设置PMU_CTL寄存器的BKPWEN位
pmu_backup_write_enable();
//软件触发备份域复位:设置RCU_BDCTL寄存器BKPRST位
bkp_deinit();
//使能外部时钟 LXTAL
rcu_osci_on(RCU_LXTAL);
rcu_osci_stab_wait(RCU_LXTAL);
//选择外部时钟
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
//使能RTC时钟
rcu_periph_clock_enable(RCU_RTC);
rtc_register_sync_wait();
rtc_lwoff_wait();
//使能秒中断和闹钟中断
rtc_interrupt_enable(RTC_INT_SECOND);
rtc_interrupt_enable(RTC_INT_ALARM);
rtc_lwoff_wait();
//设置分频
rtc_prescaler_set(32767);
rtc_lwoff_wait();
}
//串口数据处理函数
uint8_t usart_scanf(uint32_t value)
{
uint32_t i = 0;
uint32_t temp[2] = {0,0};
while(i<2){
//等待串口发送完数据
while (usart_flag_get(USART0, USART_FLAG_RBNE) == RESET);
temp[i++] = (usart_data_receive(USART0));
//在ASCIIC码中数字 0~9对 应的十六进制数为 0x30 ~ 0x39
if( (temp[i-1]<0x30) || (temp[i-1]>0x39) ){
printf("please input your number between 0~9\n");
i--;
}
}
//判断temp[]中的值是否在0~value之间
i = (temp[1]-0x30) + ((temp[0]-0x30)*10);
if(i>value){
printf("please input your number between 0and %d\n", value);
return 0xFF;
}
return i;
}
uint32_t rtc_input_time(void)
{
uint32_t t_hour = 0xFF, t_min = 0xFF, t_sec = 0xFF;
printf("\r\n Please Set Hours");
while(t_hour == 0xFF){
t_hour = usart_scanf(23);
}
printf("hour: %d\n", t_hour);
printf("\r\n Please Set Minutes");
while(t_min == 0xFF){
t_min = usart_scanf(59);
}
printf("Minutes: %d\n", t_min);
printf("\r\n Please Set Seconds");
while(t_sec == 0xFF){
t_sec = usart_scanf(59);
}
printf("Seconds: %d\n", t_sec);
timeset = 1;//标志时间设置完成
return (t_hour*60*60) + (t_min*60) + t_sec;
}
//将设置的时间写入RTC寄存器
void rtc_register_set(void)
{
uint32_t temp = 0;
rtc_lwoff_wait();
temp = rtc_input_time();
rtc_counter_set(temp);
rtc_lwoff_wait();
}
//打印时间
void rtc_time_display(uint32_t getTime)
{
uint32_t m_th = 0, m_tm = 0, m_ts = 0;
m_th = getTime / 3600;
m_tm = (getTime % 3600) / 60;
m_ts = (getTime % 3600) % 60;
printf(" Time: %0.2d:%0.2d:%0.2d\r\n", m_th, m_tm, m_ts);
}
实现代码一gd32f30x_it.c文件
在rtc.c文件中将RTC设置了秒中断,所以需要在gd32f30x_it.c文件中添加RTC中断函数:当rtc秒中断标志位RTC_FLAG_SECOND置位后,即1s时间过去,从而需要将时间通过串口打印出来。
这里将时间打印放在了中断处理函数中,所以在main函数中可以实现其他功能。
另外这里没有设置闹钟中断,需要的话可在实际应用中进行扩展。
void RTC_IRQHandler(void)
{
if(rtc_flag_get(RTC_FLAG_SECOND) != RESET){
rtc_flag_clear(RTC_FLAG_SECOND);
if(timeset == 1){ //timeset = 1:通过串口设置完成时间
rtc_time_display(rtc_counter_get());
}else {
if(bkp_read_data(BKP_DATA_0) == 0xA5A5){
rtc_time_display(rtc_counter_get());
}
}
//更新时间
if(rtc_counter_get() == 0x00015180){//时间为23:59:59,即86400秒
rtc_lwoff_wait();
rtc_counter_set(0x00);
rtc_lwoff_wait();
}
}
}
实现代码一main.c
main函数如下:
int main(void)
{
gd_eval_led_init(LED2);
gd_eval_led_init(LED3);
gd_eval_led_init(LED4);
gd_eval_led_init(LED5);
systick_config();
gd_eval_com_init(EVAL_COM1);
nvic_rtc_init();
if (bkp_read_data(BKP_DATA_0) != 0xA5A5){
rtc_init();
rtc_register_set();
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){
/* check if the pin reset flag is set */
printf("\r\n\n External Reset occurred....");
}
printf("\r\n No need to configure RTC....");
rtc_register_sync_wait();
rtc_lwoff_wait();
/* enable the RTC second */
rtc_interrupt_enable(RTC_INT_SECOND);
rtc_interrupt_enable(RTC_INT_ALARM);
/* wait until last write operation on RTC registers has finished */
rtc_lwoff_wait();
}
rcu_all_reset_flag_clear();
while(1)
{
gd_eval_led_on(LED2);
gd_eval_led_on(LED3);
gd_eval_led_on(LED4);
gd_eval_led_on(LED5);
delay_1ms(1000);
gd_eval_led_off(LED2);
gd_eval_led_off(LED3);
gd_eval_led_off(LED4);
gd_eval_led_off(LED5);
delay_1ms(1000);
}
}
结果
1)编译下载程序后提示设置时间,通过串口设置完成时间。
2)重启系统,提示无需配置RTC,且时间自动打印出来。