当前位置: 首页 > news >正文

网络授时笔记

SNTP的全称是Simple Network Time Protocol,意思是简单网络时间协议,用来从网络中获取当前的时间,也可以称为网络授时。项目中会使用LwIP SNTP模块从服务器(pool.ntp.org)获取时间

我们使用sntp例程,sntp例程路径为D:\Espressif\frameworks\esp-idf-v5.1.3\examples\protocols\sntp。复制到实验文件夹,路径为D:\esp32c3\sntp,不用修改名字,使用VSCode打开sntp文件夹,程序不需要修改,直接配置好串口、目标芯片,menuconfig就可以下载看结果,menuconfig中,除了把flash大小修改为8MB以外,还需要添加你要连接wifi的名称和密码。

添加好之后,保存关闭,编译下载到开发板,看终端结果

I (10319) example: The current date/time in New York is: Wed Jan 31 06:54:54 2024
I (10319) example: The current date/time in Shanghai is: Wed Jan 31 19:54:54 2024
I (10329) example: Entering deep sleep for 10 seconds

只有一个c文件,点击打开main下面的sntp_example_main.c文件,可以先浏览一下这个c文件,一共有4个函数,分别是app_main()、obtain_time()、time_sync_notification_cb()、print_servers(),app_main()中调用了obtain_time()获取时间函数,obtain_time()函数中又调用了剩下的两个函数,后面两个函数只起到了终端打印信息提示作用,先看app_main函数,最开始的两行代码如下所示:

++boot_count;
ESP_LOGI(TAG, "Boot count: %d", boot_count)

前面我们已经知道,程序每10秒钟会唤醒一次,每次唤醒后,boot_count值会加1,并使用ESP_LOGI把boot_count的值打印到终端。这里用来表示唤醒和重启的不同,如果是重启,boot_count的值永远都是1

time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
if (timeinfo.tm_year < (2016 - 1900)) {ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");obtain_time();// update 'now' variable with current timetime(&now);
}

1.time_t now定义一个64位变量now,使用time(&now)来获取系统当前时间,获取到的是一个64位的数字。

2.struct tm timeinfo定义一个结构体变量timeinfo,使用localtime_r(&now, &timeinfo)把64位的数字时间,各自提取到该结构体中的年月日时分秒等变量中。

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代表一月)- 取值区间为[0,11] */int tm_year;  /* 年份,其值等于实际年份减去1900 */ int tm_wday;  /* 星期–取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */ int tm_yday;  /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,以此类推 */ int tm_isdst; /*夏令时标识符,实行夏令时的时候,为1。不实行夏令时的进候,为0;不了解情况时,为-1。*/
}; 

使用上面提到的变量类型和函数,需要包含c语言的标准库函数<time.h>;

接下来,使用if判断结构体变量timeinfo中的成员tm_year的值。这条语句前面的注释,已经给到一个提示,如果tm_year的值没有设置过,将等于70。也就是说,如果开发板第一次执行这个程序,这个值将是70。如果现在是睡眠唤醒后执行到这里,今年是2024年,tm_year的值就是124,这个值需要加上1900才是当前的实际年份。obtain_time()函数用来从网络上获取当前时间。我们假设obtain_time函数已经执行完,继续看app_main函数。接下来的if条件编译没有在menuconfig中配置这个选项,所以不会执行。条件编译之后的语句如下所示:

char strftime_buf[64];// Set timezone to Eastern Standard Time and print local time
setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf);// Set timezone to China Standard Time
setenv("TZ", "CST-8", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);

上面代码中,先定义一个strftime_buf字符数组,用来存放最后将要打印的字符。

接下来的两个片段,分别设置为纽约时间和上海时间。

setenv()和tzset()设置时区。

strftime()函数根据timeinfo中的成员值把日期时间组合成一串字符,存储到strftime_buf数组中。

最后通过ESP_LOGI打印出strftime_buf数组中的字符串。

接下来的if语句,也不会执行,因为我们没有在menuconfig中设置SNTP_SYNC_MODE_SMOOTH。

最后的3条语句,如下所示:

const int deep_sleep_sec = 10;
ESP_LOGI(TAG, "Entering deep sleep for %d seconds", deep_sleep_sec);
esp_deep_sleep(1000000LL * deep_sleep_sec);

esp_deep_sleep()函数把ESP32-C3设置为睡眠状态,10秒后自动唤醒。

以上就是app_main函数的执行流程。

接下来我们看obtain_time函数,看看时间是怎么获取到的。

obtain_time函数的前3条语句如下所示:

ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK( esp_event_loop_create_default() );

以上3条语句用来做连接wifi之前的准备工作。

之后有一个if条件编译,我们没有设置,也不会执行,这里直接跳过分析。

接下来的一条语句如下所示,用来连接wifi:

ESP_ERROR_CHECK(example_connect());

接下来的if条件编译,也不会执行,会执行它的else条件编译后的语句,用来打印信息。

ESP_LOGI(TAG, "Initializing and starting SNTP");

接下来的if条件编译,当服务器数量大于1才会执行,我们只设置了一个获取时间的服务器,所以也不会执行。会执行else条件编译后的语句:

esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);

这条语句定义了一个esp_sntp_config_t类型变量config,并给该变量配置了默认值。

接下来定义了一个回调函数time_sync_notification_cb。

config.sync_cb = time_sync_notification_cb;     // Note: This is only needed if we want

放到这个函数上面,单击右键选择“转到定义”,函数原型如下所示:

void time_sync_notification_cb(struct timeval *tv)
{ESP_LOGI(TAG, "Notification of a time synchronization event");
}

该函数的目的只是用来打印信息,提示发生时间同步事件。

点击软件最上面的向左的箭头←,回到obtain_time函数中刚才的位置。

接下来的if条件编译也不会执行。

再接下来的语句如下所示,初始化sntp。

esp_netif_sntp_init(&config);

再接下来执行打印服务器名称的函数,如下所示:

print_servers();

把鼠标放到这个函数上面单击右键,选择“转到定义”,函数原型如下所示:

static void print_servers(void)
{ESP_LOGI(TAG, "List of configured NTP servers:");for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){if (esp_sntp_getservername(i)){ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i));} else {// we have either IPv4 or IPv6 address, let's print itchar buff[INET6_ADDRSTRLEN];ip_addr_t const *ip = esp_sntp_getserver(i);if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL)ESP_LOGI(TAG, "server %d: %s", i, buff);}}
}

在我们输出终端打印内容的下面两条就是该函数打印出的内容

I (6439) example: List of configured NTP servers:
I (6449) example: server 0: pool.ntp.org

点击软件最上面的向左的箭头←,回到obtain_time函数中刚才的位置。再接下来的几条语句如下所示:

// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int retry_count = 15;
while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) {ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
}
time(&now);
localtime_r(&now, &timeinfo);

esp_netif_sntp_sync_wait()函数用来从服务器获取时间。间隔2秒获取一次,直到成功获取到时间,retry_count 定义了最多的获取次数。最后的两条语句如下所示:

ESP_ERROR_CHECK( example_disconnect() );
esp_netif_sntp_deinit();

example_disconnect()函数用来断开网络连接。

esp_netif_sntp_deinit()函数用来清除初始化sntp配置。

相关文章:

网络授时笔记

SNTP的全称是Simple Network Time Protocol&#xff0c;意思是简单网络时间协议&#xff0c;用来从网络中获取当前的时间&#xff0c;也可以称为网络授时。项目中会使用LwIP SNTP模块从服务器(pool.ntp.org)获取时间 我们使用sntp例程&#xff0c;sntp例程路径为D:\Espressif\…...

【CSS】HTML页面定位CSS - position 属性 relative 、absolute、fixed 、sticky

目录 relative 相对定位 absolute 绝对定位 fixed 固定定位 sticky 粘性定位 position&#xff1a;relative 、absolute、fixed 、sticky &#xff08;四选一&#xff09; top&#xff1a;距离上面的像素 bottom&#xff1a;距离底部的像素 left&#xff1a;距离左边的像素…...

