目的

​ 虽然RTC简单,但是其牵扯的内容却蛮多的,例如时钟控制单元,电源控制,备份寄存器,最主要的目的还是想把下面3章引出来。

原理

​ RTC(Real_Time Clock)实时时钟,用于得到年、月、日、时、分、秒等时间日期信息。目前几乎已经是统一标准了,如图,32.768K经过15次分频后,恰好是1秒,其它时间只要在1秒频率下计数即可,RTC本质上就是一个1秒计数器。为了方便程序使用,内部会转化成年月日时分秒格式存储,并提供通信接口。

​ GD32内置RTC简化了上面的逻辑,直接使用一个32位计数器(2个16bit寄存器拼起来的)存储秒数,例如,1970年1月1号21点30分54秒=0x0+0x0+0x0+21x60x60+30×60+54=77454s,直接写入32位计数器中累加,只要读出该寄存器秒数,再反向运算也就知道日期时间了。

​ 我们经常会遇到下面的需求,

  1. 希望当MCU复位、异常重启时,时间不会丢
  2. 希望MCU断电重启时,时间不会丢
  3. 希望当到达某个时间后,唤醒MCU,其它时间MCU能处于低功耗状态

为此,

1. GD32将RTC分成两部分,把内核部分(预分频器、分频器、计数器、闹钟)放在备份域(后面章节会详解介绍),达到复位重启不丢时间的目的,其它(APB1接口)放在VDD电源域(电源控制章节详细介绍)跟随系统复位初始化,如下1图
2. 增加电池,当VDD断电后,自动切换到电池供电(VBAT),达到MCU断电不丢时间的目的,如下2图
3. 支持各种闹钟,各种中断,直接挂在NVIC上,用于中断响应、唤醒等功能

功能设计

实现一个时钟,具有如下功能

  1. 每秒在串口输出当前时间,格式xxxx-xx-xx xx:xx:xx
  2. 首次上电时,需要配置时间,串口输入
  3. 复位,断电都不会丢失时间

代码如下:

  1. 判断是否首次上电,此处用到了备份域的知识,详细参考下面备份域章节

    /* TRUE 第一次启动 */
    BOOL DRV_POWER_IsFirstBoot(VOID)
    {if (POWER_FIRSTFLAG_VALUE != BKP_ReadBackupRegister(POWER_FIRSTFLAG_REG)){RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_PWR | RCC_APB1PERIPH_BKP, ENABLE);PWR_BackupAccess_Enable(ENABLE);BKP_DeInit();BKP_WriteBackupRegister(POWER_FIRSTFLAG_REG, POWER_FIRSTFLAG_VALUE);return TRUE;}else{return FALSE;}
    }
    
  2. 首次上电,需要初始化RTC,就三步

    1. 选择时钟源,如图有三个选择,代码配置的是第二路,

    2. 配置分频,最终得到1Hz的频率供RTC计数器使用

      static RTC_FirstInit(VOID)
      {DRV_TRACE("First power on need to configure RTC.");/* 选择晶振LSE,低速外部晶振,即32.768Khz */RCC_RTCCLKConfig(RCC_RTCCLKSOURCE_LSE);RCC_LSEConfig(RCC_LSE_EN);while (RCC_GetBitState(RCC_FLAG_LSESTB) == RESET){}RCC_RTCCLK_Enable(ENABLE);RTC_WaitRSF();RTC_WaitLWOFF();/* 分频,即1Hz */RTC_SetPrescaler(32768-1); /* 1s */RTC_WaitLWOFF();
      }
      
    3. 通过串口设置日期时间,并配置到RTC寄存器中

    static time_t RTC_SetTime(VOID)
    {U32 year = 0xFF; U32 mon = 0xFF; U32 day = 0xFF;U32 hour = 0xFF; U32 min = 0xFF; U32 sec = 0xFF;struct tm t;memset(&t, 0, sizeof(t));printf("Please Set Time:\r\n");printf("Please input year:\r\n");scanf("%u", &year);printf("year:%u\r\n", year);printf("Please input mon:\r\n");scanf("%u", &mon);printf("mon:%u\r\n", mon);printf("Please input day:\r\n");scanf("%u", &day);printf("day:%u\r\n", day);printf("Please input hour:\r\n");scanf("%u", &hour);printf("hour:%u\r\n", hour);printf("Please input min:\r\n");scanf("%u", &min);printf("min:%u\r\n", min);printf("Please input sec:\r\n");scanf("%u", &sec);printf("sec:%u\r\n", sec);t.tm_sec = sec;t.tm_min = min;t.tm_hour = hour;t.tm_mday = day;t.tm_mon = mon-1; /* 0-11 */t.tm_year = year-1900; /* 从1900年开始开始计算的 */APP_DEBUG("%u-%u-%u %u:%u:%u", t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);return(mktime(&t));
    }VOID DRV_RTC_TimeAdjust(IN U32 sec)
    {RTC_WaitLWOFF();RTC_SetCounter(sec);RTC_WaitLWOFF();
    }
    
  3. 非首次上电,不需要重新配置RTC,只需要等待AHB接口时钟同步即可,因为RTC内核在备份域,AHB接口VDD供电,所以RTC内核配置不会断电,AHB接口需要同步

    static VOID RTC_NotFristInit(VOID)
    {DRV_TRACE("Just need wait clock synchronized.");RTC_WaitRSF();
    }
    
  4. 获取并显示时间

    #define time DRV_RTC_GetTime
    time_t DRV_RTC_GetTime(time_t *timer)
    {U32 c = 0;c = RTC_GetCounter();if (timer != NULL){*timer = c;}return c;
    }VOID APP_RTC_Test(VOID)
    {BOOL firstBootFlag = FALSE; time_t now = 0;DRV_POWER_DumpBootReason();firstBootFlag = DRV_POWER_IsFirstBoot();DRV_RTC_Init(firstBootFlag);if (TRUE == firstBootFlag){DRV_RTC_TimeAdjust(RTC_SetTime());}while(1){APP_Delay(1000);now = time(NULL);printf("%s", ctime(&now));}
    }
    

