【得捷Follow me第4期】W5500-EVB-Pico PIO通过NTP服务器获取网络时间
[复制链接]
本帖最后由 wo4fisher 于 2024-3-5 13:42 编辑
1. 可用的NTP服务器测试
使用如下的命令可以测试NTP授时服务器是否可用
- w32tm /stripchart /computer:ntp_server_address
ntp_server_address 可以是服务器主机名称,也可以是IP地址。
可用的NTP服务器地址:
国家授时中心 NTP 服务器 ntp.ntsc.ac.cn 114.118.7.161 114.118.7.163
中国 NTP 快速授时服务 cn.ntp.org.cn 223.113.97.98 119.29.26.206
教育网 edu.ntp.org.cn 202.118.1.130 202.118.1.81
2. 新建基本工程并添加Ethernet3库文件到工程lib目录
3. 代码编辑
-
- #include <Arduino.h>
- #include <SPI.h>
- #include <Ethernet3.h>
- #include <EthernetUdp3.h>
-
- #define FOURYEARDAY (365 + 365 + 365 + 366)
- #define TIMEZONE (8)
-
- typedef struct rtc_time_struct
- {
- uint16_t ui8Year;
- uint8_t ui8Month;
- uint8_t ui8DayOfMonth;
- uint8_t ui8Week;
- uint8_t ui8Hour;
- uint8_t ui8Minute;
- uint8_t ui8Second;
-
- } rtc_time_t;
-
- static uint8_t month_day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- static uint8_t Leap_month_day[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-
-
-
- byte mac[] = {
- 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
-
- unsigned int localPort = 8888;
-
- const char timeServer[] = "ntp.ntsc.ac.cn";
-
- const int NTP_PACKET_SIZE = 48;
-
- byte packetBuffer[NTP_PACKET_SIZE];
-
-
- EthernetUDP Udp;
-
-
- uint8_t isLeapYear(uint16_t year);
-
- void covUnixTimeStp2Beijing(uint32_t unixTime, rtc_time_t *tempBeijing);
-
- void setup()
- {
-
- Serial.begin(115200);
- while (!Serial)
- {
- ;
- }
-
- Ethernet.setCsPin(17);
- Ethernet.setRstPin(20);
-
-
- if (Ethernet.begin(mac) == 0)
- {
- Serial.println("Failed to configure Ethernet using DHCP");
-
- for (;;)
- ;
- }
- Udp.begin(localPort);
- }
-
- void sendNTPpacket(const char *address);
-
- void loop()
- {
- sendNTPpacket(timeServer);
-
-
- delay(1000);
- if (Udp.parsePacket())
- {
-
- Udp.read(packetBuffer, NTP_PACKET_SIZE);
-
-
-
-
- unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
- unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
-
-
- unsigned long secsSince1900 = highWord << 16 | lowWord;
- Serial.print("Seconds since Jan 1 1900 = ");
- Serial.println(secsSince1900);
-
-
- Serial.print("Unix time = ");
-
- const unsigned long seventyYears = 2208988800UL;
-
- unsigned long epoch = secsSince1900 - seventyYears;
-
- Serial.println(epoch);
-
-
- Serial.print("The UTC time is ");
-
- rtc_time_t tempBeijing2;
- char dtBuf[30] = {0};
- covUnixTimeStp2Beijing(epoch, &tempBeijing2);
- sprintf(dtBuf, "%d/%02d/%02d-%02d:%02d:%02d",
- tempBeijing2.ui8Year, tempBeijing2.ui8Month, tempBeijing2.ui8DayOfMonth,
- tempBeijing2.ui8Hour, tempBeijing2.ui8Minute, tempBeijing2.ui8Second);
- Serial.println(dtBuf);
- }
-
- delay(6000);
- Ethernet.maintain();
- }
-
-
- void sendNTPpacket(const char *address)
- {
-
- memset(packetBuffer, 0, NTP_PACKET_SIZE);
-
-
- packetBuffer[0] = 0b11100011;
- packetBuffer[1] = 0;
- packetBuffer[2] = 6;
- packetBuffer[3] = 0xEC;
-
- packetBuffer[12] = 49;
- packetBuffer[13] = 0x4E;
- packetBuffer[14] = 49;
- packetBuffer[15] = 52;
-
-
-
- Udp.beginPacket(address, 123);
- Udp.write(packetBuffer, NTP_PACKET_SIZE);
- Udp.endPacket();
- }
-
-
-
-
-
- uint8_t isLeapYear(uint16_t year)
- {
- uint8_t res = 0;
-
- if (year % 4 == 0)
- {
- if ((year % 100 == 0) && (year % 400 != 0))
- {
- res = 0;
- }
- else
- {
- res = 1;
- }
- }
- return res;
- }
-
-
-
-
-
-
- void covUnixTimeStp2Beijing(uint32_t unixTime, rtc_time_t *tempBeijing)
- {
- uint32_t totleDayNum = 0, totleSecNum = 0;
- uint16_t remainDayofYear = 0, tempYear = 0;
- uint8_t *pr = NULL;
-
- totleDayNum = unixTime / (24 * 60 * 60);
- totleSecNum = unixTime % (24 * 60 * 60);
-
- memset(tempBeijing, 0x00, sizeof(rtc_time_t));
-
-
- tempBeijing->ui8Hour = totleSecNum / 3600;
- tempBeijing->ui8Minute = (totleSecNum % 3600) / 60;
- tempBeijing->ui8Second = (totleSecNum % 3600) % 60;
-
-
- tempBeijing->ui8Hour += TIMEZONE;
- if (tempBeijing->ui8Hour > 23)
- {
-
- tempBeijing->ui8Hour -= 24;
- remainDayofYear++;
- }
-
-
- tempBeijing->ui8Year = 1970 + (totleDayNum / FOURYEARDAY) * 4;
- remainDayofYear += totleDayNum % FOURYEARDAY;
-
-
- tempYear = isLeapYear(tempBeijing->ui8Year) ? 366 : 365;
- while (remainDayofYear >= tempYear)
- {
- tempBeijing->ui8Year++;
- remainDayofYear -= tempYear;
- tempYear = isLeapYear(tempBeijing->ui8Year) ? 366 : 365;
- }
-
-
- pr = isLeapYear(tempBeijing->ui8Year) ? Leap_month_day : month_day;
- remainDayofYear++;
- while (remainDayofYear > *(pr + tempBeijing->ui8Month))
- {
- remainDayofYear -= *(pr + tempBeijing->ui8Month);
- tempBeijing->ui8Month++;
- }
-
- tempBeijing->ui8Month++;
- tempBeijing->ui8DayOfMonth = remainDayofYear;
-
- }
-
主要步骤:
第一步:定义mac地址、本地端口、ntp服务器,并且定义UDP客户端EthernetUDP实例。
第二步:在初始化函数setup中使用Ethernet.begin函数初始化W5500网络参数,然后启动udp客户端: Udp.begin(localPort)。
第三步:在Loop函数中 首先向NTP服务器发送请求包sendNTPpacket(),然后解析接收到的应答数据包,并且分别显示自1900年开始的秒数、UNIX时间(即从1970年1月1日开始的秒数)和NTC时间的时分秒。
备注:中间有增加unix时间戳计算当前日期和时间的函数,没有计算星期几。
结果,NTP时间和右下角显示时间一致
|