Skip to content

RTC时钟

esp32里面的RTC部件和SNTP服务可以用于获取时间

是顺着一个部分的时候

  1. esp32进行wifi的连接
  2. 使用SNTP网络时间库进行时间的校准
  3. 通过RTC库设置时区, 对获取的数据进行转换
  4. 使用time.h文件对时间进行转换

STNP

网络时间协议NTP的一个子集, 使用NTP协议可以获取准确的时间, 会自动获取可靠的服务器, 并且这一个架构有灵活的可扩展性以及很高的精度

使用SNTP的时候精度会有所下降

国内可用的NTP 服务器地址

1.cn.pool.ntp.org

2.cn.pool.ntp.org

3.cn.pool.ntp.org

0.cn.pool.ntp.org

cn.pool.ntp.org

tw.pool.ntp.org

0.tw.pool.ntp.org

1.tw.pool.ntp.org

2.tw.pool.ntp.org

3.tw.pool.ntp.org

esp32提供了sntp时钟同步的库,sntp获得的网络时间可以更新到esp32的系统时钟里面去

时间戳

使用NTP获取的时间戳是一个64位的数据, 前面32位是1970到现在的秒数, 后面的是小数

esp32的SNTP库会在内部调用settimeofday() and adjtime()来自动更新esp32的系统时间。这些两个函数的功能是,当收到来自NTP服务器的信息后,修改esp32的系统时间。

API函数

C语言

常用的结构

c
struct tm
{
  int	tm_sec; //秒
  int	tm_min; //分钟
  int	tm_hour; //当天的小时
  int	tm_mday; //每个月的日期
  int	tm_mon; //月份
  int	tm_year; //从1900年开始的年份
  int	tm_wday; //周几, 周日开始
  int	tm_yday; //每年的第几天
  int	tm_isdst; //Daylight Saving Time flag
};
clock_t 时钟数, 实际是一个long类型
time_t 从1900年1月1日0点UTC时间开始的时间, 实际是一个long类型。单位秒。
struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

函数

函数说明
asctimetm 转 string
ctimetime_t 转 string
gmtimeUTC时间的time_t 转 tm
localtime本地时间的time_t 转 tm
strftime格式化为string
mktimetm 转time_t
c
char *asctime(const struct tm *timeptr);

返回一个方便读取的字符串格式的时间

c
struct tm {
   int tm_sec;     /* 秒,范围从 0 到 59                */
   int tm_min;     /* 分,范围从 0 到 59                */
   int tm_hour;    /* 小时,范围从 0 到 23              */
   int tm_mday;    /* 一月中的第几天,范围从 1 到 31     */
   int tm_mon;     /* 月份,范围从 0 到 11              */
   int tm_year;    /* 自 1900 起的年数                  */
   int tm_wday;    /* 一周中的第几天,范围从 0 到 6      */
   int tm_yday;    /* 一年中的第几天,范围从 0 到 365    */
   int tm_isdst;   /* 夏令时                           */ 
};
c
time_t time(time_t *t);

获取时间, 返回值和传入参数都是返回值可以用于返回一个时间

c
int gettimeofday(struct timeval *tv, struct timezone *tz);

会把当前的时间使用第一个参数传递出来

第二个参数是用来计算时区的

c
struct  timezone{
        int tz_minuteswest;/*和greenwich时间差*/
        int tz_dsttime; 
}
c
sock_t clock();

clock()函数的返回值就是你程序当前运行的时间(毫秒为单位)

sock_t实际是一个long类型的毫秒值

c
double difftime(time_t time2, time_t time1);

double difftime(time_t time1, time_t time2) 返回 time1 和 time2 之间相差的秒数 (time1 - time2)。这两个时间是在日历时间中指定的,表示了自纪元 Epoch(协调世界时 UTC:1970-01-01 00:00:00)起经过的时间。

c
struct tm *gmtime(const time_t *timeptr);

时间格式转换

c
struct tm * tmS = localtime(time_t * p);

localtime 将 time_t (从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数,是一个8字节长度的有符号整数)格式数据转化为tm的格式

c
time_t mktime(struct tm *timeptr);

格式转换

c
size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)

根据 format 中定义的格式化规则,格式化结构 timeptr 表示的时间,并把它存储在 str 中。

说明符替换为实例
%a缩写的星期几名称Sun
%A完整的星期几名称Sunday
%b缩写的月份名称Mar
%B完整的月份名称March
%c日期和时间表示法Sun Aug 19 02:56:02 2012
%d一月中的第几天(01-31)19
%H24 小时格式的小时(00-23)14
%I12 小时格式的小时(01-12)05
%j一年中的第几天(001-366)231
%m十进制数表示的月份(01-12)08
%M分(00-59)55
%pAM 或 PM 名称PM
%S秒(00-61)02
%U一年中的第几周,以第一个星期日作为第一周的第一天(00-53)33
%w十进制数表示的星期几,星期日表示为 0(0-6)4
%W一年中的第几周,以第一个星期一作为第一周的第一天(00-53)34
%x日期表示法08/19/12
%X时间表示法02:50:06
%y年份,最后两个数字(00-99)01
%Y年份2012
%Z时区的名称或缩写CDT
%%一个 % 符号%
c
int gettimeofday(struct  timeval*tv,struct  timezone *tz ); //获取时间
int settimeofday(const struct timeval *tv, const struct timezone *tz); //设置时间

SNTP时间同步

在获取SNTP时间以后会使用settimeofday进行设置时间

包括 SNTP 函数在内的一些 lwIP API 并非线程安全,因此建议在与 SNTP 模块交互时使用 esp_netif component

  1. 要初始化特定的 SNTP 服务器并启动 SNTP 服务,只需创建有特定服务器名称的默认 SNTP 服务器配置,然后调用 esp_netif_sntp_init() 注册该服务器并启动 SNTP 服务。这一个函数会自动获取时间
c
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
esp_netif_sntp_init(&config);
  1. 等待获取时间
c
if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {
    printf("Failed to update system time within 10s timeout");
}

时区

要设置本地时区,请使用以下 POSIX 函数:

  1. 调用 setenv(),将 TZ 环境变量根据设备位置设置为正确的值。时间字符串的格式与 GNU libc 文档 中描述的相同(但实现方式不同)。
  2. 调用 tzset(),为新的时区更新 C 库的运行数据。

完成上述步骤后,请调用标准 C 库函数 localtime()。该函数将返回排除时区偏差和夏令时干扰后的准确本地时间。

c
setenv("TZ","UTC-08:00",1);