2018年3月17日 星期六

NTP 網路時鐘的製作ESP8266 + LCD

#Arduino #ESP8266 #OLED #LCD #I2C #IIC #NTP #網路時鐘 #Clock #李進衛
I2C LCD 



Wemos D1 Mini Board 
Wemos D1 Mini Board購買

函數庫下載位址:

程式碼如下
//#include <LiquidCrystal_I2C.h>

 /* 網路時鐘,配合4位顯示LED範例
 * 請注意:本範例必須配合已焊控制板的4位LED哦!
 *
 * 網拍賣場:
 * http://goods.ruten.com.tw/item/show?21649712601470
 *
 * WeMos D1 R2:
 * http://goods.ruten.com.tw/item/show?21639776266588
 *
 * 程式整理:Jason--> 2018-03-05 by lee chin Wei append  I2C LCD
 * http://blog.geeks.tw
 *
 * 本範例要配合Frankie Chu寫的Digital Tube。
 *
 * 下載網址:
 * https://brainy-bits.com/wp-content/uploads/2015/01/DigitalTube_Library.zip
 * 程式設計:李進衛
 * 本範例要配合 Paul Stoffregen寫的Time函式庫:
 * https://github.com/PaulStoffregen/Time
 */

#include <TimeLib.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

#include <TM1637.h> // "
#include <Wire.h> // IIC communication I2C使用的函數
//#include <avr/io.h>
#include <LiquidCrystal_I2C.h>

#define CLK D6 //CLK pin,可自行決定接到哪個PIN
#define DIO D7 //DIO pin,可自行決定接到哪個PIN
TM1637 tm1637(CLK,DIO);
LiquidCrystal_I2C lcd(0x3f,16,2); // Check I2C address of LCD, normally 0x27 or 0x3F

int point_flag =0;

const char ssid[] = "your network SSID";  //  your network SSID (name)
const char pass[] = "your network password";       // your network password
char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
// NTP Server:
static const char ntpServerName[] = "us.pool.ntp.org";

const int timeZone = 8;     //台灣時區+8

int hourH = 0;     //
int hourL = 0;     //
int minH = 0;     //
int minL = 0;     //
int secH = 0;     //
int secL = 0;     //
int monH = 0;
int monL = 0;
int dayH = 0;
int dayL = 0;
int dayOfWeek = 0;
//建立與NTP的連線
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets

time_t getNtpTime();

void setup()
{
  tm1637.init();
  tm1637.set(BRIGHT_TYPICAL); //BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;

  tm1637.display(0,0);  //設定每一位燈號顯示的內容,參數1:燈號,參數2:顯示的數字
  tm1637.display(1,0);
  tm1637.display(2,0);
  tm1637.display(3,0);
  Wire.begin(D14,D15);  //一定要加這一行還可以正常顯示出來 (0,2); //sda=0 | D3, scl=2 | D4
  lcd.backlight();
  lcd.clear();
//  lcd.noBlink();
  lcd.home();                // At column=0, row=0

  Serial.begin(115200);
  while (!Serial) ; // Needed for Leonardo only
  delay(250);

  //建立WiFi連線
  Serial.println("NTP 網路時鐘");
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print("IP number assigned by DHCP is ");
  Serial.println(WiFi.localIP());
  Serial.println("Starting UDP");
  Udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(Udp.localPort());
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
  setSyncInterval(300);
}

time_t prevDisplay = 0; // 記錄上一次的時間,如果相同,LED就不用更新

void loop()
{
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //時間變化就顯示
      prevDisplay = now();   //把目前時間丟給prevDisplay
//      Serial.println(now());
      digitalClockDisplay(); //呼叫顯示時間的副程式
    }
  }
}

