学习目标
- 理解原理图RTC设计部分
- 掌握初始化RTC
- 掌握设置时间
-
学习内容
RTC原理图
RTC结构框图
RTC时钟
开发流程
加载依赖。
gd32f4xx_rtc.c,gd32f4xx_pmu.c- 初始化RTC。
- 时钟配置。
- 获取时钟。
RTC初始化
// 电池管理加载rcu_periph_clock_enable(RCU_PMU);pmu_backup_write_enable();// 晶振加载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电源供应为外部独立电路,需要加载电源管理,打开rtc电源供应。
- RTC的时钟晶振为外部,需要加载外部晶振。
- 加载完成过程,需要等待同步。
时钟配置
```c rtc_parameter_struct rps; rps.year = 0x23; rps.month = 0x04; rps.date = 0x20; rps.day_of_week = 0x04; rps.hour = 0x23; rps.minute = 0x59; rps.second = 0x55; rps.display_format = RTC_24HOUR; rps.am_pm = RTC_AM; rps.factor_asyn = 0x7F; rps.factor_syn = 0xFF;
rtc_init(&rps);
<br />1 = 32.768k/(asyn + 1)/(syn + 1)- asyn取值范围为0到0x7F- syn取值范围为0到0x07FF<a name="YsGfY"></a>#### 时钟获取```crtc_parameter_struct rps;rtc_current_time_get(&rps);uint16_t year = READ_BCD(rps.year) + 2000;uint8_t month = READ_BCD(rps.month);uint8_t date = READ_BCD(rps.date);uint8_t week = READ_BCD(rps.day_of_week);uint8_t hour = READ_BCD(rps.hour);uint8_t minute = READ_BCD(rps.minute);uint8_t second = READ_BCD(rps.second);printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);
BCD格式转化
BCD(Binary-Coded Decimal,二进制编码十进制)是一种用于表示十进制数字的二进制编码形式。在RTC(实时时钟)等应用中,BCD格式常用于存储和显示日期和时间信息。它的主要特点是每个十进制数位都被编码成4位二进制数。
在BCD格式中,一个十进制数的每一位被表示为4位二进制数,其中每个二进制数位都对应一个十进制数位。例如:
- 十进制数 0 用BCD表示为 0000。
- 十进制数 1 用BCD表示为 0001。
- 十进制数 9 用BCD表示为 1001。
这样,一个BCD字节(8位)可以表示两个十进制数字。
// 十位取出左移4位 + 个位 (得到BCD数)#define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)// 将高4位乘以10 + 低四位 (得到10进制数)#define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)
完整代码
#include "gd32f4xx.h"#include "systick.h"#include <stdio.h>#include "main.h"#include "Usart.h"// 十位取出左移4位 + 个位 (得到BCD数)#define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)// 将高4位乘以10 + 低四位 (得到10进制数)#define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)void Usart0_recv(uint8_t *data, uint32_t len) {printf("%s\r\n", data);}static void RTC_config() {// 电池管理加载rcu_periph_clock_enable(RCU_PMU);pmu_backup_write_enable();// 晶振加载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_parameter_struct rps;rps.year = WRITE_BCD(23);rps.month = WRITE_BCD(4);rps.date = WRITE_BCD(20);rps.day_of_week = WRITE_BCD(4);rps.hour = WRITE_BCD(23);rps.minute = WRITE_BCD(59);rps.second = WRITE_BCD(55);rps.display_format = RTC_24HOUR;rps.am_pm = RTC_AM;rps.factor_asyn = 0x7F;rps.factor_syn = 0xFF;rtc_init(&rps);}static void RTC_read() {rtc_parameter_struct rps;rtc_current_time_get(&rps);uint16_t year = READ_BCD(rps.year) + 2000;uint8_t month = READ_BCD(rps.month);uint8_t date = READ_BCD(rps.date);uint8_t week = READ_BCD(rps.day_of_week);uint8_t hour = READ_BCD(rps.hour);uint8_t minute = READ_BCD(rps.minute);uint8_t second = READ_BCD(rps.second);printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);}int main(void){nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);systick_config();Usart0_init();RTC_config();while(1) {RTC_read();delay_1ms(1000);}}
RTC闹钟
开发流程
- 配置RTC时钟
- 设置RTC闹钟
- 配置RTC闹钟中断
- 实现中断函数
RTC闹钟初始化
```c // 闹钟外部中断 exti_flag_clear(EXTI_17); exti_init(EXTI_17,EXTI_INTERRUPT,EXTI_TRIG_RISING);
// 重置闹钟 rtc_alarm_disable(RTC_ALARM0);
rtc_alarm_struct ras; ras.alarm_mask = RTC_ALARM_HOUR_MASK | RTC_ALARM_MINUTE_MASK | RTC_ALARM_SECOND_MASK; ras.weekday_or_date = RTC_ALARM_DATE_SELECTED; ras.alarm_day = 0x21; ras.alarm_hour = WRITE_BCD(23); ras.alarm_minute = WRITE_BCD(59); ras.alarm_second = WRITE_BCD(59); ras.am_pm = RTC_AM; rtc_alarm_config(RTC_ALARM0, &ras);
// 中断配置 nvic_irq_enable(RTC_Alarm_IRQn, 2, 2); rtc_interrupt_enable(RTC_INT_ALARM0); rtc_flag_clear(RTC_FLAG_ALRM0);
rtc_alarm_enable(RTC_ALARM0);
<a name="xtUiV"></a>#### 中断函数```cvoid RTC_Alarm_IRQHandler() {if (SET == rtc_flag_get(RTC_FLAG_ALRM0)) {// 处理RTC闹钟中断printf("alarm \r\n");}rtc_flag_clear(RTC_FLAG_ALRM0);exti_flag_clear(EXTI_17);}
完整代码
#include "gd32f4xx.h"#include "systick.h"#include <stdio.h>#include "main.h"#include "Usart.h"// 十位取出左移4位 + 个位 (得到BCD数)#define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)// 将高4位乘以10 + 低四位 (得到10进制数)#define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)void Usart0_recv(uint8_t *data, uint32_t len) {printf("%s\r\n", data);}static void RTC_config() {// 电池管理加载rcu_periph_clock_enable(RCU_PMU);pmu_backup_write_enable();// 晶振加载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_parameter_struct rps;rps.year = WRITE_BCD(23);rps.month = WRITE_BCD(04);rps.date = WRITE_BCD(20);rps.day_of_week = WRITE_BCD(04);rps.hour = WRITE_BCD(23);rps.minute = WRITE_BCD(59);rps.second = WRITE_BCD(55);rps.display_format = RTC_24HOUR;rps.am_pm = RTC_AM;rps.factor_asyn = 0x7F;rps.factor_syn = 0xFF;rtc_init(&rps);}static void RTC_read() {rtc_parameter_struct rps;rtc_current_time_get(&rps);uint16_t year = READ_BCD(rps.year) + 2000;uint8_t month = READ_BCD(rps.month);uint8_t date = READ_BCD(rps.date);uint8_t week = READ_BCD(rps.day_of_week);uint8_t hour = READ_BCD(rps.hour);uint8_t minute = READ_BCD(rps.minute);uint8_t second = READ_BCD(rps.second);printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);}static void ALARM_config() {// 闹钟外部中断exti_flag_clear(EXTI_17);exti_init(EXTI_17,EXTI_INTERRUPT,EXTI_TRIG_RISING);// 重置闹钟rtc_alarm_disable(RTC_ALARM0);rtc_alarm_struct ras;ras.alarm_mask = RTC_ALARM_HOUR_MASK | RTC_ALARM_MINUTE_MASK | RTC_ALARM_SECOND_MASK;ras.weekday_or_date = RTC_ALARM_DATE_SELECTED;ras.alarm_day = 0x21;ras.alarm_hour = WRITE_BCD(23);ras.alarm_minute = WRITE_BCD(59);ras.alarm_second = WRITE_BCD(59);ras.am_pm = RTC_AM;rtc_alarm_config(RTC_ALARM0, &ras);// 中断配置nvic_irq_enable(RTC_Alarm_IRQn, 2, 2);rtc_interrupt_enable(RTC_INT_ALARM0);rtc_flag_clear(RTC_FLAG_ALRM0);rtc_alarm_enable(RTC_ALARM0);}void RTC_Alarm_IRQHandler() {if (SET == rtc_flag_get(RTC_FLAG_ALRM0)) {// 处理RTC闹钟中断printf("alarm \r\n");}rtc_flag_clear(RTC_FLAG_ALRM0);exti_flag_clear(EXTI_17);}int main(void){nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);systick_config();Usart0_init();RTC_config();ALARM_config();while(1) {RTC_read();delay_1ms(1000);}}
练习题
- 实现RTC时钟设置和获取
- 实现RTC闹钟的设置和中断配置
