【M5Stack物联网开发】第八章 使用传感器(二)

1. 使用RTC

1.1 实时时钟模块

ESP32 Real-Time Clock (RTC) 不是一个独立的模块,而是ESP32 微控制器芯片内部的一部分。它能在多种低功耗模式下提供时间相关的功能,特别适合需要时间管理和调度任务的应用。

  1. 系统 RTC:

    • ESP32 包含一个整合在芯片中的 RTC,通过配置能够实现许多低功耗功能。
    • RTC 是低功耗 CPU(ULP)的一个重要组件,可以在深度睡眠模式下维持运行。
  2. RTC 日历功能:

    • ESP32 内部的 RTC 可以保持当前时间和日期。
    • 在设备断电后,RTC 仍需要外部电源供电(例如纽扣电池)以继续保存时间。

1.2 网络时间协议

NTP(Network Time Protocol)和SNTP(Simple Network Time Protocol)都是用于网络时间同步的协议,它们帮助计算机系统和网络设备在互联网上精确同步其时钟。NTP是一个高度准确的网络时间协议,广泛用于同步计算机系统和网络设备的时钟。NTP可以通过多种层级的时间服务器提供时间同步服务,以保证高精度和可靠性。

主要特点

  1. 高精度:

    • NTP可以将时钟同步到毫秒级别,甚至在理想条件下达到微秒级别的精度。
    • 使用复杂的算法来校正网络延迟和传播时间,保证时间同步的准确性。
  2. 多层级结构:

    • NTP采用层级架构(称为“stratum”),其中一级服务器直接连接到高精度参考时钟(例如GPS)。
    • 二级服务器则从一级服务器获取时间,并为下一级服务器提供同步服务,依此类推,形成层级结构。
  3. 容错和冗余:

    • NTP可以从多个时间源获取时间,并通过投票算法选择最可靠的时间源,增强系统的容错能力。
  4. 复杂性:

    • NTP的实现和配置相对复杂,适用于需要高精度时间同步的大中型网络和关键任务系统。

SNTP是NTP的简化版本,旨在提供相对较简单但足够准确的时间同步服务。它适用于某些对时间精度要求不高、资源有限的嵌入式系统和小型网络。

主要特点

  1. 简化版本:

    • SNTP简化了NTP的算法和功能,易于实现和配置。
    • 实现相对较简单,适合资源有限的设备。
  2. 基本精度:

    • 虽然没有NTP那么高精度,SNTP仍能提供足够准确的时间同步,通常精度可达几毫秒到几十毫秒。
  3. 无多层结构:

    • SNTP不支持NTP的多层级结构,只能直接从一个或多个时间服务器获取时间。
    • 这简化了配置,但也限制了容错能力。
  4. 低资源占用:

    • SNTP占用的资源较少,适合嵌入式系统或处理能力有限的设备。

1.3 标准时间

GMT(Greenwich Mean Time)起源于格林尼治皇家天文台(Royal Observatory, Greenwich)所在地的平均太阳时,即基于太阳在格林尼治的天顶点来定义的时间。GMT作为世界标准时间已有数百年历史,长期以来被用作航海和铁路运输等领域的时间基准。GMT是一个固定时区,没有夏令时调整,是0时区的标准时间。随着时间科学和技术的发展,GMT在精确度和一致性方面有所不足,因此逐渐被UTC取代。

UTC(Coordinated Universal Time)是通过国际原子时(TAI)与地球自转的UT1时间协调生成的全球时间标准。它是现代全球时间标准体系的基石。UTC由国际度量衡大会(CIPM)来协调,目前是国际上用于科学、技术与日常生活的时间标准。UTC是一个全球统一的时间标尺,没有特定地区的相关定义,它的用途广泛,包括国际航空、航海、通信、科学研究等领域。不同地区的本地时间可以通过相对于UTC的偏移量来表示,例如北京时间(CST)是UTC+8小时。

下面是每个大洲中使用最广泛且常见的UTC时区,每个时区代表一个主要区域:

