- One ESP-12E
- 6 green LEDs
- 8 red LEDs (one of the red LEDs is for decoration, so it doesn't have to work)
- 14 100Ω resistors
- One 74HC595 shift register
- Lots of wires
- micro USB to USB-A cable
- Computer with Arduino IDE installed
- Breadboard
/* * This is a program to run a binary clock on an ESP8266. * Copyright (c) 2019 Ben G. */ // include WiFi libraries #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <WiFiUdp.h> // NOTE: Time is in EST timezone -- for UTC, comment out line // 185, which subtracts five hours to make it EST. // the Wi-Fi network is so we can get the time from the Internet #define ssid "Your-WiFi-SSID" #define pass "Your-WiFi-Password" unsigned int localPort = 2390; // local port to listen for UDP packets const int twelve = 0; // 12 or 24 hour time? For this project, we need 24 hour time /* Don't hardwire the IP address or we won't get the benefits of the pool. * Lookup the IP address for the host name instead */ //IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server IPAddress timeServerIP; // time.nist.gov NTP server address const char* ntpServerName = "time.nist.gov"; const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message unsigned long epoch = 0; byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP WiFiUDP udp; // for minutes const int Sclock = D3; // shift register clock pin const int Slatch = D1; // shift register latch pin const int Sdata = D2; // shift register data pin // for hours: // first digit const int hoursFirst2 = D4; // First hours digit - 2's place const int hoursFirst1 = D0; // First hours digit - 1's place // second digit const int hoursSecond8 = D8; // Second hours digit - 8's place const int hoursSecond4 = D7; // Second hours digit - 4's place const int hoursSecond2 = D6; // Second hours digit - 2's place const int hoursSecond1 = D5; // Second hours digit - 1's place unsigned long sendNTPpacket(IPAddress& address) { Serial.println("sending NTP packet..."); // 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(); } #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) int year, month, day, seconds, minutes, hours; const int leapYearMonths[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int regularMonths[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; void splitTicks(unsigned long time) { seconds = time % 60; time /= 60; minutes = time % 60; time /= 60; hours = time % 24; time /= 24; year = reduceDaysToYear(time); month = reduceDaysToMonths(time,year); day = int(time); } int daysInYear(unsigned long years) { if (LEAP_YEAR(years) == true) { return 366; } else { return 365; } } int daysInMonth(unsigned long monthies, unsigned long yearies) { if (LEAP_YEAR(yearies)) { return leapYearMonths[monthies]; } if (!LEAP_YEAR(yearies)) { return regularMonths[monthies]; } } int reduceDaysToYear(unsigned long &days) { int year; for (year=1970;days>daysInYear(year);year++) { days -= daysInYear(year); } return year; } int reduceDaysToMonths(unsigned long &days,int year) { int month; for (month=0;days>daysInMonth(month,year);month++) days -= daysInMonth(month,year); return month; } void setup() { // setting up. when done you will see a H made up of the LEDs // it's an H because that's the first letter in Hi pinMode(D0, OUTPUT); pinMode(D1, OUTPUT); pinMode(D2, OUTPUT); pinMode(D3, OUTPUT); pinMode(D4, OUTPUT); pinMode(D5, OUTPUT); pinMode(D6, OUTPUT); pinMode(D7, OUTPUT); pinMode(D8, OUTPUT); Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pass); Serial.print("Connecting"); while (WiFi.status() != WL_CONNECTED) { delay(250); Serial.print("."); } Serial.println("Starting UDP"); udp.begin(localPort); Serial.print("Local port: "); Serial.println(udp.localPort()); WiFi.hostByName(ntpServerName, timeServerIP); digitalWrite(hoursSecond8, HIGH); digitalWrite(hoursSecond4, HIGH); digitalWrite(hoursSecond2, HIGH); digitalWrite(hoursSecond1, HIGH); digitalWrite(Slatch, LOW); shiftOut(Sdata, Sclock, LSBFIRST, B01001111); digitalWrite(Slatch, HIGH); delay(1000); // "H" on bootup } void loop() { // put your main code here, to run repeatedly: sendNTPpacket(timeServerIP); // send an NTP packet to a time server // wait to see if a reply is available delay(987); // I like waiting for abnormal amounts of time so that's why 987ms // get the network time int cb = udp.parsePacket(); if (!cb) { Serial.println("no packet yet"); } else { Serial.print("packet received, length="); Serial.println(cb); // We've received a packet, read the data from it udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[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; Serial.print("Seconds since Jan 1 1900 = " ); Serial.println(secsSince1900); // now convert NTP time into everyday time: Serial.print("Unix time = "); // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: epoch = secsSince1900 - seventyYears; epoch -= 18000; // Converts to EST time. This is line 185 // print Unix time: Serial.println(epoch); int hour = (epoch % 86400L) / 3600; int minute = (epoch % 3600) / 60; int second = epoch % 60; // print the hour, minute and second: Serial.println(hour); Serial.println(minute); Serial.println(second); Serial.println(); // set hours digit digitalWrite(hoursFirst1, bitRead(int(hour / 10), 0)); digitalWrite(hoursFirst2, bitRead(int(hour / 10), 1)); digitalWrite(hoursSecond1, bitRead((hour % 10), 0)); digitalWrite(hoursSecond2, bitRead((hour % 10), 1)); digitalWrite(hoursSecond4, bitRead((hour % 10), 2)); digitalWrite(hoursSecond8, bitRead((hour % 10), 3)); byte minutes; // MSB -> LSB, first minute digit first (8, then 4, then 2, then 1) // the MSB in minutes will always be zero so that's where you put a decorative LED bitWrite(minutes, 7, bitRead(int(minute / 10), 3)); // this will always be 0 because this digit will never get above 5 (it can't be 10:99) bitWrite(minutes, 6, bitRead(int(minute / 10), 2)); // int(x/10) rounds x down bitWrite(minutes, 5, bitRead(int(minute / 10), 1)); bitWrite(minutes, 4, bitRead(int(minute / 10), 0)); bitWrite(minutes, 3, bitRead((minute % 10), 3)); // the % operator means divide and return remainder bitWrite(minutes, 2, bitRead((minute % 10), 2)); bitWrite(minutes, 1, bitRead((minute % 10), 1)); bitWrite(minutes, 0, bitRead((minute % 10), 0)); Serial.println(minutes); // Send data to shift register digitalWrite(Slatch, LOW); shiftOut(Sdata, Sclock, LSBFIRST, minutes); digitalWrite(Slatch, HIGH); } }
Okay, now you can upload the code. Here's a tip: set Tools -> Upload Speed to 921600. It uploads way faster.
![](http://www.weebly.com/weebly/images/file_icons/file.png)
binaryclock8266.fzz |
13:40 (aka 1:40 PM)