spark汇总

目录 描述运行模式1. Windows模式代码示例 2. Local模式3. Standalone模式 RDD描述特性RDD创建代码示例&#xff08;并行化创建&#xff09;代码示例&#xff08;读取外部数据&#xff09;代码示例&#xff08;读取目录下的所有文件&#xff09; 算子DAGSparkSQLSparkStreaming…...

【Rust自学】11.5. 在测试中使用Result<T, E>

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.5.1. 测试函数返回值为Result枚举 到目前为止&#xff0c;测试运行失败的原因都是因为触发了panic&#xff0c;但可以导致测试失败的…...

Sping Boot教程之五十四:Spring Boot Kafka 生产者示例

Spring Boot Kafka 生产者示例 Spring Boot 是 Java 编程语言中最流行和使用最多的框架之一。它是一个基于微服务的框架&#xff0c;使用 Spring Boot 制作生产就绪的应用程序只需很少的时间。Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序&#xff0c;您可…...

设计模式-结构型-组合模式

1. 什么是组合模式&#xff1f; 组合模式&#xff08;Composite Pattern&#xff09; 是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。换句话说&#xff0c;组合模式允…...

基于Java的推箱子游戏设计与实现

基于Java的推箱子游戏设计与实现 摘 要 社会在进步&#xff0c;人们生活质量也在日益提高。高强度的压力也接踵而来。社会中急需出现新的有效方式来缓解人们的压力。此次设计符合了社会需求&#xff0c;Java推箱子游戏可以让人们在闲暇之余&#xff0c;体验游戏的乐趣。具有…...

Spark vs Flink分布式数据处理框架的全面对比与应用场景解析

1. 引言 1.1 什么是分布式数据处理框架 随着数据量的快速增长&#xff0c;传统的单机处理方式已经无法满足现代数据处理需求。分布式数据处理框架应运而生&#xff0c;它通过将数据分片分布到多台服务器上并行处理&#xff0c;提高了任务的处理速度和效率。 分布式数据处理框…...

python_excel列表单元格字符合并、填充、复制操作

读取指定sheet页&#xff0c;根据规则合并指定列&#xff0c;填充特定字符&#xff0c;删除多余的列&#xff0c;每行复制四次&#xff0c;最后写入新的文件中。 import pandas as pd""" 读取指定sheet页&#xff0c;根据规则合并指定列&#xff0c;填充特定字…...

nums[:]数组切片

问题&#xff1a;给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 使用代码如下没有办法通过测试示例&#xff0c;必须将最后一行代码改成 nums[:]nums[-k:]nums[:-k]切片形式&#xff1a; 原因&#xff1a;列表的切片操作 …...

【Arthas 】Can not find Arthas under local: /root/.arthas/lib 解决办法