亚洲

  • 中国标准时间(CST)
    • 时区:UTC+8
    • 主要覆盖区域:中国大陆、香港、澳门、台湾。
    • 说明:全年使用中国标准时间,无夏令时。
  • 日本标准时间(JST)
    • 时区:UTC+9
    • 主要覆盖区域:日本
    • 说明:日本标准时间,没有夏令时。

欧洲

  • 中欧时间(CET)
    • 时区:UTC+1
    • 主要覆盖区域:包括法国、德国、意大利、西班牙等大部分西欧和中欧国家。
    • 说明:中欧夏令时(CEST)在夏季使用,偏移量为UTC+2。

非洲

  • 东非时间(EAT)
    • 时区:UTC+3
    • 主要覆盖区域:肯尼亚、坦桑尼亚、乌干达、埃塞俄比亚等东非国家。
    • 说明:大部分东非国家全年使用东非时间,无夏令时。

北美洲

  • 东部标准时间(EST)
    • 时区:UTC-5
    • 主要覆盖区域:美国东部、加拿大东部地区。
    • 说明:东部夏令时(EDT)在夏季使用,偏移量为UTC-4。

南美洲

  • 巴西时间(BRT)
    • 时区:UTC-3
    • 主要覆盖区域:巴西大部分地区。
    • 说明:部分地区在夏季使用巴西夏令时(BRST),偏移量为UTC-2。

大洋洲

  • 澳大利亚东部时间(AEST)
    • 时区:UTC+10
    • 主要覆盖区域:澳大利亚东部,包括新南威尔士、昆士兰、维多利亚等。
    • 说明:澳大利亚东部夏令时(AEDT)在夏季使用,偏移量为UTC+11。

中东

  • 海湾标准时间(GST)
    • 时区:UTC+4
    • 主要覆盖区域:阿拉伯联合酋长国、阿曼。
    • 说明:全年使用,无夏令时。

1.4 C++中的时间处理API

time.h 是C语言标准库中的一个头文件,提供了一组用于日期和时间操作的函数。该文件中的功能涵盖了从获取当前时间和日期,到格式化和操作时间值等多种用途。

关键数据结构

  1. time_t:

    • 定义:time_t 类型通常用于表示自1970年1月1日00:00:00 UTC 起经过的秒数(也称为epoch时间)。
    • 作用:它被广泛用于表示时间点。
  2. struct tm:

    • 定义:struct tm 是一个结构体,用于存储分解的时间值。
    • 复制代码
      struct tm {
          int tm_sec;   // 秒数:0 - 60(允许闰秒)
          int tm_min;   // 分钟:0 - 59
          int tm_hour;  // 小时:0 - 23
          int tm_mday;  // 一个月中的第几天:1 - 31
          int tm_mon;   // 月份:0 - 11(1月表示为0)
          int tm_year;  // 年份:从 1900 年起算的年数(例如,1990 表示为 90)
          int tm_wday;  // 星期几:0 - 6(星期天表示为0)
          int tm_yday;  // 一年中的第几天:0 - 365
          int tm_isdst; // 夏令时标志:正值表示夏令时,零值表示标准时,负值表示信息不可用
      };
      复制代码

常用函数

  1. time

    • 原型:time_t time(time_t *tloc);
    • 功能:获取当前时间,并以 time_t 格式返回。如果 tloc 不为 NULL,那么当前时间也将存储到 tloc 指向的对象中。
  2. clock

    • 原型:clock_t clock(void);
    • 功能:返回程序执行起至调用该函数时所使用的处理器时间(单位是 clock ticks)。
  3. difftime

    • 原型:double difftime(time_t time1, time_t time2);
    • 功能:计算两个时间点 time1 和 time2 之间的秒数差。
  4. mktime

    • 原型:time_t mktime(struct tm *timeptr);
    • 功能:将 struct tm 结构表示的时间转换为 time_t 类型。
  5. gmtime

    • 原型:struct tm *gmtime(const time_t *timer);
    • 功能:将 time_t 类型转换为 UTC(协调世界时)的 struct tm 结构。
  6. localtime

    • 原型:struct tm *localtime(const time_t *timer);
    • 功能:将 time_t 类型转换为本地时间的 struct tm 结构。
  7. ctime

    • 原型:char *ctime(const time_t *timer);
    • 功能:将 time_t 类型的时间转换为字符串格式,表示当地的时间和日期。
  8. asctime

    • 原型:char *asctime(const struct tm *timeptr);
    • 功能:将 struct tm 类型的时间转换为字符串格式。
  9. strftime

    • 原型:size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
    • 功能:根据格式字符串 format 格式化 struct tm 类型的时间,并将结果存储在字符数组 s 中,最多写入 max 个字符。

