ENC28J60 NTP Client (and DHCP) Demo

In this tutorial we show how to get the time from a specificic NTP server with a ENC28J60 module.



Rightclick to see full picture The ENC28J60 network module can be bought on ebay for a few dollar.

You can download the library here.







Pinout:
SS 8
MOSI 11
MISO 12
SCK 13
GND GND
VCC 5V (the manuals only recomend to use 3,3V but did not worked for me, so don't blame me for any damage!

For this tutorial we need also a DS1307 or DS3231 (which are significant better) which we connect to the i2c.

In the setup loop we try to get a dhcp adress. When succes the script tries to get a response from a designated time server. When succes the received ntp time will be set to the RTC module.
Also as the cherisch on a cake, i put a little function to adjust the timezone setting automaticly (Europe), which i find somewhere on the internet. Of course you can adjust the script to sync with a time server in the loop let's say by pressing a button.

enc28j60_ntp_client.ino

// Arduino demo sketch for testing the DHCP client code
//
// Original author: Andrew Lindsay
// Major rewrite and API overhaul by jcw, 2011-06-07
//
// Copyright: GPL V2
// See http://www.gnu.org/licenses/gpl.html

#include <EtherCard.h>
#include <Wire.h>
#include "RTClib.h" // Credit: Adafruit


RTC_DS1307 RTC;


static byte ntpServer[] = {194,109,6,2}; //ntp.xs4all.nl but you can cange in any public ntp server.
uint8_t ntpMyPort = 123;
long timeZoneOffset = 3600L; //Winter (original) time Europe
boolean networkConnection = true;


static byte mymac[] = { 0x01,0x02,0x03,0x04,0x05,0x06 }; //Change this in a unique mac adres for your network

byte Ethernet::buffer[700];


void setup () {
Serial.begin(9600);

// Instantiate the RTC
Wire.begin();
RTC.begin();


// Check if the RTC is running.
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running");
} else {
Serial.println("RTC present");
}


Serial.println(F("\n[testDHCP]"));

Serial.print("MAC: ");
for (byte i = 0; i < 6; ++i) {
Serial.print(mymac[i], HEX);
if (i < 5)
Serial.print(':');
}
Serial.println();

int i = 1;
int DHCP = 0;
//Try to get dhcp settings 3 times before giving up
Serial.println("Resolve dhcp ...");
lcd.setCursor(0,0);
lcd.print("Resolve dhcp ...");


while( DHCP == 0 && i < 3){
Serial.print("Trying to resolve DHCP attempt nr. ");
Serial.println(i);
lcd.setCursor(i,1);
lcd.print("*");
delay(1000);
DHCP = ether.begin(sizeof Ethernet::buffer, mymac);
i++;
}

//Serial.println(F("Setting up DHCP"));
if (!ether.dhcpSetup()) {
Serial.println(F("DHCP failed"));
lcd.setCursor(0,1);
lcd.print("DHCP failed");
networkConnection = false;
}

ether.printIp("My IP: ", ether.myip);
ether.printIp("Netmask: ", ether.netmask);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);

//you can output this to lcd, oled or 7-segment
uint8_t *ipPtr = ether.myip;
String ip0 = String(ipPtr[0], DEC);
String ip1 = String(ipPtr[1], DEC);
String ip2 = String(ipPtr[2], DEC);
String ip3 = String(ipPtr[3], DEC);


//Get time from DS3231
DateTime now = RTC.now();
unsigned long epoch = now.unixtime();


//If network connection is true, sync with ntp server
if (networkConnection) {epoch = getNtpTime();}
if (epoch == 0) {DateTime now = RTC.now(); epoch = now.unixtime();} //sync failed, use DS3231 time instead

//Check summer / winter time
if (adjustDstEurope()) {epoch = epoch + 3600; timeZoneOffset = 7200L;}
RTC.adjust(epoch);
now = RTC.now();

Serial.println(epoch);
} //End of setup


unsigned long getNtpTime() {
unsigned long timeFromNTP;
const unsigned long seventy_years = 2208988800UL;
int i = 60; //Number of attempts
Serial.println("NTP request sent");
while(i > 0) {
ether.ntpRequest(ntpServer, ntpMyPort);
Serial.print("."); //Each dot is a NTP request
word length = ether.packetReceive();
ether.packetLoop(length);
if(length > 0 && ether.ntpProcessAnswer(&timeFromNTP,ntpMyPort)) {
Serial.println();
Serial.println("NTP reply received");
return timeFromNTP - seventy_years + timeZoneOffset;
}
delay(500);
i--;
}
Serial.println();
Serial.println("NTP reply failed");
return 0;
}


boolean adjustDstEurope()
{
// Get the current time
DateTime now = RTC.now();
// last sunday of march
int beginDSTDate= (31 - (5* now.year() /4 + 4) % 7);
int beginDSTMonth=3;
//last sunday of october
int endDSTDate= (31 - (5 * now.year() /4 + 1) % 7);
int endDSTMonth=10;
// DST is valid as:
if (((now.month() > beginDSTMonth) && (now.month() < endDSTMonth))
|| ((now.month() == beginDSTMonth) && (now.day() >= beginDSTDate))
|| ((now.month() == endDSTMonth) && (now.day() < endDSTDate)))
return true; // DST europe = GMT +2
else return false; // nonDST europe = GMT +1
}


void loop () {
// Get the current time
DateTime now = RTC.now();

unsigned long newHour = now.hour();
unsigned long newMinute = now.minute();
unsigned long newSecond = now.second();
unsigned long newYear = now.year();
unsigned long newMonth = now.month();
unsigned long newDay = now.day();


int hour1 = (newHour%10);
int hour10 = (newHour/10);
int minute1 = (newMinute%10);
int minute10 = (newMinute/10);
int second1 = (newSecond%10);
int second10 = (newSecond/10);
int year1 = (newYear%10);
int year10 = ((newYear/10)%10);
int year100 = ((newYear/100)%10);
int year1000 = (newYear/1000);
int month1 = (newMonth%10);
int month10 = (newMonth/10);
int day1 = (newDay%10);
int day10 = (newDay/10);


//Output to serial console, but you can use lcd, oled or 7-segment
Serial.print(hour10);
Serial.print(hour1);
Serial.print(":");
Serial.print(minute10);
Serial.print(minute1);
Serial.print(":");
Serial.print(second10);
Serial.print(second1);
Serial.print(" ");
Serial.print(day10);
Serial.print(day1);
Serial.print("-");
Serial.print(month10);
Serial.print(month1);
Serial.print("-");
Serial.print(year1000);
Serial.print(year100);
Serial.print(year10);
Serial.println(year1);

delay(1000);
}

Serial output

RTC present

[testDHCP]
MAC: 01:02:03:04:05:06
Resolve dhcp ...
Trying to resolve DHCP attempt nr. 1
My IP: 192.168.1.101
Netmask: 255.255.255.0
GW IP: 192.168.1.1
DNS IP: 192.168.1.1
NTP request sent
......
NTP reply received
1448374162