跳转至

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

用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;

我们会迅速核实并且修改文档;

同时也会为您累计找错积分,您还可能赢取月度找错奖金!