< async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"">

Friday, March 7, 2014

A simple arduino clock using ethernet shield and ntp for beginners

ADVERTISEMENT
Led clock with arduino and ethernetshield (NTP)

In this post we will build a simple clock using arduino and 7-segment led display. The display used is the same as in my previous post on ultrasound range detector, where the pin connection for the seven segment led module is explained in detail. In this case we use the ethernet shield to connect to an ntp server to get the correct time. It uses a time library which keeps the correct time and updates it from ntp. So there is no need to use a real time (RTC) clock module ( a small clock with a battery to keep the time when arduino is switched off). The whole setup can be easily bread boarded as shown below. There are 12 connection to the led display of which eight of them uses a resistor to limit the current and to protect arduino pins and led. Compared to previous post, here instead of digital pins 8 to 13, A0 to A5 ( ie 14 to 19) are used ( to avoid interfering with Ethernet shield). See the sketch / firmware given at the end of the post to determine the pin connections.


This is a very simple and quick project (where all complex stuffs are encapsulated in the libraries). It gets the correct time from ntp when started and is kept (by time library). The serial console can be used to debug where it output the full time and date.

This is just an example and there are multiple possibilities based on these basic blocks. Complete source including libraries can be downloaded here

/*
 * This sketch uses the Ethernet library and Hobby Components 7segement library
 */
 
#include <Time.h> 
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>

/* Include the 7 segment display library */
#include <HC7Segment.h>
/* Pin order for digit select DIO */
const byte u8PinOut_Digit[] = {14,6,5,2};

/* Pin order for segment DIO. The segment order is A,B,C,D,E,F,G,DP */
const byte u8PinOut_Segment[] = {3,7,16,18,19,4,15,17};
/* Create an instance of HC7Segment(). In this example we will be using a 4 digit
common cathode display (CAI5461AH) */
HC7Segment HC7Segment(4, LOW);
/* Place any setup code that you require here */

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
// NTP Servers:
IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov
// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov
// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov


const int timeZone = 1;     // Central European Time
//const int timeZone = -5;  // Eastern Standard Time (USA)
//const int timeZone = -4;  // Eastern Daylight Time (USA)
//const int timeZone = -8;  // Pacific Standard Time (USA)
//const int timeZone = -7;  // Pacific Daylight Time (USA)


EthernetUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets

void setup() 
{
  Serial.begin(9600);
  while (!Serial) ; // Needed for Leonardo only
  delay(250);
  Serial.println("TimeNTP Example");
  if (Ethernet.begin(mac) == 0) {
    // no point in carrying on, so do nothing forevermore:
    while (1) {
      Serial.println("Failed to configure Ethernet using DHCP");
      delay(10000);
    }
  }
  Serial.print("IP number assigned by DHCP is ");
  Serial.println(Ethernet.localIP());
  Udp.begin(localPort);
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
}

time_t prevDisplay = 0; // when the digital clock was displayed

void loop()
{  
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      digitalClockDisplay();  
    }
  }
  HC7Segment.vDisplay_Number(hour()*100+minute(),3);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
  HC7Segment.vDisplay_Number(hour(),2);
}

void printDigits(int digits){
  // utility for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*-------- NTP code ----------*/

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()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  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();
}

9 comments:

  1. sir if i want add second value, not only hour and minute. then what can i do? i do this work according to your tutorial. please help me for add extra two digit for second

    ReplyDelete
    Replies
    1. Just add two more digits and then
      HC7Segment HC7Segment(4, LOW); ==> HC7Segment HC7Segment(6 ,LOW);
      and add others in const byte u8PinOut_Digit[] = {14,6,5,2, extra digit , extra digit};

      and finally adjust this HC7Segment.vDisplay_Number(hour()*10000+minute()*100+second(),3);

      godd luck!

      Delete
  2. Sir after edit according to your solution my clock show garbage value.01.22.78. that means 78 second. is jaust a sample.

    ReplyDelete
    Replies
    1. check serial port (debug) and see if seconds are correct. Try HC7Segment.vDisplay_Number function with a large number to see if it output correct or define a variable like
      double lcdout = hour()*10000+minute()*100+second();
      HC7Segment.vDisplay_Number(lcdout,3);

      Delete
    2. It seems the library may needs modification to accept such a big number!

      as vDisplay_Number function takes an int ( max value 32767 )

      Delete
    3. double lcdout = hour()*10000+minute()*100+second();
      HC7Segment.vDisplay_Number(lcdout,3);

      sir this portion didn't work. just same.
      may be library function problem which is written in c++.
      thank you sir for help me

      Delete
    4. Seems the library cant handle it. You may try changing the library files HC7Segment.h and HC7Segment.cpp by replacing the int to double for vDisplay_Number.

      Easy solution is using a serial 7 segment display module with their libraries

      Good luck !

      Delete
    5. obs!! use long instead of double in all my replies

      Delete
  3. i use all long instead of double. but same problem.

    ReplyDelete