基于GD32F307的嵌入式学习之路--RTC

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,且时间自动打印出来。

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iFan&iLT123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值