之前做的那些1602时钟虽然使用了DS3231来走时,误差不算太大, 但始终会有点误差。加上上次因为DS3231模块设计问题,导致给纽扣电池的电压达到了5V,最终把电池给弄炸了,威力还不小,让我有点害怕,所以决定做一个基于WiFi自动校时的程序。
上网找了一会,没有现成的方案和代码,但是找到了一个WiFi对时的程序,参见:https://github.com/YFROBOT-TM/YFRobot-NTPClock_OneNet,我的1602时钟也是基于这个WiFi授时改动来的。
硬件连接:
这个版本用的1602是那种带按键的模块式的,直接插上板子即可。
代码:
#include <ESP8266WiFi.h> #include <Time.h> #include <Timezone.h> #include "NTP.h" #include <LiquidCrystal.h> // Set your WiFi login credentials #define WIFI_SSID "XXX" // 使用时请修改为当前你的 wifi ssid #define WIFI_PASS "XXX" // 使用时请修改为当前你的 wifi 密码 #define ledPin 14 // 定义ledPin连接到GPIO14 LiquidCrystal lcd(0, 2, 4, 14, 12, 13); //年 byte Nian[8] = {0b01000,0b01111,0b10010, 0b01111, 0b01010, 0b11111, 0b00010, 0b00010}; //月 byte Yue[8] = {0b01111, 0b01001, 0b01111, 0b01001, 0b01111, 0b01001, 0b10011, 0b00001}; //日 byte Ri[8] = {0b01111, 0b01001, 0b01001, 0b01111, 0b01001, 0b01001, 0b01111, 0b00000}; // This clock is in the Mountain Time Zone // Change this for your timezone // 北京时间时区 #define STD_TIMEZONE_OFFSET +8 // Standard Time offset (-7 is mountain time) // *************************************************************** // TimeZone and Daylight Savings Time Rules // *************************************************************** // Define daylight savings time rules for the China TimeChangeRule mySTD = {"", First, Sun, Jan, 0, STD_TIMEZONE_OFFSET * 60}; Timezone myTZ(mySTD, mySTD); WiFiClient client; // This function is called once a second void updateDisplay(void) { TimeChangeRule *tcr; // Pointer to the time change rule // Read the current UTC time from the NTP provider time_t utc = now(); // Convert to local time taking DST into consideration time_t localTime = myTZ.toLocal(utc, &tcr); // Map time to pixel positions int weekdays= weekday(localTime); int days = day(localTime); int months = month(localTime); int years = year(localTime); int seconds = second(localTime); int minutes = minute(localTime); int hours = hour(localTime) ; //12 hour format use : hourFormat12(localTime) isPM()/isAM() Serial.println(""); Serial.print("Current local time:"); Serial.print(days); Serial.print("/"); Serial.print(months); Serial.print("/"); Serial.print(years); Serial.print(" - "); Serial.print(hours); Serial.print(":"); Serial.print(minutes); Serial.print(":"); Serial.print(seconds); Serial.print(" - "); Serial.print(dayStr(weekdays)); Serial.println(""); lcd.clear(); lcd.setCursor(0,0); lcd.print("Time:"); if(hours<10) { lcd.print("0"); } lcd.print(hours); lcd.print(":"); if(minutes<10) { lcd.print("0"); } lcd.print(minutes); lcd.print(":"); if(seconds<10) { lcd.print("0"); } lcd.print(seconds); lcd.print(" W"); printWeek(weekdays); lcd.setCursor(0,1); lcd.print("Date:"); lcd.print(years); lcd.write(byte(0)); if(months<10) { lcd.print("0"); } lcd.print(months); lcd.write(byte(1)); if(days<10) { lcd.print("0"); } lcd.print(days); lcd.write(byte(2)); } void setup() { Serial.begin(115200); pinMode(ledPin, OUTPUT); delay(10); lcd.begin(16, 2); lcd.createChar(0, Nian); lcd.createChar(1, Yue); lcd.createChar(2, Ri); // We start by connecting to a WiFi network initNTP(WIFI_SSID, WIFI_PASS); } // Previous seconds value time_t previousSecond = 0; void loop() { // Update the display only if time has changed if (timeStatus() != timeNotSet) { if (second() != previousSecond) { previousSecond = second(); // Update the display updateDisplay(); } } delay(1000); } void printWeek(int week) { switch(week) { case 1: lcd.print("7");break; case 2: lcd.print("1");break; case 3: lcd.print("2");break; case 4: lcd.print("3");break; case 5: lcd.print("4");break; case 6: lcd.print("5");break; case 7: lcd.print("6");break; default: lcd.print("E");break; } }NTP.h 文件:
#ifndef NTP_H #define NTP_H #include <Arduino.h> #include <ESP8266WiFi.h> #include <TimeLib.h> #include <WiFiUdp.h> #define LOCALPORT 5000 // Local port to listen for UDP packets #define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message // A UDP instance to let us send and receive packets over UDP WiFiUDP udp; byte packetBuffer[NTP_PACKET_SIZE]; // Buffer to hold incoming and outgoing packets // Don't hardwire the IP address or we won't get the benefits of the time server pool. const char *ntpServerName ;//= "time.windows.com";//"1.cn.pool.ntp.org"; IPAddress timeServerIP(182,92,12,11); //ONENET -- NTP // Send an NTP request to the time server at the given address unsigned long sendNTPpacket(IPAddress& address) { // Set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // All NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(address, 123); // NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); } // NTP Time Provider Code time_t getNTPTime() { int attempts = 10; // Try multiple attempts to return the NTP time while (attempts--) { // Get a server from the pool if(ntpServerName != NULL){ WiFi.hostByName(ntpServerName, timeServerIP); } Serial.printf("Time server IP address: "); Serial.println(timeServerIP); while (udp.parsePacket() > 0); // Discard any previously received packets Serial.println("Transmitted NTP Request"); sendNTPpacket(timeServerIP); uint32_t beginWait = millis(); while (millis() - beginWait < 1500) { int size = udp.parsePacket(); if (size >= NTP_PACKET_SIZE) { Serial.println("Received NTP Response"); udp.read(packetBuffer, NTP_PACKET_SIZE); // Read packet into the buffer unsigned long secsSince1900; // Convert four bytes starting at location 40 to a long integer secsSince1900 = (unsigned long) packetBuffer[40] << 24; secsSince1900 |= (unsigned long) packetBuffer[41] << 16; secsSince1900 |= (unsigned long) packetBuffer[42] << 8; secsSince1900 |= (unsigned long) packetBuffer[43]; Serial.println("Got the time"); return secsSince1900 - 2208988800UL; } delay(10); } Serial.println("Retrying NTP request"); delay(4000); } Serial.println("No NTP Response"); return 0; } // Login to WiFi network and assign the time sync provider void initNTP(const char *ssid, const char *password) { // Set station mode WiFi.mode(WIFI_STA); //set work mode: WIFI_AP /WIFI_STA /WIFI_AP_STA // Start by connecting to a WiFi network WiFi.begin(ssid, password); int i = 0; while ((WiFi.status() != WL_CONNECTED) && (i++ < 30)) { delay(500); Serial.printf("."); } if (i == 31) { Serial.printf("\nCould not connect to: %s\n", ssid); return; } Serial.printf("\nConnected to: %s\n", ssid); delay(500); // Login suceeded so set UDP local port udp.begin(LOCALPORT); // Set the time provider to NTP setSyncProvider(getNTPTime); } #endif效果图:
https://github.com/PaulStoffregen/Time
https://github.com/JChristensen/Timezone