|
做了个可以自动对时的时钟,没有从网上找到合适的读取NTP服务器时间的代码,自己写了一个,贡献出来,供需要的人参考。
使用的是ESP8266的AT指令,没有使用任何的库
有好几个函数,入口是第一个:synchDateTimeFromNTPServer()
比较粗糙,有很多地方没有判断指令是否执行成功。
- /**
- * 网络对时
- */
- void synchDateTimeFromNTPServer(){
- String cmd, respMessage;
- byte packetBuffer[48];
-
- cmd = "AT+CIPMUX=0";
- respMessage = execATCommand(cmd, 500, false);
-
- //Connect to the NTP server
- cmd = "AT+CIPSTART="UDP","1.cn.pool.ntp.org",123";
- respMessage = execATCommand(cmd, 500, false);
-
- cmd = "AT+CIPSEND=48";
- respMessage = execATCommand(cmd, 50, false);
- memset(packetBuffer, 0, 48);
- 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
- packetBuffer[12] = 49;
- packetBuffer[13] = 0x4E;
- packetBuffer[14] = 49;
- packetBuffer[15] = 52;
- Serial.setTimeout(30000);
- while(Serial.available() > 0){
- Serial.read();
- }
- Serial.write(packetBuffer, 48);
- String data = "";
- unsigned long t1 = millis();
- byte ntpPackage[48];
- do{
- char r = Serial.read();
- if(r == '\n' || r == '\r'){
- data = "";
- }else if( r >= 0){
- data += r;
- }
- if(data == "+IPD,48:"){
- Serial.readBytes(ntpPackage, 48);
- parserNTPMessage(ntpPackage);
- break;
- }
- }while(millis() - t1 < 30000);
- cmd = "AT+CIPCLOSE";
- respMessage = execATCommand(cmd, 200, true);
- }
- /**
- * 解析NTP服务器返回的报文,
- *
- */
- void parserNTPMessage (byte ntpPackage[]){
- byte li = (byte) ((ntpPackage[0] >> 6) & 0x3);
- byte ver = (byte) ((ntpPackage[0] >> 3) & 0x7);
- byte mode = (byte) (ntpPackage[0] & 0x7);
- //Serial.println(" LI=" + String(li) + "; version=" + String(ver) + "; mode=" + String(mode));
- if(li == (byte) 11){
- //11表示当前不可对时(服务器处于闰秒状态)
- return;
- }
- unsigned long highWord = word(ntpPackage[40], ntpPackage[41]);
- unsigned long lowWord = word(ntpPackage[42], ntpPackage[43]);
- // combine the four bytes (two words) into a long integer
- // this is NTP time (seconds since Jan 1 1900):
- unsigned long secsSince1900 = highWord << 16 | lowWord;
- unsigned long secs = secsSince1900 + 8 * 3600L; //东八区,加8小时
- int y = 1900, mon, d, h, m, s, wk;
- wk = (secs / 86400L) % 7 + 1; //86400 is secons in one day; +1 for 1900/1/1 is Monday
-
- do{
- unsigned long ys;
- if(( y % 4 == 0 && y % 100 != 0) || y % 400 == 0){
- ys = 31622400L; //31622400 = 366 * 24 * 3600;
- }else{
- ys = 31536000L; // 31536000 = 365 * 24 * 3600;
- }
- if(secs < ys){
- break;
- }else{
- secs -= ys;
- y++;
- }
- }while(1);
-
- int mons[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
- if((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){
- mons[1] = 29;
- }
- for(mon=0; mon < 12; mon ++){
- if(secs < mons[mon] * 86400L){
- break;
- }else{
- secs -= mons[mon] * 86400L;
- }
- }
- d = secs / 86400L + 1; //86400 = 24 * 3600 = how many seconds in a day
- secs = secs % 86400L;
- h = secs / 3600;
- secs = secs % 3600;
- m = secs / 60;
- s = secs % 60;
-
- //NTP服务器返回的时间已经解析完毕
- //TODO:如果需要更精确的时间,需要处理报文中的服务器收到请求和处理完毕的时间戳;
- //记录arduino发送NTP request和收到response的时间戳,
- //计算网络消耗掉的时长并加到这里获得的时间上
-
- //char buf[50];
- //snprintf(buf, sizeof(buf), "%04d/%02d/%02d %02d:%02d:%02d %0d", y, mon + 1, d, h, m, s, wk);
- //Serial.print("DATE: ");
- //Serial.println(buf);
- }
- /**
- * 向TCP Server发送消息
- */
- void sendMessage(String msg){
- String cmd = "AT+CIPSEND=" + String(msg.length());
- execATCommand(cmd, 0, false);
- delay(10);
- //TODO:没有判断命令是否成功执行
- Serial.print(msg);
- }
- /**
- * 获取ESP8266 IP地址
- */
- String getIPAddr(){
- String msg = execCommand("AT+CIFSR", 100);
- String ip = msg.substring(23,38);
- if(ip.indexOf(""") > 0){
- ip = ip.substring(0, ip.indexOf("""));
- }
- return ip;
- }
- String execCommand(String cmd, int timeout){
- return execATCommand(cmd, timeout, true);
- }
- /**
- * 执行一个AT命令,并返回ESP8266的返回值
- */
- String execATCommand(String cmd, int timeout, boolean clearCache){
- //执行AT命令前,先把缓存内的数据都读完(不用)防止影响命令结果
- if(clearCache){
- while( Serial.available() > 0) {
- Serial.read();
- }
-
- }
- Serial.print(cmd);
- Serial.print("\r\n");
- String data = "";
- if(timeout > 0){
- //delay(50);
- long t1 = millis();
- //while(Serial.available() > 0){
- do{
- char r = Serial.read();
- if(r < 0){
- //r==-1 if nothing read
- continue;
- }
- if(r == '\r') {
- //舍弃回车,仅仅保留换行
- } else {
- data += r;
- }
- }while((millis() - t1) < timeout);
- }
- return data;
- }
复制代码 |
|