输出格式

  • %a:星期几的缩写(例如:Sun)。
  • %A:星期几的全称(例如:Sunday)。
  • %b:月份名的缩写(例如:Jan)。
  • %B:月份名的全称(例如:January)。
  • %c:日期和时间的完整格式(例如:Sun Oct 17 04:41:13 2021)。
  • %C:世纪数(年数的前两位数字,00-99)。
  • %d:一月中的第几天(01-31)。
  • %D:日期格式(等同于 %m/%d/%y)。
  • %e:一月中的第几天,用空格填充( 1-31)。
  • %F:ISO 8601 日期格式(等同于 %Y-%m-%d)。
  • %g:ISO 8601 标准下的两位数年份(00-99)。
  • %G:ISO 8601 标准下的四位数年份。
  • %h:月份名的缩写(等同于 %b)。
  • %H:24小时制的小时(00-23)。
  • %I:12小时制的小时(01-12)。
  • %j:一年中的第几天(001-366)。
  • %k:24小时制的小时,用空格填充( 0-23)。
  • %l:12小时制的小时,用空格填充( 1-12)。
  • %m:月份(01-12)。
  • %M:分钟(00-59)。
  • %n:换行符。
  • %p:AM 或 PM 标记。
  • %P:小写的 am 或 pm 标记。
  • %r:12小时制的时间格式(等同于 %I:%M:%S %p)。
  • %R:24小时制的时间格式(等同于 %H:%M)。
  • %S:秒(00-60),允许闰秒。
  • %t:制表符。
  • %T:时间格式(等同于 %H:%M:%S)。
  • %u:星期几(1-7,周一为1)。
  • %U:一年中的第几周,以周日为第一天计算(00-53)。
  • %V:一年中的第几周,按照 ISO 8601 标准计算(01-53)。
  • %w:星期几(0-6,周日为0)。
  • %W:一年中的第几周,以周一为第一天计算(00-53)。
  • %x:日期的格式化字符串(国际化区域设定的格式)。
  • %X:时间的格式化字符串(国际化区域设定的格式)。
  • %y:两位数的年份(00-99)。
  • %Y:四位数的年份。
  • %z:ISO 8601 格式的时区偏移(例如:-0500)。
  • %Z:时区名称或缩写。
复制代码
#include <time.h>

int main() {
    // 获取当前时间
    time_t current_time = time(NULL);
    struct tm *local_time = localtime(&current_time);

    char buffer[80];

    // 完整日期和时间
    strftime(buffer, sizeof(buffer), "%c", local_time);
    printf("Full date and time: %s\n", buffer);

    // YYYY-MM-DD 格式
    strftime(buffer, sizeof(buffer), "%Y-%m-%d", local_time);
    printf("ISO date format: %s\n", buffer);

    // 12小时制时间
    strftime(buffer, sizeof(buffer), "%I:%M:%S %p", local_time);
    printf("12-hour time: %s\n", buffer);

    // 24小时制时间
    strftime(buffer, sizeof(buffer), "%H:%M:%S", local_time);
    printf("24-hour time: %s\n", buffer);

    // 星期几
    strftime(buffer, sizeof(buffer), "%A", local_time);
    printf("Day of the week: %s\n", buffer);

    // ISO 8601 week number
    strftime(buffer, sizeof(buffer), "Week number: %V", local_time);
    printf("%s\n", buffer);

    return 0;
}
复制代码

 

2. 使用GPS模块

2.1 全球定位系统

全球定位系统(Global Positioning System, GPS)是一种利用卫星进行导航和位置计算的系统,它能够提供全球范围内的定位和时间信息。