代码路径

https://github.com/YaFood/GD32F103/tree/master/TestRTC
https://gitee.com/YaFOOD/GD32F103/tree/master/TestRTC

GD32实战14__RTC相关推荐

  1. GD32实战11__SPI FLASH

    知识点 1. 理解SPI总线原理 2. 强化按时序图编程 3. 掌握FLASH SPI原理 SPI(Serial Peripheral Interface)串行外设接口,是Motorola公司推出的一 ...

  2. GD32实战20__Boot综合实验

    知识点 设计并实现一个boot,需要用到如下知识点, 1. 体会boot的作用2. 新增闪存控制器学习3. 串口知识复习4. FLASH&SPI知识复习5. 状态机知识点复习6. 初识上位机软 ...

  3. GD32实战7__中断

    引子 什么是中断 ​ 举个生活中的小栗子吧,我正在编写这个文档,突然门铃响了,我去开下门,原来是快递,签收完快递后,又回来接着写. ​ 上面的例子中, 1. 我就是CPU 2. 编写文档,是主运行程序 ...

  4. 《嵌入式 – GD32开发实战指南》第3章 GPIO流水灯的前世今生

    开发环境: MDK:Keil 5.30 MCU:GD32F207IK 上一章通过控制GPIO的高低电平实现了流水灯,但只是告诉了大家怎么做,如何实现流水灯,本文将深入剖析的GPIO流水灯的前生今世,深 ...

  5. 《嵌入式 – GD32开发实战指南》第19章 程序加密

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 19.1程序加密工作原理 GD32通过读取芯片唯一ID号来实现程序的保护,防止被抄袭.96位 ...

  6. 《嵌入式 – GD32开发实战指南》第12章 ADC

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 12.1 ADC工作原理 GD32F2系列有 3 个逐次逼近型的ADC,精度为 12 位,有 ...

  7. 《嵌入式 – GD32开发实战指南》第14章 内部温度传感器

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 14.1内部温度传感器工作原理 GD32 有一个内部的温度传感器,可以用来测量 CPU 及周 ...

  8. 《嵌入式 – GD32开发实战指南》第18章 CRC

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 18.1 CRC的校验原理 循环冗余校验(CRC)计算单元是根据固定的生成多项式得到任一32 ...

  9. 《嵌入式 – GD32开发实战指南》第2章 初识GPIO流水灯

    开发环境: MDK:Keil 5.30 MCU:GD32F207IK 2.1 GPIO工作原理 熟悉单片机的朋友都知道,学习的第一个例程就是流水灯,要想实现流水灯,首先必须了解GPIO的工作原理.GP ...

  10. 《嵌入式 – GD32开发实战指南》第20章 GD32的存储结构

    开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 20.1 GD32存储结构的工作原理 20.1.1 Cortex-M内核的存储器映射 存储器 ...

最新文章

  1. 返回子串CF 312A(Whose sentence is it?-strstr(s,p))
  2. html用a标签怎么提交表单?
  3. 关于oracle分组后组外排序的问题
  4. JavaScript学习笔记:AJAX基础
  5. 关于Java的File.separator
  6. [Python] L1-007. 念数字-PAT团体程序设计天梯赛GPLT
  7. C语言实现三子棋游戏
  8. 《Steve Jobs》
  9. 太赞了!分享一个数据科学利器 PyCaret,几行代码搞定从数据处理到模型部署
  10. 【python面向对象】技能系统
  11. html5离散数学,离散数学怎样判断合取范式和析取范式
  12. java 抓图程序的实现
  13. 机器学习sklearn-线性回归
  14. 测试人的后半生:跑滴滴还是送外卖?
  15. 完整的网络端口表《二》
  16. 网页中嵌入外部页面的四种方法
  17. python编写赛车_90%的人说Python程序慢,5大神招让你的代码像赛车一样跑起来
  18. cstring转int(long转CString)
  19. 工作技能不等于工作能力——工作能力的5个维度
  20. 如何一次高效的插入200MB(50万条)的insert语句

热门文章

  1. 产品基础——认识竞品分析
  2. 2017年全国数学建模国赛B题题目、解题思路、matlab代码(三)
  3. Echarts图表位置调整
  4. NODE.JS对接验证码短信接口DEMO示例
  5. 华为HCIE云计算培训笔记第5天
  6. QThread 的使用
  7. js pdf文件 如何调用打印机打印_js直接打印pdf文件内容
  8. matplotlib绘制圆饼图
  9. 网页设计html轮播代码,20行js代码实现网页轮播图效果
  10. MATLAB 绘制折线图