NTP
一、NTP 基本概念
网络时间协议 NTP(Network Time Protocol)是 TCP/IP 协议族里面的一个应用层协议,用来使客户端和服务器之间进行时钟同步,提供高精准度的时间校正。NTP 服务器从权威时钟源(例如原子钟、GPS)接收精确的协调世界时 UTC,客户端再从服务器请求和接收时间。
对于 Air780E, 移动/电信卡, 通常会下发基站时间, 同步时间并不是必要的, 而联通卡通常不会下发, 就需要 sntp 了,很多场景中,由于业务需要,模块需要保持正确的系统时钟,才能正常工作。
二、演示功能概述
本文教你怎么使用 AT 命令,通过模组连接 NTP 服务器进行时间同步,为了 NTP 功能的整体独立性,这里将完整的记录从开机到获取到网络时间的全部步骤。
三、准备硬件环境
工欲善其事,必先利其器。在正式介绍本功能示例之前,需要先准备好以下硬件环境。
3.1 Air8101 开发板
本文使用 Air8101 开发板,如下图所示:
点击链接购买:Air8101 开发板淘宝购买链接 ;
此开发板的详细使用说明参考:Air8101 产品手册 中的 << 开发板 Core_Air8101 使用说明 VX.X.X.pdf>>。
3.2 WIFI 热点
可以使用场地或者手机 WIFI 热点,确保 WIFI 可以正常上网。
3.3 PC 电脑
准备一台电脑,其中电脑需要具备 USB-A 接口,需要安装好 CH340 驱动。
注意:电脑有 USB 口,并且可以正常上网!!!
3.4 数据通信线
准备一根 USB TypeC 数据线,此数据线的作用是,连接 Air8101 开发板和 PC 电脑,用于更新固件,下载脚本以及打印日志。
3.5 组装硬件环境
连接 Beken 串口小板和电脑 USB 接口,此时串口小板的电源指示灯亮起。将串口小板插在 BK7258 EVB 的
DL_UART0 排针接口处,将开关打开提供供电,如图。
四、准备软件环境
工欲善其事,必先利其器。在正式介绍本功能示例之前,需要先准备好以下软件环境。
4.1 Luatools 工具
要想烧录 Luat 脚本到开发板中,需要用到合宙的强大的调试工具:Luatools;
详细使用说明参考:Luatools 工具使用说明 。
4.2 底层固件
访问:Air8101 固件版本 ,找到最新版本的固件即可,下载的固件如下图所示。
打开 Luatools 工具,按照下图进行固件下载。
五、编写 Luat 脚本
5.1 总体设计说明 本demo将演示使用NTP授时服务来同步时间。使用luat socket相关API,和系统服务API完成系统默认ntp服务同步时间,以及自定义地址同步时间。
源码地址:https://gitee.com/openLuat/LuatOS-Air8101.git 完整源码
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "sntpdemo"
VERSION = "1.0.0"
-- sys库是标配
_G.sys = require("sys")
-- 统一联网函数
sys.taskInit(function()
-----------------------------
-- 统一联网函数, 可自行删减
----------------------------
if wlan and wlan.connect then
-- wifi 联网, Air8101系列均支持,ssid、password修改为自己的wifi参数
local ssid = "momowifi"
local password = "abc123456"
log.info("wifi", ssid, password)
wlan.init()
wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
device_id = wlan.getMac()
wlan.connect(ssid, password, 1)
else
-- 其他不认识的bsp, 循环提示一下吧
while 1 do
sys.wait(1000)
log.info("bsp", "本bsp可能未适配网络层, 请查证")
end
end
-- 默认都等到联网成功
sys.waitUntil("IP_READY")
sys.publish("net_ready", device_id)
end)
sys.taskInit(function()
-- 等待联网
local ret, device_id = sys.waitUntil("net_ready")
sys.wait(1000)
-- sntp内置了几个常用的ntp服务器, 也支持自选服务器
while 1 do
-- 使用内置的ntp服务器地址, 包括阿里ntp
log.info("开始执行SNTP")
socket.sntp()
-- 自定义ntp地址
-- socket.sntp("ntp.aliyun.com")
-- socket.sntp({"baidu.com", "abc.com", "ntp.air32.cn"})
-- 通常只需要几百毫秒就能成功
local ret = sys.waitUntil("NTP_UPDATE", 5000)
if ret then
-- 以下是获取/打印时间的演示,注意时区问题
log.info("sntp", "时间同步成功", "本地时间", os.date())
log.info("sntp", "时间同步成功", "UTC时间", os.date("!%c"))
log.info("sntp", "时间同步成功", "RTC时钟(UTC时间)", json.encode(rtc.get()))
log.info("sntp", "时间同步成功", "本地时间戳", os.time())
local t = os.date("*t")
log.info("sntp", "时间同步成功", "本地时间os.date() json格式", json.encode(t))
log.info("sntp", "时间同步成功", "本地时间os.date(os.time())", os.time(t))
-- 正常使用, 一小时一次, 已经足够了, 甚至1天一次也可以
-- sys.wait(3600000)
-- 这里为了演示, 用5秒一次
sys.wait(5000)
else
log.info("sntp", "时间同步失败")
sys.wait(60000) -- 1分钟后重试
end
-- 注意, 至少成功完成2次sntp,该时间戳才比较准确
-- 如果仅完成了一次sntp, 时间戳比标准时间会慢一个网络延时的时长(10~500ms)不等
if socket.ntptm then
local tm = socket.ntptm()
log.info("tm数据", json.encode(tm))
log.info("时间戳", string.format("%u.%03d", tm.tsec, tm.tms))
sys.wait(5000)
end
end
end)
sys.subscribe("NTP_ERROR", function()
log.info("socket", "sntp error")
-- socket.sntp()
end)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
5.1 引入 sys 库
-- sys库是标配
_G.sys = require("sys")
5.2 建立协程,连接 wifi,如果成功则发布"net_ready"消息。
-- 统一联网函数
sys.taskInit(function()
local device_id = mcu.unique_id():toHex()
-----------------------------
-- 统一联网函数, 可自行删减
----------------------------
if wlan and wlan.connect then
-- wifi 联网, ESP32系列均支持
local ssid = "luatos1234"
local password = "12341234"
log.info("wifi", ssid, password)
-- TODO 改成自动配网
-- LED = gpio.setup(12, 0, gpio.PULLUP)
wlan.init()
wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
device_id = wlan.getMac()
wlan.connect(ssid, password, 1)
while 1 do
sys.wait(1000)
log.info("bsp", "本bsp可能未适配网络层, 请查证")
end
end
-- 默认都等到联网成功
sys.waitUntil("IP_READY")
sys.publish("net_ready", device_id)
end)
5.3 建立协程,连接 wifi,等待连接 wifi 协程发布的"net_ready"消息。
local ret, device_id = sys.waitUntil("net_ready")
5.4 执行 sntp 服务,通常只需要几百毫秒就能成功
socket.sntp()
5.5 如果使用自定义 ntp 地址可以参考如下代码,服务器地址改为自己的就行
-- 自定义ntp地址
-- socket.sntp("ntp.aliyun.com")
-- socket.sntp({"baidu.com", "abc.com", "ntp.air32.cn"})
5.6 接收到“NTP_UPDATE”消息,代表已经成功同步时间,打印时间信息
local ret = sys.waitUntil("NTP_UPDATE", 5000)
if ret then
-- 以下是获取/打印时间的演示,注意时区问题
log.info("sntp", "时间同步成功", "本地时间", os.date())
log.info("sntp", "时间同步成功", "UTC时间", os.date("!%c"))
log.info("sntp", "时间同步成功", "RTC时钟(UTC时间)", json.encode(rtc.get()))
-- os.time(rtc.get()) 需要 2023.07.21 之后的版本, 因为月份的命名差异mon/month
-- log.info("sntp", "时间同步成功", "utc时间戳", os.time(rtc.get()))
log.info("sntp", "时间同步成功", "本地时间戳", os.time())
local t = os.date("*t")
log.info("sntp", "时间同步成功", "本地时间os.date() json格式", json.encode(t))
log.info("sntp", "时间同步成功", "本地时间os.date(os.time())", os.time(t))
-- log.info("sntp", "时间同步成功", "本地时间", os.time())
-- 正常使用, 一小时一次, 已经足够了, 甚至1天一次也可以
-- sys.wait(3600000)
-- 这里为了演示, 用5秒一次
sys.wait(5000)
5.7 如果同步失败,则打印“时间同步失败”,一分钟后进行重新同步
log.info("sntp", "时间同步失败")
sys.wait(60000) -- 1分钟后重试
5.8 脚本编写完成后,保存到本地为 main.lua 以便下一步验证。
六、下载验证
主动断开 WIFI 热点,开发板断开连接
重新打开 WIFI 热点,开发板自动重连 WIFI 成功后,重新同步时间成功
我们使用自定义 ntp 服务器地址,(socket.sntp({"baidu.com", "abc.com", "ntp.air32.cn"}))一次设置了三个 ntp 服务器地址。
socket.sntp({"baidu.com", "abc.com", "ntp.air32.cn"})
如果当前地址不可用,则自动尝试下一个地址;具体制定结果如下图所示:
七、常见问题 Q&A
7.1 开发板无法同步时间?
1. 确保 Luat 代码逻辑无问题。
2. 检查 Luat 脚本中 WIFI ssid password 参数是否与当前 wifi 热点一致。
3.开发板智能连接 2.4G 频段,请检查当前 WIFI 是否为 2.4G 频段。
3. 检查 ntp 服务器是否可用。
给读者的话
本篇文章由
Murphy
开发;本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;
请登录合宙技术交流论坛,点击文档找错赢奖金-Air8101-LuatOS-软件指南-网络协议大全-NTP;
用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;
我们会迅速核实并且修改文档;
同时也会为您累计找错积分,您还可能赢取月度找错奖金!