除了美国的GPS,还有其他国家或地区开发的全球导航卫星系统,类似于GPS,如:

  • GLONASS:俄罗斯的全球导航卫星系统。
  • Galileo:欧洲的全球导航卫星系统。
  • 北斗:中国的全球导航卫星系统。

这些系统共同构成了全球导航卫星系统(Global Navigation Satellite System, GNSS),提供更可靠和精确的定位服务。

2.2 经纬度

经纬度(Longitude and Latitude)是一种用于描述地球表面某个点的位置的坐标系统。通过经纬度可以精确确定地点在地球上的位置。

纬度是指一个点在地球上的南北位置。纬线为东西方向的平行线,并与赤道平行。主要特点和定义如下:

纬度(Latitude)

纬度是指一个点在地球上的南北位置。纬线为东西方向的平行线,并与赤道平行。主要特点和定义如下:

  • 赤道:赤道是0°纬线,将地球分为北半球和南半球。
  • 南北极:北极为90°N(北纬),南极为90°S(南纬)。
  • 范围:纬度的范围从赤道的0°到北极的+90°(北纬),以及从赤道的0°到南极的-90°(南纬)。
  • 表示方式:纬度一般用度(°)、分(′)和秒(″)来表示。例如,北纬37度14分6秒表示为37°14'6"N。

经度(Longitude)

经度是指一个点在地球上的东西位置。经线为南北方向的半圆线,所有经线在地极相交。主要特点和定义如下:

  • 本初子午线:0°经线,又称格林尼治子午线(通过英国伦敦的格林尼治天文台),将地球分为东经和西经两部分。
  • 国际日期变更线:大约在180°经线的位置,用于确定日期变化。
  • 范围:经度的范围从本初子午线的0°到东经+180°和西经-180°。
  • 表示方式:经度一般用度(°)、分(′)和秒(″)来表示。例如,东经121度29分14秒表示为121°29'14"E。从格林尼治向东称为东经,从格林尼治向西称为西经。

经纬度的表示方法

一个具体位置的经纬度表示方法结合了两个坐标:

  • 格式:纬度在前,经度在后。例如,北京市天安门广场的经纬度为39°54'26"N, 116°23'17"E。
  • 如果使用double格式可以表示为39.5426和116.2317

2.3 NMEA协议

NMEA(National Marine Electronics Association,国家海洋电子协会)是一个标准协议,用于传输来自GPS、声纳、测深仪和其他导航设备的数据。NMEA协议的主要目标是确保不同设备之间数据通信的兼容性,使得数据能在不同厂商的设备之间互换。这种标准协议被广泛应用于船舶和航空导航系统。

NMEA 0183协议

NMEA 0183是最常见的NMEA协议版本,也是目前使用最广泛的。NMEA 0183协议定义了数据在单个数据流中的传输方法,有几个关键特征:

  1. 数据格式:NMEA 0183消息通常是ASCII格式,以逗号分隔。
  2. 波特率:标准波特率为4800bps,但也有9600bps或更高的实现。
  3. 消息类型:每条NMEA消息的开头都有一个特定的消息标识符,用以区分不同类型的数据。
  4. 终止符:每条消息以回车换行符结束(<CR><LF>)。

NMEA消息结构

NMEA消息通用格式如下:

 
$<Talker ID><Message Type>,<Data1>,<Data2>,...,<Checksum>*<CR><LF>
  • $:消息起始符。
  • <Talker ID>:两个字符,表示发送消息的设备。例如,GP为标准GPS接收机,UB为u-blox GPS模块。
  • <Message Type>:三个字符,指示消息的类型。例如,GGARMCGLL等。
  • <Data>:以逗号分隔的数据字段。
  • <Checksum>:校验和,用于验证消息是否传输完整和正确。

