# 使用 ITEAD 的 WeeESP8266 函式庫進行網路對時
我把其中的 ntpupdate() 函式複製到以 WeeESP8266 函式庫為基礎的 wifi 設定架構中, 完整程式如下 :
#include <SoftwareSerial.h>
#include "ESP8266.h"
//-----application include & def listed HERE-----
//NTP 伺服器 IP 82.209.243.241, 91.226.136.136, 192.5.41.40
#define HOST_NAME "91.226.136.136"
#define HOST_PORT 123 //NTP 埠號
//system use please do not edit
SoftwareSerial esp8266(7,8); //(D7:RX, D8:TX)
ESP8266 wifi(esp8266); //create wifi obj
const int SW_PIN=4; //Pin to switch configuration or working mode
int mode; //store current mode(LOW=configuration, HIGH=working)
void setup() {
//system use please do not edit
Serial.begin(9600);
wifi.restart(); //reset ESP8266
Serial.print(F("Firmware version ... "));
Serial.println(wifi.getVersion());
pinMode(SW_PIN, INPUT);
mode=digitalRead(SW_PIN);
boolean ok=true;
if (mode==LOW) { //setup mode : for wifi configuration
ok &= wifi.setOprToStationSoftAP();
ok &= wifi.enableMUX();
ok &= wifi.startTCPServer(80);
if (ok) {Serial.println(F("Setup mode ... OK"));}
}
else { //working mode : for running application
ok &= wifi.setOprToStation();
if (ok) {Serial.println(F("Working mode ... OK"));}
}
delay(5000);
Serial.print(F("IP ... "));
Serial.println(wifi.getLocalIP());
//-----application setup codes listed HERE-----
}
void loop() {
if (mode==LOW) {setupWifi();}
else { //-----application loop codes listed bellow-----
//if (esp8266.available()) {Serial.write(esp8266.read());}
//if (Serial.available()) {esp8266.write(Serial.read());}
ntpupdate(); //呼叫 NTP 對時函數
delay(10000);
}
}
void setupWifi() {
uint8_t buffer[256]={0}; //init buffer
uint8_t mux_id; //TCP connection id (0~4)
uint32_t len=wifi.recv(&mux_id, buffer, sizeof(buffer), 2000); //get response
if (len > 0) { //data received
String path="";
for (uint32_t i=0; i<len; i++) {
if (!path.endsWith(" HTTP/")) {path.concat((char)buffer[i]);}
else {break;}
}
path=path.substring(path.indexOf("/") + 1, path.indexOf(" HTTP/"));
Serial.println(path); //eg:update/?ssid=EDIMAX-tony&pwd=1234567890
if (path.startsWith("update")) { //update ssid & pwd
String ssid=path.substring(path.indexOf("?") + 6, path.indexOf("&"));
String pwd=path.substring(path.indexOf("&") + 5);
Serial.println(ssid);
Serial.println(pwd);
if (wifi.joinAP(ssid, pwd)) {
uint8_t data[]="<html>Wifi setup OK!</html>";
wifi.send(mux_id, data, sizeof(data));
}
else {
uint8_t data[]="<html>Wifi setup failed!</html>";
wifi.send(mux_id, data, sizeof(data));
}
}
else { //show setup page
uint8_t data[]="<html><form method=get action='/update/'>"
"SSID <input name=ssid type=text><br>"
"PWD <input name=pwd type=text> "
"<input type=submit value=Connect></form></html>";
wifi.send(mux_id, data, sizeof(data));
}
//Serial.println(wifi.releaseTCP(mux_id));
}
Serial.println(wifi.getIPStatus().c_str());
}
void ntpupdate() {
uint8_t buffer[128]={0}; //儲存 NTP 回應字元的緩衝器
if (wifi.registerUDP(HOST_NAME, HOST_PORT)) { //註冊 UDP (CIPSTART)
Serial.print("register udp ok\r\n");
}
else {Serial.print("register udp err\r\n");}
//定義兩個程式記憶體變數 (Flash) 儲存要傳送的 UDP 資料 (0~3, 12~15)
static const char PROGMEM timeReqA[]={227,0,6,236}; //E3,00,06,EC (前 4 Bytes)
static const char PROGMEM timeReqB[]={49,78,49,52}; //31,4E,31,34 (索引 12~15)
//製作要傳送給 NTP 伺服器的封包資料
uint8_t buf[48]; //傳送與接收 UDP 封包的字元串緩衝器
memset(buf, 0, sizeof(buf)); //全部先填入預設值 0
//把存於 Flash 的陣列複製到字元串緩衝器 (0~3, 12~15)
memcpy_P(buf, timeReqA, sizeof(timeReqA));
memcpy_P(&buf[12], timeReqB, sizeof(timeReqB));
//傳送資料給 NTP 伺服器
wifi.send((const uint8_t*)buf, 48);
//接收 NTP 伺服器回應至 buffer 緩衝器 (索引 43~40, timeout=1 秒)
uint32_t len=wifi.recv(buffer, sizeof(buffer), 10000);
if (len > 0) { //有收到 NTP 回應
//計算 UNIX 開始到現在之毫秒數 (後面三個 byte 分別移位後做 OR 運算)
unsigned long t=(((unsigned long)buffer[40] << 24) |
((unsigned long)buffer[41] << 16) |
((unsigned long)buffer[42] << 8) |
(unsigned long)buffer[43]) - 2208988800UL;
//將 CCT 時間戳記轉換為 "時:分:秒"
Serial.print("The CCT time is "); //輸出 CCT 時間 (UTC+8)
if ((((t % 86400L) / 3600 + 8) % 24) < 10) {Serial.print('0');} //時 (小於 10 補 0)
Serial.print(((t % 86400L) / 3600 + 8) % 24); //時 (一天 86400 秒, 取餘數除 3600 為時)
Serial.print(':');
if (((t % 3600) / 60) < 10 ) {Serial.print('0');} //分 (小於 10 補 0)
Serial.print((t % 3600) / 60); //分
Serial.print(':');
if ( (t % 60) < 10 ) {Serial.print('0');} //秒 (小於 10 補 0)
Serial.println(t % 60); //秒
}
//登出 UDP (CIPCLOSE)
if (wifi.unregisterUDP()) {
Serial.print("unregister udp ");
Serial.println(" ok");
}
else {
Serial.print("unregister udp ");
Serial.println(" err");
}
}
草稿碼使用了 15,758 bytes (51%) 的程式存儲空間。最大值為 30,720 bytes。
全域變數使用了 993 bytes (48%) 的動態記憶體,剩餘 1,055 bytes 供局部變數。最大值為 2,048 bytes 。
串列埠監控視窗擷取訊息如下 :
Firmware version ... 0018000902
Working mode ... OK
IP ... 192.168.43.111
register udp ok
The CCT time is 16:36:17
unregister udp ok
register udp ok
The CCT time is 16:36:28
unregister udp ok
register udp ok
The CCT time is 16:36:39
unregister udp ok
register udp ok
The CCT time is 16:36:50
unregister udp ok
看起來運作正常. 這次我改用了另外一個 NTP 伺服器 91.226.136.136, 因為 82.209.243.241 伺服器有時候沒回應. OK, Bingo!
沒有留言:
張貼留言