发新帖本帖赏金 50.00元(功能说明)我要提问
返回列表
[APM32F4]

mbedos RTC介绍与使用

[复制链接]
2266|5
手机看帖
扫描二维码
随时随地手机跟帖
DKENNY|  楼主 | 2024-5-30 11:08 | 显示全部楼层 |阅读模式
本帖最后由 DKENNY 于 2024-5-30 11:06 编辑

#申请原创# @21小跑堂


前言
    在嵌入式系统开发中,时间管理对于许多应用程序至关重要。无论是日程安排、数据记录还是事件同步,精确的时间记录都是不可或缺的。在Mbed OS中,RTC(Real Time Clock,实时时钟)起着至关重要的作用,为开发人员提供了可靠且准确的时间跟踪功能。RTC不仅仅是一个简单的时钟,它是系统中的重要组成部分,用于记录时间、定时任务以及事件的时间戳。通过Mbed OS的RTC功能,开发人员可以轻松地处理时间相关的任务,确保系统在各种应用场景下都能准确运行。

1、RTC原理及介绍
  RTC(Real Time Clock,实时时钟)是一种特殊的定时器,在设备掉电后仍然能够继续运行。与普通定时器相比,RTC相对简单,主要用于计时和触发中断。它的特殊之处在于,即使主电源断开,它也可以通过连接锂电池来继续工作,因此在整个APM32芯片中具有特殊的作用。
  RTC的主要特性如下:
  计时功能:RTC具有32位计数器,只能向上计数。它可以使用高速外部时钟的128分频、低速内部时钟LSI以及低速外部时钟LSE作为时钟源。
  掉电继续运行:通过连接锂电池到APM32的RTC备份发卡(通过VBAT引脚供电),即使主电源断开,RTC仍然可以工作。RTC中的数据保存在备份域中,包括RTC模块寄存器以及42个16位寄存器,这些寄存器可以在主电源和备份电源断电时保持数据,不会被复位。
  时钟源选择:由于掉电后高速外部时钟和低速内部时钟会受到影响,所以RTC通常使用低速外部时钟LSE作为时钟源,频率通常为32.768KHz。
  总的来说,RTC在APM32中是一个简单但功能强大的外设,不仅具有计时和中断触发功能,还能在掉电情况下继续运行,保留重要数据。

  如下是APM32F4系列的RTC外设框图。
image001.png

    运行流程:
    当APM32的主电源VDD正常工作时,RTC可以触发三种事件:RTC_Second(每秒触发的中断)、RTC_Overflow(溢出事件)和RTC_Alarm(闹钟中断)。但是,通过结构图可以看出,定时器溢出事件无法配置为中断触发。如果APM32处于待机状态,它可以被闹钟事件或外部唤醒事件(WKUP事件,不属于RTC,属于EXTI模块)唤醒。闹钟事件会在RTC计数器RTC_CNT的值等于闹钟寄存器RTC_ALR的值时触发。

    在备份域中,所有寄存器都是16位的,包括控制RTC的相关寄存器。在配置RTC模块时钟时,通常使用输入频率为32768Hz的RTCCLK,经过32768分频得到实际驱动计数器的时钟TR_CLK=RTCCLK/32768=1Hz,这意味着计时周期为1秒,计时器在1Hz的驱动下计数,即每秒计数器RTC_CNT的值加1。

    更通俗易懂的解释:当APM32电源正常时,RTC相当于是一个时钟守护者,可以在每秒发出提醒、显示时间的效果。如果要把APM32从休眠状态唤醒,可以通过设置闹钟或者外部唤醒按钮来实现。就像闹钟会在设定的时间响起一样,RTC在特定数值时也可以触发操作。备份寄存器在这里起到储存关键数据的作用,类似于备用电源。配置RTC时钟就像是调整时钟上的秒针,确保计时器能够准确计数。

    举个例子:想象你把APM32当做是一台记时器。每当总秒数达到60秒时,记时器会溢出,这个事件无法被配置为提醒。如果你希望在记时器显示特定分钟时提醒你,就相当于设置了一个闹钟。当记时器显示的分钟数等于你设定的值时,闹钟就会响起。同时,备份寄存器就像是一个盒子,可以在关掉电源后保存你的设置,让记时器不会忘记你的设定。配置RTC时钟的过程就像是调整记时器的时钟,以确保时间显示的准确性。