报错 [INFO] JAVA_HOME: /opt/java/openjdk [INFO] arthas-boot version: 4.0.4 [INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER. [1]: 12 org.springframework.boot.loader.JarLauncher 1 [ER…...

录用率23%!CCF推荐-B类,Early Access即可被SCI数据库收录,中美作者占比过半

International Journal of Human-Computer Interaction&#xff08;IJHCI&#xff09;创刊于1989年&#xff0c;由泰勒-弗朗西斯&#xff08;Taylor & Francis, Inc.&#xff09;出版&#xff0c;主要发表关于交互式计算&#xff08;认知和人体工程学&#xff09;、数字无障…...

IP 地址与蜜罐技术

基于IP的地址的蜜罐技术是一种主动防御策略&#xff0c;它能够通过在网络上布置的一些看似正常没问题的IP地址来吸引恶意者的注意&#xff0c;将恶意者引导到预先布置好的伪装的目标之中。 如何实现蜜罐技术 当恶意攻击者在网络中四处扫描&#xff0c;寻找可入侵的目标时&…...

Vue_API文档

Vue API风格 Vue 的组件可以按两种不同的风格书写&#xff1a;选项式 API&#xff08;Vue2&#xff09; 和组合式 API&#xff08;Vue3&#xff09; 大部分的核心概念在这两种风格之间都是通用的。熟悉了一种风格以后&#xff0c;你也能够很快地理解另一种风格 选项式API(Opt…...

WebSocket 设计思路

WebSocket 设计思路 1. 核心结构体 1.1 Manager (管理器) // Manager 负责管理所有WebSocket连接 type Manager struct {clients sync.Map // 存储所有客户端连接broadcast chan []byte // 广播消息通道messages chan Message // 消息处理通道config *config.WebSo…...

Jenkins持续集成与交付安装配置

Jenkins 是一款开源的持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;工具&#xff0c;它主要用于自动化软件的构建、测试和部署流程。为项目持续集成与交付功能强大的应用。下面我们来介绍下它的安装与配置。 环境准备 更新系统组件&#xff08;这…...

ESP32作为Wi-Fi AP模式的测试

一、AP模式的流程 初始化阶段 (Init Phase): 1.1: Main task&#xff08;主任务&#xff09;初始化LwIP&#xff08;轻量级TCP/IP协议栈&#xff09;。 ESP_ERROR_CHECK(esp_netif_init()); 1.2: 创建和初始化Event task&#xff08;事件任务&#xff09;。 ESP_ERROR_CHECK…...

【爬虫】单个网站链接爬取文献数据:标题、摘要、作者等信息

源码链接&#xff1a; https://github.com/Niceeggplant/Single—Site-Crawler.git 一、项目概述 从指定网页中提取文章关键信息的工具。通过输入文章的 URL&#xff0c;程序将自动抓取网页内容 二、技术选型与原理 requests 库&#xff1a;这是 Python 中用于发送 HTTP 请求…...

Android RIL(Radio Interface Layer)全面概述和知识要点(3万字长文)

在Android面试时,懂得越多越深android framework的知识,越为自己加分。 目录 第一章:RIL 概述 1.1 RIL 的定义与作用 1.2 RIL 的发展历程 1.3 RIL 与 Android 系统的关系 第二章:RIL 的架构与工作原理 2.1 RIL 的架构组成 2.2 RIL 的工作原理 2.3 RIL 的接口与协议…...

leetcode_2816. 翻倍以链表形式表示的数字

2816. 翻倍以链表形式表示的数字 - 力扣&#xff08;LeetCode&#xff09; 搜先看到这个题目 链表的节点那么多 已经远超longlong能够表示的范围 那么暴力解题 肯定是不可以的了 我们可以想到 乘法运算中 就是从低位到高位进行计算 刚开始 我想先反转链表 然后在计算 然后在进…...

【论文阅读】MAMBA系列学习

Mamba code&#xff1a;state-spaces/mamba: Mamba SSM architecture paper&#xff1a;https://arxiv.org/abs/2312.00752 背景 研究问题&#xff1a;如何在保持线性时间复杂度的同时&#xff0c;提升序列建模的性能&#xff0c;特别是在处理长序列和密集数据&#xff08;如…...

MySQL教程之:批量使用mysql

在前几节中&#xff0c;您以交互方式使用mysql输入语句并查看结果。您也可以运行mysql批量模式。为此&#xff0c;请将要运行的语句放在文件中&#xff0c;然后告诉mysql从文件中读取其输入&#xff1a; $> mysql < batch-file 如果您在Windows下运行mysql&#xff0c;…...

17_Redis管道技术

Redis管道(Pipeline)技术是一种在 Redis 客户端与服务器之间进行高效数据交互的技术。 1.Redis管道技术介绍 1.1 传统请求响应模式 在传统的请求-响应模式下,客户端每发送一个命令后会等待服务器返回结果,然后再发送下一个命令。这种方式在网络延迟较高的情况下会导致性…...

【LC】3270. 求出数字答案

题目描述&#xff1a; 给你三个 正 整数 num1 &#xff0c;num2 和 num3 。 数字 num1 &#xff0c;num2 和 num3 的数字答案 key 是一个四位数&#xff0c;定义如下&#xff1a; 一开始&#xff0c;如果有数字 少于 四位数&#xff0c;给它补 前导 0 。答案 key 的第 i 个数…...

【redis】ubuntu18安装redis7

在Ubuntu 18下安装Redis7可以通过以下两种方法实现&#xff1a;手动编译安装和使用APT进行安装。 Ubuntu 18系统的环境和版本&#xff1a; $ cat /proc/version Linux version 4.15.0-213-generic (builddlcy02-amd64-079) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)…...

d2j-dex2jar classes.dex 执行报错:not support version 问题解决

这个错误是由于 dex2jar 工具不支持你的 classes.dex 文件的版本导致的。通常情况下&#xff0c;这是因为你尝试使用的 dex2jar 版本不支持 Android 较新的 DEX 文件格式&#xff08;例如 DEX 格式 038 或更新版本&#xff09;。 解决方法 以下是一些解决此问题的步骤&#x…...

智慧城市应急指挥中心系统平台建设方案

建设背景与目标 智慧城市应急指挥中心系统平台的建设&#xff0c;源于对城市管理精细化、智能化的迫切需求。平台旨在通过整合各方资源&#xff0c;实现应急事件的快速响应与高效处置&#xff0c;提升城市安全管理水平。 前端设计与信息采集 前端设计注重立体化、全方位信息…...

QT鼠标、键盘事件

一、鼠标 鼠标点击 mousePressEvent 鼠标释放 mouseReleaseEvent 鼠标移动 mouseMoveEvent 鼠标双击 mouseDoubleClickEvent 鼠标滚轮 QWheelEvent 二、键盘 键盘按下 keyPressEvent 键盘松开keyReleaseEvent 一、鼠标 #include <QMouseEvent> 鼠标点击 mouse…...

Ceph分布式存储集群,不仅仅是一个简单的对象存储解决方案

Ceph 作为 OpenStack 的存储后端 块存储&#xff08;Cinder 后端&#xff09; Ceph 的 RBD&#xff08;RADOS Block Device&#xff09;模块作为 OpenStack Cinder 服务的后端&#xff0c;为虚拟机提供块级别的存储资源。RBD 支持快照、克隆和恢复等功能&#xff0c;能够满足虚…...

DSP+Simulink——点亮LED灯(TMSDSP28379D)超详细

实现功能&#xff1a;DSP28379D-LED灯闪烁 :matlab为2019a :环境建立见之前文章 Matlab2019a安装C2000 Processors超详细过程 matlab官网链接&#xff1a; Getting Started with Embedded Coder Support Package for Texas Instruments C2000 Processors Overview of Creat…...

怎么给网站做logo/舆情监测

平均真实波幅(ATR)指标在仓位管理中的用途十分广泛。其在现代技术分析和资金管理方面&#xff0c;作用也不容忽视。 要计算这个平均真实波幅(ATR)&#xff0c;就要先会计算真实波幅。真实波幅是以下三个值中的最大者&#xff1a; 1) 当前交易日的最高价与最低价间的波幅 2) …...

张楚岚/seo算法优化

源码地址&#xff1a;springboot-integration 如果你觉得解决了你使用的需求&#xff0c;欢迎fork|star。转载于:https://www.cnblogs.com/geekdc/p/9253197.html...

河间哪里有做网站的/广州最新疫情通报

1 问题 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a;一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 示例 1: 给定二叉树 [3,9,20,null,null,15,7] 返回 true 。 示例 2: 给定二叉树…...

网站建设项目的预表/搜索引擎优化的方式有哪些

终于找到了。...

网站logo显示/青岛谷歌优化

本文从各种角度对几个常用的 JavaScript 表格库进行比较&#xff0c;一目了然。 Feature DataTables JqGrid Slickgrid dhtmlxGrid Flexigrid ExtJs LicenseGPL v2 license or a BSD (3-point) licenseLGPLMITGrid License $449MITLicense from $600Show/Hide c…...

制作网站生成器/世界新闻最新消息

动态规划的题型中要抽象出递归相类似的表达式。动态规划&#xff0c;给我的感觉就是一个存表和查表操作&#xff0c;而且这两个操作在物理和逻辑上是连续的。 Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. Maybe you …...