学习目标

  1. 理解原理图RTC设计部分
  2. 掌握初始化RTC
  3. 掌握设置时间
  4. 掌握读取时间

    学习内容

    RTC原理图

    078.png

    RTC结构框图

    077.png

    RTC时钟

    开发流程

  5. 加载依赖。gd32f4xx_rtc.c,gd32f4xx_pmu.c

  6. 初始化RTC。
  7. 时钟配置。
  8. 获取时钟。

    RTC初始化

    1. // 电池管理加载
    2. rcu_periph_clock_enable(RCU_PMU);
    3. pmu_backup_write_enable();
    4. // 晶振加载
    5. rcu_osci_on(RCU_LXTAL);
    6. rcu_osci_stab_wait(RCU_LXTAL);
    7. rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
    8. // RTC功能加载
    9. rcu_periph_clock_enable(RCU_RTC);
    10. 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);

  1. ![213.png](https://cdn.nlark.com/yuque/0/2023/png/27903758/1692658785345-5f8a3670-4228-4b9c-a4ab-a1a5a5e23866.png#averageHue=%23faf8f7&clientId=u2ce1441f-b6f6-4&from=ui&id=ue6ecd29e&originHeight=313&originWidth=966&originalType=binary&ratio=1&rotation=0&showTitle=false&size=72919&status=done&style=none&taskId=u50947e4d-b54b-40bf-9198-68061f1bb09&title=)<br />1 = 32.768k/(asyn + 1)/(syn + 1)
  2. - asyn取值范围为00x7F
  3. - syn取值范围为00x07FF
  4. <a name="YsGfY"></a>
  5. #### 时钟获取
  6. ```c
  7. rtc_parameter_struct rps;
  8. rtc_current_time_get(&rps);
  9. uint16_t year = READ_BCD(rps.year) + 2000;
  10. uint8_t month = READ_BCD(rps.month);
  11. uint8_t date = READ_BCD(rps.date);
  12. uint8_t week = READ_BCD(rps.day_of_week);
  13. uint8_t hour = READ_BCD(rps.hour);
  14. uint8_t minute = READ_BCD(rps.minute);
  15. uint8_t second = READ_BCD(rps.second);
  16. 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位)可以表示两个十进制数字。

  1. // 十位取出左移4位 + 个位 (得到BCD数)
  2. #define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)
  3. // 将高4位乘以10 + 低四位 (得到10进制数)
  4. #define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)

完整代码

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include "main.h"
  5. #include "Usart.h"
  6. // 十位取出左移4位 + 个位 (得到BCD数)
  7. #define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)
  8. // 将高4位乘以10 + 低四位 (得到10进制数)
  9. #define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)
  10. void Usart0_recv(uint8_t *data, uint32_t len) {
  11. printf("%s\r\n", data);
  12. }
  13. static void RTC_config() {
  14. // 电池管理加载
  15. rcu_periph_clock_enable(RCU_PMU);
  16. pmu_backup_write_enable();
  17. // 晶振加载
  18. rcu_osci_on(RCU_LXTAL);
  19. rcu_osci_stab_wait(RCU_LXTAL);
  20. rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
  21. // RTC功能加载
  22. rcu_periph_clock_enable(RCU_RTC);
  23. rtc_register_sync_wait();
  24. rtc_parameter_struct rps;
  25. rps.year = WRITE_BCD(23);
  26. rps.month = WRITE_BCD(4);
  27. rps.date = WRITE_BCD(20);
  28. rps.day_of_week = WRITE_BCD(4);
  29. rps.hour = WRITE_BCD(23);
  30. rps.minute = WRITE_BCD(59);
  31. rps.second = WRITE_BCD(55);
  32. rps.display_format = RTC_24HOUR;
  33. rps.am_pm = RTC_AM;
  34. rps.factor_asyn = 0x7F;
  35. rps.factor_syn = 0xFF;
  36. rtc_init(&rps);
  37. }
  38. static void RTC_read() {
  39. rtc_parameter_struct rps;
  40. rtc_current_time_get(&rps);
  41. uint16_t year = READ_BCD(rps.year) + 2000;
  42. uint8_t month = READ_BCD(rps.month);
  43. uint8_t date = READ_BCD(rps.date);
  44. uint8_t week = READ_BCD(rps.day_of_week);
  45. uint8_t hour = READ_BCD(rps.hour);
  46. uint8_t minute = READ_BCD(rps.minute);
  47. uint8_t second = READ_BCD(rps.second);
  48. printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);
  49. }
  50. int main(void)
  51. {
  52. nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
  53. systick_config();
  54. Usart0_init();
  55. RTC_config();
  56. while(1) {
  57. RTC_read();
  58. delay_1ms(1000);
  59. }
  60. }

RTC闹钟

开发流程

  1. 配置RTC时钟
  2. 设置RTC闹钟
  3. 配置RTC闹钟中断
  4. 实现中断函数

    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);

  1. <a name="xtUiV"></a>
  2. #### 中断函数
  3. ```c
  4. void RTC_Alarm_IRQHandler() {
  5. if (SET == rtc_flag_get(RTC_FLAG_ALRM0)) {
  6. // 处理RTC闹钟中断
  7. printf("alarm \r\n");
  8. }
  9. rtc_flag_clear(RTC_FLAG_ALRM0);
  10. exti_flag_clear(EXTI_17);
  11. }

完整代码

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include "main.h"
  5. #include "Usart.h"
  6. // 十位取出左移4位 + 个位 (得到BCD数)
  7. #define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)
  8. // 将高4位乘以10 + 低四位 (得到10进制数)
  9. #define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)
  10. void Usart0_recv(uint8_t *data, uint32_t len) {
  11. printf("%s\r\n", data);
  12. }
  13. static void RTC_config() {
  14. // 电池管理加载
  15. rcu_periph_clock_enable(RCU_PMU);
  16. pmu_backup_write_enable();
  17. // 晶振加载
  18. rcu_osci_on(RCU_LXTAL);
  19. rcu_osci_stab_wait(RCU_LXTAL);
  20. rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
  21. // RTC功能加载
  22. rcu_periph_clock_enable(RCU_RTC);
  23. rtc_register_sync_wait();
  24. rtc_parameter_struct rps;
  25. rps.year = WRITE_BCD(23);
  26. rps.month = WRITE_BCD(04);
  27. rps.date = WRITE_BCD(20);
  28. rps.day_of_week = WRITE_BCD(04);
  29. rps.hour = WRITE_BCD(23);
  30. rps.minute = WRITE_BCD(59);
  31. rps.second = WRITE_BCD(55);
  32. rps.display_format = RTC_24HOUR;
  33. rps.am_pm = RTC_AM;
  34. rps.factor_asyn = 0x7F;
  35. rps.factor_syn = 0xFF;
  36. rtc_init(&rps);
  37. }
  38. static void RTC_read() {
  39. rtc_parameter_struct rps;
  40. rtc_current_time_get(&rps);
  41. uint16_t year = READ_BCD(rps.year) + 2000;
  42. uint8_t month = READ_BCD(rps.month);
  43. uint8_t date = READ_BCD(rps.date);
  44. uint8_t week = READ_BCD(rps.day_of_week);
  45. uint8_t hour = READ_BCD(rps.hour);
  46. uint8_t minute = READ_BCD(rps.minute);
  47. uint8_t second = READ_BCD(rps.second);
  48. printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);
  49. }
  50. static void ALARM_config() {
  51. // 闹钟外部中断
  52. exti_flag_clear(EXTI_17);
  53. exti_init(EXTI_17,EXTI_INTERRUPT,EXTI_TRIG_RISING);
  54. // 重置闹钟
  55. rtc_alarm_disable(RTC_ALARM0);
  56. rtc_alarm_struct ras;
  57. ras.alarm_mask = RTC_ALARM_HOUR_MASK | RTC_ALARM_MINUTE_MASK | RTC_ALARM_SECOND_MASK;
  58. ras.weekday_or_date = RTC_ALARM_DATE_SELECTED;
  59. ras.alarm_day = 0x21;
  60. ras.alarm_hour = WRITE_BCD(23);
  61. ras.alarm_minute = WRITE_BCD(59);
  62. ras.alarm_second = WRITE_BCD(59);
  63. ras.am_pm = RTC_AM;
  64. rtc_alarm_config(RTC_ALARM0, &ras);
  65. // 中断配置
  66. nvic_irq_enable(RTC_Alarm_IRQn, 2, 2);
  67. rtc_interrupt_enable(RTC_INT_ALARM0);
  68. rtc_flag_clear(RTC_FLAG_ALRM0);
  69. rtc_alarm_enable(RTC_ALARM0);
  70. }
  71. void RTC_Alarm_IRQHandler() {
  72. if (SET == rtc_flag_get(RTC_FLAG_ALRM0)) {
  73. // 处理RTC闹钟中断
  74. printf("alarm \r\n");
  75. }
  76. rtc_flag_clear(RTC_FLAG_ALRM0);
  77. exti_flag_clear(EXTI_17);
  78. }
  79. int main(void)
  80. {
  81. nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
  82. systick_config();
  83. Usart0_init();
  84. RTC_config();
  85. ALARM_config();
  86. while(1) {
  87. RTC_read();
  88. delay_1ms(1000);
  89. }
  90. }

练习题

  1. 实现RTC时钟设置和获取
  2. 实现RTC闹钟的设置和中断配置