2、mbedos的RTC
  Mbed OS(Mbed Operating System)是一款由Arm开发的开源嵌入式操作系统,专为物联网(IoT)设备和嵌入式系统设计。其 RTC(Real-Time Clock,实时时钟)模块提供了在嵌入式系统中管理时间和日期的功能。下面是相关的API说明。

Mbedos的RTC API说明
  
函数名
  
作用
void set_time(time_t t)
提供基于微控制器实时时钟 (RTC) 设置和读取当前时间的机制,以及一些标准 C 操作和格式化函数。
参数说明:
t 自 1970 年 1 月 1 日以来的秒数(UNIX 时间戳)
void attach_rtc  (time_t(*read_rtc)(void), void(*write_rtc)(time_t), void(*init_rtc)(void),  int(*isenabled_rtc)(void))
连接一个外部 RTC,用于 C 时间功能。
参数说明:
  
read_rtc 指向返回当前 UNIX 时间戳的函数的指针
write_rtc 指向设置当前 UNIX 时间戳的函数的指针,可以为 NULL
init_rtc 指向初始化 RTC 的函数的指针,可以为 NULL
isenabled_rtc 指向返回 RTC 是否已启用的函数的指针,可以为 NULL
int gettimeofday  (struct timeval *tv, void *tz)
标准库重新定位,获取时间。
参数说明:
tv 结构包含 time_t 秒和 useconds_t 微秒。由于 RTC 实现针对不同的目标,因此仅使用秒部分。
  
tz 标准中已弃用:此参数保留在旧代码中。它不再使用。
int settimeofday  (const struct timeval *tv, const struct timezone *tz)
标准库重新定位,设置时间。
参数说明:
  
tv 结构包含 time_t 秒和 useconds_t 微秒。由于 RTC 实现针对不同的目标,因此仅使用秒部分。  
tz 标准中已弃用:此参数保留在旧代码中。它不再使用。


3、UNIX时间戳
  在使用RTC外设之前,我们需要了解UNIX时间戳的概念。
  想象一下,如果我们将RTC_CNT计数器从现在开始置为0,然后每秒加1,那么这个计数器什么时候会溢出呢?由于RTC_CNT是一个32位寄存器,它可以存储的最大值是(2的32次方-1),即大约需要232秒才会溢出,这相当于136年的时间:

  N = (2^32)/365/24/60/60 ≈136年

  举个例子,假设某时刻读取到计数器的数值为X = 60 x 60 x 24x 2,也就是两天的秒数。如果我们知道这个计数器在2011年1月1日的0时0分0秒被置为0,通过这个相对时间数值X,我们可以计算出这个时刻实际对应的是2011年1月3日的0时0分0秒。但是计数器会在(2011+136)年左右溢出,意味着在未来的(2011+136)年,如果我们仍然使用这个计数器来提供时间,就会遇到问题。

  在操作系统中,通常会使用时间戳和计时元年来计算当前时间。大多数系统都采用UNIX时间戳和UNIX计时元年作为共同的参考标准。UNIX计时元年被设定为1970年1月1日0时0分0秒格林尼治时间,这主要是为了纪念UNIX系统的诞生。UNIX时间戳表示当前时间与UNIX计时元年之间经过的秒数。虽然UNIX时间戳主要用于表示当前时间或与计算机相关的时间,考虑到所有文件不可能在1970年前创建,因此UNIX时间戳很少用于表示1970年之前的时间。
  在这种时间计数系统中,使用有符号的32位整数来存储UNIX时间戳,相比之前的例子,实际可用的计数位少了一位。这意味着UNIX计时元年相对较早,而这种计时机制将在2038年1月19日03时14分07秒发生溢出,这个日期并不遥远。由于UNIX时间戳被广泛应用于各种系统中,溢出可能引起严重问题。因此,如果我们在设计长期使用的设备时,就需要特别留意这个潜在问题。

4、RTC例程设计

/*
* Copyright (c) 2006-2020 Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*/
#include "mbed.h"

