写点什么

ESP8266 调用 NTP 服务器进行时间校准

作者:DS小龙哥
  • 2023-06-09
    重庆
  • 本文字数:2934 字

    阅读完需:约 10 分钟

一、背景知识

【1】什么是 NTP 服务器?

NTP 是网络时间协议(Network Time Protocol,简称 NTP),是一种用于同步计算机时间的协议。NTP 服务器指的是提供 NTP 服务的计算机或设备。NTP 服务器的主要功能是保证网络上的所有设备的时间同步,以确保各个设备相互之间的时间协调一致。NTP 服务器通常连接到具有高度精确时间源的设备,例如:GPS 接收器或原子钟,以确保提供准确如一的时间。网络上的计算机可以通过连接到 NTP 服务器来同步其时间,并确保它们在同一时刻进行操作。



目前有许多可以使用的 NTP 服务器,以下是一些常用的 NTP 服务器列表:

1. cn.ntp.org.cn2. ntp.sjtu.edu.cn3. ntp.linux.org.cn4. time.nist.gov.cn5. ntp.aliyun.com6. ntp.api.bz7. ntp1.aliyun.com8. time1.cloud.tencent.com9. pool.ntp.org.cn
复制代码

【2】RTC 实时时钟是什么?

RTC (Real-Time Clock)实时时钟,是指一种专门用于记忆日期、时间的计时芯片或模块。一般包括一个时钟芯片、一块石英晶体、一块温度补偿电路、电源管理电路等组成。RTC 可以精确地记录日期和时间,即使是在断电等异常情况下,也能保持记录的时间长达数年。常常用于嵌入式系统、数据采集设备等领域,是一种至关重要的设备。在某些系统应用中,RTC 也会成为其他设备的时钟源,如单片机或微控制器单位等。


RTC 的时间精度通常为 ppm 级别,即每百万分之一,能够满足大多数实时应用场景的要求。为了提高 RTC 的稳定度和精度,许多 RTC 都带有自动校正功能,可以自动从外部时钟源或 NTP 服务器中获取准确的时间,并进行校正。同时,许多 RTC 还会集成电源管理功能,支持低功耗模式以延长电池寿命。

二、ESP8266 获取网络时间

要通过 ESP8266 联网并获取网络时间,需要执行以下步骤:


  1. 在 STM32F103ZET6 上配置 UART 串口以与 ESP8266 进行通信。

  2. 使用 AT 指令将 ESP8266 连接到 Wi-Fi 网络。可以使用以下指令:

AT+CWJAP="SSID","password"
复制代码

其中,替换 "SSID" 为自己的 Wi-Fi 网络名称,"password" 是 Wi-Fi 密码。

使用 AT 指令连接到 NTP 服务器并获取时间。可以使用以下指令:

AT+CIPSNTPCFG=0,1,"pool.ntp.org"AT+CIPSNTPTIME?
复制代码

这将连接到 ntp 服务器并检索当前的 UTC 时间。

  1. 将 ESP8266 返回的 UTC 时间转换为本地时间。需要知道当前所在的时区,并对 UTC 进行适当的调整。

  2. 将本地时间设置为 STM32F103ZET6 上的 RTC 实时时钟。


下面是实现的代码:


#include <stdio.h>#include "stm32f10x.h"
// UART配置void uart_init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);}
// 发送AT指令并等待响应int send_at_command(char* command, char* response, uint32_t timeout) { // 发送命令 USART_SendData(USART1, (uint8_t*)command, strlen(command)); // 等待响应 uint32_t start_time = HAL_GetTick(); while ((HAL_GetTick() - start_time) < timeout) { if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) { char c = USART_ReceiveData(USART1); // 检查是否收到了预期的响应 if (strstr(response, c) != NULL) { return 0; // 成功 } } } return -1; // 超时或没有收到预期的响应}
// 连接ESP8266到Wi-Fivoid connect_to_wifi() { char command[50]; char response[100]; // 设置Wi-Fi SSID和密码 sprintf(command, "AT+CWJAP=\"%s\",\"%s\"\r\n", "YourSSID", "YourPassword"); send_at_command(command, "OK", 5000);}
// 连接到NTP服务器并获取时间int get_ntp_time(uint32_t* time) { char response[100]; // 配置SNTP客户端 send_at_command("AT+CIPSNTPCFG=0,1,\"pool.ntp.org\"\r\n", "OK", 5000); // 获取时间 send_at_command("AT+CIPSNTPTIME?\r\n", response, 5000); // 解析响应并提取时间戳 char* token = strtok(response, ","); uint32_t timestamp = atoi(token); *time = timestamp - 2208988800UL; // 转换为Unix时间戳 return 0;}
// 将时间设置到RTCvoid set_rtc_time(uint32_t time) { // 启用PWR和BKP外设时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); // 解锁备份寄存器区域 PWR_BackupAccessCmd(ENABLE); // 配置RTC RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128); // RTC时钟源为HSE/128 RCC_RTCCLKCmd(ENABLE); // 启用RTC时钟 RTC_InitTypeDef RTC_InitStructure; // 配置RTC时钟 RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24; RTC_InitStructure.RTC_AsynchPrediv = 127; RTC_InitStructure.RTC_SynchPrediv = 255; RTC_Init(&RTC_InitStructure);
// 设置RTC时间 RTC_TimeTypeDef RTC_TimeStruct; RTC_DateTypeDef RTC_DateStruct;
// 将Unix时间戳转换为RTC时间和日期 uint32_t days = time / 86400; uint32_t seconds = time % 86400; uint32_t hours = seconds / 3600; uint32_t minutes = (seconds % 3600) / 60; uint32_t secs = (seconds % 3600) % 60; uint32_t year = 1970; uint32_t month = 1; while (days > 365) { if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { days -= 366; } else { days -= 365; } year++; } while (days > 0) { if (month == 2) { if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { if (days > 29) { days -= 29; } else { break; } } else { if (days > 28) { days -= 28; } else { break; } } } else if (month == 4 || month == 6 || month == 9 || month == 11) { if (days > 30) { days -= 30; } else { break; } } else { if (days > 31) { days -= 31; } else { break; } } month++; if (month > 12) { month = 1; year++; } }
RTC_TimeStruct.RTC_Hours = hours; RTC_TimeStruct.RTC_Minutes = minutes; RTC_TimeStruct.RTC_Seconds = secs; RTC_DateStruct.RTC_Date = days; RTC_DateStruct.RTC_Month = month; RTC_DateStruct.RTC_Year = year - 2000;
// 设置RTC时间和日期 RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct); RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct); }
int main() { // 初始化UART串口 uart_init();
// 连接ESP8266到Wi-Fi connect_to_wifi();
// 获取NTP时间 uint32_t ntp_time; get_ntp_time(&ntp_time);
// 将时间设置到 RTC set_rtc_time(ntp_time);
while (1) { // 做其他的事情... } }
复制代码


发布于: 1 小时前阅读数: 3
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022-01-06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
ESP8266调用NTP服务器进行时间校准_6 月优质更文活动_DS小龙哥_InfoQ写作社区