常见NMEA GPS消息类型

  1. GGA - Global Positioning System Fix Data

    • 提供固定时间的位置和相关数据。
    • 示例消息:
       
      $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
    • 字段解释:
      • $GPGGA:消息标识符
      • 123519:UTC时间(12:35:19)
      • 4807.038,N:纬度48度07.038分北(N)
      • 01131.000,E:经度11度31.000分东(E)
      • 1:GPS定位质量指示(0 = 无定位,1 = GPS定位,2 = 差分GPS定位)
      • 08:使用中的卫星数
      • 0.9:水平精度因子
      • 545.4,M:天线离海平面的高度,单位为米
      • 46.9,M:大地水准面分离,从椭球到大地水准面的高度
      • ,,:未使用
      • *47:校验和
  2. RMC - Recommended Minimum Specific GPS/Transit Data

    • 提供最低限度的GPS数据,包括时间、日期、位置、速度和航向等。
    • 示例消息:
       
      $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
    • 字段解释:
      • $GPRMC:消息标识符
      • 123519:UTC时间(12:35:19)
      • A:数据状态(A = 有效,V = 无效)
      • 4807.038,N:纬度48度07.038分北(N)
      • 01131.000,E:经度11度31.000分东(E)
      • 022.4:速度(单位:节)
      • 084.4:航向(度)
      • 230394:UTC日期(23 March 1994)
      • 003.1,W:磁偏角(3.1度西(W))
      • *6A:校验和
  3. GSA - GPS DOP and Active Satellites

    • 提供与当前使用的卫星和位置精度有关的信息。
    • 示例消息:
       
      $GPGSA,A,3,04,05,,09,12,,24,,,,,2.5,1.3,2.1*39
    • 字段解释:
      • $GPGSA:消息标识符
      • A:自动选择2D或3D模式(M = 手动,A = 自动)
      • 3:定位类型(1 = 无定位,2 = 2D,3 = 3D)
      • 04,05,...:当前使用的卫星PRN号
      • 2.5:位置精度因子(PDOP)
      • 1.3:水平精度因子(HDOP)
      • 2.1:垂直精度因子(VDOP)
      • *39:校验和
  4. GSV - GPS Satellites in View

    • 提供当前可见的所有卫星的详细信息。
    • 示例消息:
       
      $GPGSV,2,1,08,01,40,083,41,02,50,123,42,03,60,203,43,04,70,053,44*70
    • 字段解释:
      • $GPGSV:消息标识符
      • 2:总消息数
      • 1:当前消息编号
      • 08:可见卫星总数
      • 01,40,083,41:卫星1的PRN号,仰角,方位角,信号强度(重复出现,每条消息最多包含4颗卫星信息)
      • *70:校验和
  5. GLL - Geographic Position - Latitude/Longitude

    • 提供当前的纬度和经度。
    • 示例消息:
       
      $GPGLL,4916.45,N,12311.12,W,225444,A,*1D
    • 字段解释:
      • $GPGLL:消息标识符
      • 4916.45,N:纬度49度16.45分北(N)
      • 12311.12,W:经度123度11.12分西(W)
      • 225444:UTC时间(22:54:44)
      • A:数据状态(A = 有效,V = 无效)
      • *1D:校验和

校验和(Checksum)

每条NMEA消息以星号(*)和校验和结束。校验和是从$开始到*之前所有字符的异或(XOR)结果,用于验证数据的完整性。如果消息校验失败,意味着数据在传输过程中出现错误,接收端可以忽略这条消息。

3. 小程序:旅行位置记录

3.1 功能分析

  1. 初始化模块:

    • 初始化ESP32、GPS模块、RTC模块和存储设备(如microSD卡)。
    • 检查各模块的连接和状态,确保工作正常。
  2. 获取GPS数据:

    • 通过UART接口与GPS模块(AT6558)通信,读取NMEA数据。
    • 使用TinyGPS++库解析NMEA数据,获取经纬度、速度、方向、时间等信息。
  3. 获取RTC时间:

    • 使用RTC库读取RTC时间,确保时间记录准确。
  4. 数据存储:

    • 将获取的GPS数据和RTC时间格式化并写入存储设备。
    • 数据格式可考虑TXT或JSON格式,方便后续数据处理和分析。

3.2 伪代码

 

3.3 功能实现

4. 小练习:利用GPS信息,当传感器到达特定位置时,播放声音

 

posted @   庞兴庆  阅读(76)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示