int main()
{

    // 设置时间戳
    set_time(1716973801);

    while (true) {
        time_t seconds = time(NULL);

        printf("Time as seconds since January 1, 1970 = %u\n", (unsigned int)seconds);

        printf("Time as a basic string = %s", ctime(&seconds));

        char buffer[32];
        strftime(buffer, 32, "%I:%M %p\n", localtime(&seconds));
        printf("Time as a custom formatted string = %s", buffer);

        ThisThread::sleep_for(1s);
    }
}

   这段代码是一个基于Mbed OS的简单程序,用于获取当前时间并以不同的格式打印出来。

1. 设置时间戳
   set_time(1716973801);
   这行代码设置系统的时间戳为 1716973801,这个时间戳代表了从1970年1月1日0时0分0秒开始计算的秒数。

2. 获取当前时间:
   time_t seconds = time(NULL);
   使用 time(NULL) 函数获取当前时间的秒数,并将其存储在 seconds 变量中。

3. 打印时间:
   printf("Time as seconds since January 1, 1970 = %u\n", (unsigned int)seconds);
   这行代码以整数形式打印从1970年1月1日0时0分0秒开始到当前时间的秒数。

   printf("Time as a basic string = %s", ctime(&seconds));
   这行代码以基本的字符串格式打印当前时间,使用了 ctime 函数将时间转换为字符串格式。

   char buffer[32];
   strftime(buffer, 32, "%I:%M %p\n", localtime(&seconds));
   printf("Time as a custom formatted string = %s", buffer);
   这段代码以自定义格式打印当前时间。首先,使用 localtime 函数将时间转换为本地时间,然后使用 strftime 函数按照自定义格式 "%I:%M %p\n" 格式化时间,并将格式化后的时间存储在 buffer 数组中,最后通过 printf 函数打印出来。

    note:strftime 函数介绍:https://www.ibm.com/docs/zh/i/7.5?topic=functions-strftime-convert-datetime-string

4. 延时:
   ThisThread::sleep_for(1s);
   这行代码使程序暂停1秒钟,然后再次执行循环中的代码,以模拟每隔1秒钟获取一次时间并打印出来的效果。


5、获取系统时间戳
   系统当前时间戳的获取可以参考如下的代码。
//获取系统当前时间戳
#include <iostream>
#include <chrono>
#include <ctime>

const std::time_t base_time = 0;

int main()
{
    // 获取当前系统的时间
    auto now = std::chrono::system_clock::now();

    // 将当前时间点转换为time_t格式
    std::time_t now_time = std::chrono::system_clock::to_time_t(now);

    // 计算时间戳
    std::time_t timestamp = now_time - base_time;

    printf("%u", timestamp);
}

    用一根usb线把pc端和APM32F407IG-Tiny板连接后,串口就会一直打印当前系统的时间了。
image003.png


   RTC不仅仅是一个简单的时钟,它是嵌入式系统中的关键组件,为开发人员提供了准确的时间跟踪功能,帮助应用程序处理时间相关的任务。通过合理利用RTC,开发人员可以确保系统在各种应用场景下都能准确运行,并实现精准的时间记录和管理。
    以上就是本次分享的全部内容,欢迎各位讨论交流。

    附件(本帖中所使用的源码):
source.zip (941 Bytes)

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 50.00 元 2024-06-06
理由:恭喜通过原创审核!期待您更多的原创作品~

评论
21小跑堂 2024-6-6 14:35 回复TA
详细介绍RTC的原理与应用,并在APM32平台上使用mbed os操作系统完成程序设计。文章整体结构完整,思路清晰,整体感觉较佳。 
weifeng90| | 2024-6-6 19:33 | 显示全部楼层
第一次听说MbedOS,这是开源免费还是收费版呢?

使用特权

评论回复
DKENNY|  楼主 | 2024-6-6 21:31 | 显示全部楼层
weifeng90 发表于 2024-6-6 19:33
第一次听说MbedOS,这是开源免费还是收费版呢?

这是一个开源的操作系统哦

使用特权

评论回复
丙丁先生| | 2024-6-11 07:06 | 显示全部楼层
APM32F411V Tiny Board 支持这个例程吗?联网同步,会用到RTC吗?

使用特权

评论回复
DKENNY|  楼主 | 2024-6-11 09:35 | 显示全部楼层
丙丁先生 发表于 2024-6-11 07:06
APM32F411V Tiny Board 支持这个例程吗?联网同步,会用到RTC吗?

目前只支持F407系列的

使用特权

评论回复
发新帖 本帖赏金 50.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

18

主题

33

帖子

4

粉丝