void digitalClockDisplay()
{
//    lcd.home();                // At column=0, row=0
  //設定每一位燈號顯示的內容,參數1:燈號,參數2:顯示的數字
  tm1637.display(0,hour() / 10);
  tm1637.display(1,hour() % 10);
  tm1637.display(2,minute() / 10);
  tm1637.display(3,minute() % 10);
//==============================================
  monH = (month()/10);
  monL = (month()%10);
  dayH = (day()/10);
  dayL = (day()%10);

  hourH = (hour()/10) ;
//  hourH = hourH/10;
//  Serial.print(hourH);
  hourL = (hour()%10);
//  Serial.print(hourL);
  minH = (minute() / 10);
//  Serial.print(minH);

  minL = (minute() % 10);
//  Serial.print(hourL);

  secH = (second() /10);
//  Serial.print(secH);

  secL = (second() %10);
//  Serial.println(secL);

//================================================
    lcd.setCursor(0, 0);
    lcd.print(year());
    lcd.setCursor(4,0);
    lcd.print("/");
    lcd.setCursor(5,0);
    lcd.print(monH,DEC);
    lcd.setCursor(6,0);
    lcd.print(monL,DEC);
    lcd.setCursor(7,0);
    lcd.print("/");
    lcd.setCursor(8,0);
    lcd.print(dayH,DEC);
    lcd.setCursor(9,0);
    lcd.print(dayL,DEC);
 
// dayOfWeek = weekday();
    lcd.setCursor(11,0);
lcd.print(daysOfTheWeek[weekday()-1]);
/*
switch(dayOfWeek){
  case 1:
    lcd.setCursor(11,0);
    lcd.print("Sun");

//    Serial.println("Sunday");
    break;
  case 2:
    lcd.setCursor(11,0);
    lcd.print("Mon");
//    Serial.println("Monday");
    break;
  case 3:
    lcd.setCursor(11,0);
    lcd.print("Tue");
//    Serial.println("Tuesday");
    break;
  case 4:
    lcd.setCursor(11,0);
    lcd.print("Wed");

//    Serial.println("Wednesday");
    break;
  case 5:
    lcd.setCursor(11,0);
    lcd.print("Thu");
//    Serial.println("Thursday");
    break;
  case 6:
    lcd.setCursor(11,0);
    lcd.print("Fri");

 //   Serial.println("Friday");
    break;
  case 7:
    lcd.setCursor(11,0);
    lcd.print("Sat");

//    Serial.println("Saturday");
    break;
  } 

  */
 
 

//  Serial.print(year());
//  Serial.print("/");
//  Serial.print(month());
//  Serial.print("/");
//  Serial.print(day());
 // Serial.print("===>");
 // Serial.println(weekday());
    lcd.setCursor(0, 1);
    lcd.print(hourH,DEC);
    lcd.setCursor(1, 1);
    lcd.print(hourL,DEC);
    lcd.setCursor(2, 1);
    lcd.print(":");
    lcd.setCursor(3, 1);
    lcd.print(minH,DEC);
    lcd.setCursor(4, 1);
    lcd.print(minL,DEC);
    lcd.setCursor(5, 1);
    lcd.print(":");
     lcd.setCursor(6, 1);
    lcd.print(secH,DEC);
     lcd.setCursor(7, 1);
    lcd.print(secL,DEC);
     lcd.setCursor(16,1);
 
//    lcd.home();                // At column=0, row=0
 // lcd.noBlink();

 // Serial.print(hour());
 // Serial.print(":");
 // Serial.print(minute());
 // Serial.print(":");
 // Serial.println(second());
 
  //顯示時和分之間的:,如果目前是顯示,就設定下次不顯示
  if(point_flag){
    tm1637.point(POINT_OFF);
    point_flag = 0;
  }else{
    tm1637.point(POINT_ON);
    point_flag = 1;
  }
}


/*-------- NTP 程式碼 ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  IPAddress ntpServerIP; // NTP server's ip address

  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  // get a random server from the pool
  WiFi.hostByName(ntpServerName, ntpServerIP);
  Serial.print(ntpServerName);
  Serial.print(": ");
  Serial.println(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive 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];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  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();
}

沒有留言:

WEMOS D1 MINI ESP8266 製作 NTP + 網路斷線自動重置裝置

我的同事建議我將 NTP 加上網路斷線偵測可以重新reset的功能