Showing posts with label Shield. Show all posts
Showing posts with label Shield. Show all posts

2017/05/14

NTP Server Synchronized LCD DS1307 RTC Clock


Requirements:

1. Arduino Uno R3
2. RTC (DS1307) Sensor Shield
3. W5100 Ethernet Shield
4. LCD Keypad Shield

Schetch:

/*
 * NTPSynchronizedRTC20170514.ino
 */

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7);

char dayOfWeek[9][4] = {"", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
time_t t;
int displayAtSecond;

// timeZoneOffset = (Time Zone) * 3600L eg. (+8) * 3600L = 28800L for Taipei, Taiwan
const long timeZoneOffset = 28800L; 
// sync to NTP server every "ntpSyncInterval" seconds, set to 1 hour or more to be reasonable
unsigned long ntpSyncInterval = 3600;
// adjust the sync latency with computer NTP client in seconds 
unsigned long syncLatency = 0;

// Enter a MAC address for your controller bellow.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
unsigned int localPort = 8888; // local port to listen for UDP packets
IPAddress timeServer(192, 168, 1, 123); // LAN NTP server
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

// keep track of how long ago we updated the NTP server
unsigned long ntpLastUpdate = 0;

void setup()  {
  Serial.begin(115200);
  lcd.begin(16,2);
  lcd.print("*cheaphousetek*");
  lcd.setCursor(0,1);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     lcd.print("Unable to sync");
  else
     lcd.print("Sync system time ");
  displayAtSecond = second();
  delay(2000);
  lcd.clear();
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    lcd.setCursor(0,1);
    lcd.print("DHCP failed");
    for (;;);
  }
  Udp.begin(localPort);
}

void loop()
{
  if ((now() - ntpLastUpdate) >= ntpSyncInterval) {
    ntpSyncDS1307();
    // clear seconds displayed once a second when sync is needed, cause seconds blink to notify checking the network status
    lcd.setCursor(9, 1);
    lcd.print("       ");
  }
  
  // for LCD shield to disp date, day of the week, time and temperature once a second
  t = now();
  if (displayAtSecond != second(t)) { 
    digitalClockDisplay(); 
    displayAtSecond = second(t); 
  }
}

void digitalClockDisplay(){
  // digital clock display of the time
  dateDisplay();
  weekdayDisplay();
  timeDisplay();
  // display seconds since last NTP update
  lcd.setCursor(9, 1);
  lcd.print(now()-ntpLastUpdate);
     // Serial.print(now());
     // Serial.print("    ");
     // Serial.println(ntpLastUpdate);
}

void dateDisplay() {
  lcd.setCursor(0,0);
  lcd.print(year(t));
  lcd.print('-');
  if (month(t) < 10) {
    lcd.print('0');
  }
  lcd.print(month(t));
  lcd.print('-');
  if (day(t) < 10) {
    lcd.print('0');
  }
  lcd.print(day(t));
  // lcd.print(' ');
}

void weekdayDisplay() {
  lcd.setCursor(11,0);
  lcd.print(dayOfWeek[weekday()]);
}

void timeDisplay() {
  lcd.setCursor(0,1);
  if (hour(t) < 10) {
    lcd.print('0');
  }
  lcd.print(hour(t));
  lcd.print(':');
  if (minute(t) < 10) {
    lcd.print('0');
  }
  lcd.print(minute(t));
  lcd.print(':');
  if (second(t) < 10) {
    lcd.print('0');
  }
  lcd.print(second(t));
  // lcd.print(' ');
}

void ntpSyncDS1307() {
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait to see if a replay is available
  delay(100);
  if (Udp.parsePacket()) {
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
    // the timstamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract 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;
    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800L;
    // substract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears + timeZoneOffset + syncLatency;
    setTime(epoch);
    RTC.set(epoch);
    ntpLastUpdate = now();
    // clear seconds displayed once ntp sync succeeded
    lcd.setCursor(9, 1);
    lcd.print("       ");
  }
}

// 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 clodk
  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);
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

2015/04/24

MakerCarve - A Shapeoko 2 Compatible CNC Router/Carving/Engraving Machine

MakerCarve is a Shapeoko 2 compatible machine with some modification listed bellow:

1. Mechanical Kit
A. Tapped SlideSlot aluminium rail extrusions are used instead of MakerSlide
B. All plates are made of aluminium
C. End plates are 5mm in thickness to increase stiffness
D. 2020 aluminium extrusions are 527mm in length

2. Electronic Kit
A. The grblShield is replaced by CNC Shield
B. Belt locking torsion springs are used

3. Software
A. GRBL Controller (G-Code Sender) is preferred to Universal-G-Code-Sender

To enable MakerCarve function well, the Arduino Uno R3 must be uploaded with grbl firmware (hex file) and properly configured. To upload grbl hex file, XLoader is used.
A. GRBL Homepage
B. Quick GRBL (Arduino G-Code Interpreter) Setup Guide For Windows
C. GRBL Configuration Page

To assembly, methods and tools used in Shapeoko Rebuild are recommended.

To engrave or to carve, the free open source F-Engrave is used.

2014/11/09

Arduino RF Wireless Message Display Using I2C LCD Keypad Shield

The function of this sketch is same as the sketch posted on May. 11, 2014, but using I2C LCD Keypad Shield as the output device.

Sketch

/*
SimpleReceiveI2CLCD
This sketch displays text strings received using VirtualWire
Connect the Receiver data pin to Arduino pin 11
Modified by Befun Hung on Nov. 09, 2014 
Use I2C LCD Keypad Shield as the output
*/

#include <VirtualWire.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// #define BACKLIGHT_PIN 13
LiquidCrystal_I2C lcd(0x20); //Set the LCD I2C address
// LiquidCrystal_I2C lcd(0x38, BACKLIGHT_PIN, POSITIVE);

byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message
unsigned long counter = 1;

void setup()
{
  // pinMode(BACKLIGHT_PIN, OUTPUT);
  // digitalWrite(BACKLIGHT_PIN, HIGH);
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2); //initialize the lcd
  // Print a message to the LCD.
  lcd.home(); //go home
  lcd.print("Device is ready!");
  // 
  Serial.begin(9600);
  Serial.println("Device is ready");
  // Initialize the IO and ISR
  vw_setup(2000); // Bits per sec
  vw_rx_start(); // Start the receiver
}
void loop()
{
  if (vw_get_message(message, &messageLength)) // Non-blocking
  {
    lcd.clear();
    Serial.print(counter);
    Serial.print(": ");
    // set the cursor to column 0, line 1
    // (note: line 1 is the second row, since counting begins with 0):
    lcd.setCursor(0, 0);
    lcd.print(counter);
    lcd.print(":");
    lcd.setCursor(0,1);
    for (int i = 0; i < messageLength; i++)
    {
      Serial.write(message[i]);
      lcd.print(char(message[i]));
    }
    Serial.println();
    counter++;
  }
}

2014/09/21

Camera Slider / Dolly - MakerSlide + Arduino + CNC Shield + A4988 Driver + 42BYGH4417 Stepper Motor

One dimension movement is the most basic practice to position. By following the design of simple camera slider by Bart Dring from Inventables, I have made my own camera dolly and changed the pulley and belt of  gt2 specification for easy steps calculation.

The use of CNC Shield is optional, it is used just for easy extension to y-axis and z-axis.

Connection

1. Stack CNC Shield on Arduino Uno or Mega2560
2. Connect CNC Shield to power supply with voltage 8-35V
3. Connect CNC X axis to 42BYGH4417 stepper motor

Photo


Connections 



Dolly In Motion
Sketch

// simple stepper motor control 
// only x axis is used for dolly
#define EN 8 / / stepper motor enable
#define X_DIR 5/ / x axis direction control
#define Y_DIR 6/ / y axis direction control
#define Z_DIR 7/ / z axis direction control
#define X_STP 2/ / x axis step control
#define Y_STP 3/ / y axis step control
#define Z_STP 4/ / z axis step control

/*
// step(): to control direction and steps of stepper motor
// parameter: dir for direction control, 
//                   dirPin maps to DIR pin of stepper motor,
//                   stepperPin maps to STEP pin of stepper motor
// return value: none
*/

void step(boolean dir, byte dirPin, byte stepperPin, int steps)
{
  digitalWrite(dirPin, dir);
  delay(50);
  for (int i = 0; i < steps; i++) {
    digitalWrite(stepperPin, HIGH);
    delayMicroseconds(800);
    digitalWrite(stepperPin, LOW);
    delayMicroseconds(800);
  }
}

void setup (){
  // setup stepper motor I/O pin to output
  pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);
  pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);
  pinMode(Z_DIR, OUTPUT); pinMode(Z_STP, OUTPUT);
  pinMode(EN, OUTPUT);
  digitalWrite(EN, LOW);
}

void loop (){
  // 200 steps per turn
  step(false, X_DIR, X_STP, 1800); // run 360 mm
  step(false, Y_DIR, Y_STP, 200); 
  step(false, Z_DIR, Z_STP, 200); 
  delay(1000);
  step(true, X_DIR, X_STP, 1800);  // run 360 mm in reverse direction
  step(true, Y_DIR, Y_STP, 200); 
  step(true, Z_DIR, Z_STP, 200); 
  delay(1000);
}



2014/08/09

Schematic and Photo Of Arduino PCF8574 I2C LCD Keypad Shield

  My PCF8574 I2C LCD Keypad Shield has been completed. The benefit of I2C LCD Keypad Shield over LCD Keypad Shield is that it free up 6 digital I/O used by LCD Keypad Shield for other use.
  The schematic used is version 1.1 other than the version 1.0 posted on Feb. 28, 2014. The difference between version 1.1 and version 1.0 is that the version 1.1 has a 4-pins I2C connector as shown on the bottom-left corner of the shield on the photo to act a either a shield or a breakout. When the shield serves as a breakout, the 5-way button cannot function. The sketch runs is same as the one posted on Feb. 28, 2014.

  When the shield is stacked directly upon the Arduino Uno, it should be noticed avoiding the pins of PCF8574 touching the shield of USB type B connector of Arduino. A insulated stick is a simple way. It is recommend to use Arduino boards with mini or micro USB connector such as Leonardo or stack on any other shield.


Schematic
Photo

2014/06/22

Arduino Color LCD Shield Keypad Adjustable DS1307 Real Time Clock Using Time.h Library

The ColorLCDShield.h library comes with an example sketch ChronoLCD_Color which sets the time at compile stage and time cannot be adjusted. By reading time from DS1307, the sketch can get correct time after power interruption. By modifying the setTime(), time can be adjusted and restored to DS1307 real time clock. No re-compilation is needed any more.

Boards
1. Arduino Uno R3
2. cheaphousetek RTC Shield
3. Color LCD Shield

Photo




Sketch

/*
  ChronoLCD Color - An example sketch for the Color LCD Shield Library
  by: Jim Lindblom
  SparkFun Electronics
  date: 6/23/11
  license: CC-BY SA 3.0 - Creative commons share-alike 3.0
  use this code however you'd like, just keep this license and
  attribute. Let me know if you make hugely, awesome, great changes.
  
  This sketch draws an analog and digital clock on the Color LCD
  Shield. You can also use the on-board buttons to set the hours
  and minutes.
  
  Use the defines at the top of the code to set the initial time.
  You can also adjust the size and color of the clock.
  
  To set the time, first hit S3. Then use S1 and S2 to adjust the
  hours and minutes respsectively. Hit S3 to start the clock
  back up.
  
  This example code should give you a good idea of how to use
  the setCircle, setLine, and setStr functions of the Color LCD
  Shield Library.
*/
// Modified by Befun Hung on Jun. 22, 2014 
// 1) Sync time with DS1307 real time clock 
// 2) Use onboard keypad to adjust DS1307 time parameter
//    Press S1 get into adjustment mode, 
//    Press S2 to adjust or 
//    Press S3 to select which parameter to be adjusted with default to hour
//    Press S1 to save parameters to DS1307
// 3) Show date and weekday
// 4) Minor adjustment of analog clock

#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t
#include <ColorLCDShield.h>

char *dayOfWeek[] = {"", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
time_t t;
int displayAtSecond;

#define CLOCK_RADIUS 41  // radius of clock face
#define CLOCK_CENTER 50  // If you adjust the radius, you'll probably want to adjust this
#define H_LENGTH  23  // length of hour hand
#define M_LENGTH  33  // length of minute hand
#define S_LENGTH  37  // length of second hand

#define BACKGROUND  BLACK  // room for growth, adjust the background color according to daylight
#define C_COLOR  RED  // This is the color of the clock face, and digital clock
#define H_COLOR  BLUE  // hour hand color
#define M_COLOR  GREEN  // minute hand color
#define S_COLOR  YELLOW  // second hand color

LCDShield lcd;

int years, months, days;
int hours, minutes, seconds;
int buttonPins[3] = {3, 4, 5};

void setup()
{
  /* Set up the button pins as inputs, set pull-up resistor */
  for (int i=0; i<3; i++)
  {
    pinMode(buttonPins[i], INPUT);
    digitalWrite(buttonPins[i], HIGH);
  }
  
  /* Initialize the LCD, set the contrast, clear the screen */
  lcd.init(PHILIPS);
  lcd.contrast(-63);
  lcd.clear(BACKGROUND);
  
  setSyncProvider(RTC.get); // the function to get the time from the RTC
}

void loop()

  t = now();
  years = year(t);
  months = month(t);
  days = day(t);
  hours = hour(t);
  minutes = minute(t);
  seconds = second(t);
  
  if (!digitalRead(buttonPins[2]))
      setTime();  // If S3 was pressed, go set the time
      
  if (displayAtSecond != second(t)) {
    drawClock(); // Draw the clock face, this includes 12, 3, 6, 9
    displayAnalogTime(hours, minutes, seconds); // Draw the clock hands
    displayDateDayOfWeek(years, months, days);
    displayDigitalTime(hours, minutes, seconds); // Draw the digital clock text
    displayAtSecond = second(t);
  }
}
/* 
  setTime uses on-shield switches S1, S2, and S3 to set the time
  pressing S3 will exit the function. S1 increases hours, S2 
  increases seconds.
 */ 
void setTime()
{
  int setVariable = 3, checkStatus = 0;
  /* Reset the clock */
  years = year(t);
  months = month(t);
  days = day(t);
  hours = hour(t);
  minutes = minute(t);
  seconds = second(t);
  
  /* Draw the clock, so we can see the new time */
  drawClock();
  displayAnalogTime(hours, minutes, seconds);
  displayDateDayOfWeek(years, months, days);
  displayDigitalTime(hours, minutes, seconds);
    
  while (!digitalRead(buttonPins[2]))
    ; // wait till they let go of S1
  
  /* We'll run around this loop until S3 is pressed again */
  while(digitalRead(buttonPins[2]))
  {
    /* If S1 is pressed, we'll update the hours */
    if (!digitalRead(buttonPins[0]))
    {
      delay(100);
      setVariable = (setVariable + 1) % 6;  // Select year, month, day, hour, minute, second to change, default is year
        
      /* and update the clock, so we can see it */
      drawClock();
      displayAnalogTime(hours, minutes, seconds);
      displayDateDayOfWeek(years, months, days);
      displayDigitalTime(hours, minutes, seconds);
    }
    if (!digitalRead(buttonPins[1]))
    {
      delay(100);
      switch (setVariable) {
        case 0:{
          years = ((years + 1) % 100) + 2000;
          break;
        }
        case 1:{
          months = (months % 12) + 1; 
          break;
        }
        case 2:{
          days = (days % 31) + 1;
          break;
        }
        case 3:{
          hours = (hours + 1) % 24;
          break;
        }
        case 4:{
          minutes = (minutes + 1) % 60;
          break;
        }
        case 5:{
          seconds = (seconds + 1) % 60;
          break;
        }
      }
      // minutes++;  // Increase minutes by 1
      // if (minutes >= 60)
      //   minutes = 0;  // If minutes is 60, set it back to 0
        
      /* and update the clock, so we can see it */
      drawClock();
      displayAnalogTime(hours, minutes, seconds);
      displayDateDayOfWeek(years, months, days);
      displayDigitalTime(hours, minutes, seconds);
    }
  }
  /* Once S3 is pressed, we'll exit, but not until it's released */
  while(!digitalRead(buttonPins[2]))
    ;
  if ((months == 1 || months == 3 || months == 5 || months == 7 || months == 8 || months == 10 || months == 12) && days <= 31) checkStatus = 1;
  if ((months == 4 || months == 6 || months == 9 || months == 11) && days <=30) checkStatus = 1;
  if ((months == 2 && (years % 4) == 0) && days <= 29) checkStatus = 1;
  if ((months == 2 && (years % 4) != 0) && days <= 28) checkStatus = 1;
  if (checkStatus) {
    setTime(hours, minutes, seconds, days, months, years);
    RTC.set(now());
  }
}

/*
  displayDateDayOfWeek() takes in values for years, months, days.
  It'll print the date, day of week, in digital format, on the
  bottom of the screen.
*/
void displayDateDayOfWeek(int y, int m, int d)
{
  char dateChar[12];
  
  sprintf(dateChar, "%.4d-%.2d-%.2d ", y, m, d);
  
  /* Print the time on the clock */
  lcd.setStr(dateChar, 90, 10, 
              C_COLOR, BACKGROUND);
  lcd.setStr(dayOfWeek[weekday()], 90, 98, 
              C_COLOR, BACKGROUND);
}

/*
  displayDigitalTime() takes in values for hours, minutes and 
  seconds. It'll print the time, in digital format, on the
  bottom of the screen.
*/
void displayDigitalTime(int h, int m, int s)
{
  char timeChar[10]; // adjust the number of characters to avoid odd display
  
  sprintf(timeChar, "%.2d:%.2d:%.2d", h, m, s);
  
  /* Print the time on the clock */
  lcd.setStr(timeChar, 105, 26, C_COLOR, BACKGROUND);
}

/*
  drawClock() simply draws the outer circle of the clock, and '12',
  '3', '6', and '9'. Room for growth here, if you want to customize
  your clock. Maybe add dashe marks, or even all 12 digits.
*/
void drawClock()
{
  /* Draw the circle */
  lcd.setCircle(CLOCK_CENTER, 66, CLOCK_RADIUS, C_COLOR);
  
  /* Print 12, 3, 6, 9, a lot of arbitrary values are used here
     for the coordinates. Just used trial and error to get them 
     into a nice position. */
  lcd.setStr("12", CLOCK_CENTER - CLOCK_RADIUS, 66-9, C_COLOR, BACKGROUND);
  lcd.setStr("3", CLOCK_CENTER - 9, 66 + CLOCK_RADIUS - 12, C_COLOR, BACKGROUND);
  lcd.setStr("6", CLOCK_CENTER + CLOCK_RADIUS - 18, 66-4, C_COLOR, BACKGROUND);
  lcd.setStr("9", CLOCK_CENTER - 9, 66 - CLOCK_RADIUS + 4, C_COLOR, BACKGROUND);
}

/*
  displayAnalogTime() draws the three clock hands in their proper
  position. Room for growth here, I'd like to make the clock hands
  arrow shaped, or at least thicker and more visible.
*/
void displayAnalogTime(int h, int m, int s)
{
  double midHours;  // this will be used to slightly adjust the hour hand
  static int hx, hy, mx, my, sx, sy;
  
  /* Adjust time to shift display 90 degrees ccw
     this will turn the clock the same direction as text */
  h -= 3;
  m -= 15;
  s -= 15;
  if (h <= 0)
    h += 12;
  if (m < 0)
    m += 60;
  if (s < 0)
    s += 60;
    
  /* Delete old lines: */
  lcd.setLine(CLOCK_CENTER, 66, CLOCK_CENTER+sx, 66+sy, BACKGROUND);  // delete second hand
  lcd.setLine(CLOCK_CENTER, 66, CLOCK_CENTER+mx, 66+my, BACKGROUND);  // delete minute hand
  lcd.setLine(CLOCK_CENTER, 66, CLOCK_CENTER+hx, 66+hy, BACKGROUND);  // delete hour hand
  
  /* Calculate and draw new lines: */
  s = map(s, 0, 60, 0, 360);  // map the 0-60, to "360 degrees"
  sx = S_LENGTH * sin(3.14 * ((double) s)/180);  // woo trig!
  sy = S_LENGTH * cos(3.14 * ((double) s)/180);  // woo trig!
  lcd.setLine(CLOCK_CENTER, 66, CLOCK_CENTER+sx, 66+sy, S_COLOR);  // print second hand
  
  m = map(m, 0, 60, 0, 360);  // map the 0-60, to "360 degrees"
  mx = M_LENGTH * sin(3.14 * ((double) m)/180);  // woo trig!
  my = M_LENGTH * cos(3.14 * ((double) m)/180);  // woo trig!
  lcd.setLine(CLOCK_CENTER, 66, CLOCK_CENTER+mx, 66+my, M_COLOR);  // print minute hand
  
  midHours = minutes/12;  // midHours is used to set the hours hand to middling levels between whole hours
  h *= 5;  // Get hours and midhours to the same scale
  h += midHours;  // add hours and midhours
  h = map(h, 0, 60, 0, 360);  // map the 0-60, to "360 degrees"
  hx = H_LENGTH * sin(3.14 * ((double) h)/180);  // woo trig!
  hy = H_LENGTH * cos(3.14 * ((double) h)/180);  // woo trig!
  lcd.setLine(CLOCK_CENTER, 66, CLOCK_CENTER+hx, 66+hy, H_COLOR);  // print hour hand
}

2014/05/11

Arduino RF Wireless Message Display

As I am building the RF wireless power socket for home automation, I need a stand along tool to display any wireless received message. During the lab, I use Arduino serial monitor to monitor the message received once a second, error always happens at different time point as following screen shot shows. After disconnecting the Arduino Uno from PC to monitor message received by using LCD keypad shield as a stand along system, the error condition gone.
The RF wireless message display can be used to display the time on the NTP synchronized RTC clock (my projects during Aug 2013), so no additional time adjustment at display side is needed.


Parts Used

1. Arduino Uno R3
2. cheaphousetek LCD Keypad Shield
3. RF Receiver (described in Arduino Cookbook 14.1)

Connection

1. Stack LCD Key Keypad Upon Arduino Uno R3
2. RF Receiver Data Pin - Arduino Uno D11
3. RF Receiver Vcc - Arduino Uno 5V
4. RF Receiver Gnd - Arduino Uno Gnd

Photo


The sketch runs correctly with output to LCD shield for 247,610 times.



Sketch

/*
SimpleReceiveLCD
This sketch displays text strings received using VirtualWire
Connect the Receiver data pin to Arduino pin 11
*/
#include <VirtualWire.h>
// include the library code:
#include <LiquidCrystal.h>
byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message
unsigned long counter = 1;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup()
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
  lcd.clear();
  Serial.begin(9600);
  Serial.println("Device is ready");
  // Initialize the IO and ISR
  vw_setup(2000); // Bits per sec
  vw_rx_start(); // Start the receiver
}
void loop()
{
  if (vw_get_message(message, &messageLength)) // Non-blocking
  {
    lcd.clear();
    Serial.print(counter);
    Serial.print(": ");
    // set the cursor to column 0, line 1
    // (note: line 1 is the second row, since counting begins with 0):
    lcd.setCursor(0, 0);
    lcd.print(counter);
    lcd.print(":");
    lcd.setCursor(0,1);
    for (int i = 0; i < messageLength; i++)
    {
      Serial.write(message[i]);
      lcd.print(char(message[i]));
    }
    Serial.println();
    counter++;
  }
}

2014/02/28

Schematic For PCF8574 I2C LCD Keypad Shield Using LiquidCrystal_I2C.h Library

By using PCF8574 I2C port extender, the LCD Keypad Shield can be released 6 digital I/O ports used to control HD44780 compatible LCD by using only SDA and SCL (Arduino A4 and A5). Part of the following schematic is implemented on breadboard to show result on LCD module, run the example sketch of LiquidCrystal_I2C.h library by changing the address to 0x20, the result is showed on the following photo.


Schematic

Photo

Sketch

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define BACKLIGHT_PIN     13

LiquidCrystal_I2C lcd(0x20);  // Set the LCD I2C address

//LiquidCrystal_I2C lcd(0x38, BACKLIGHT_PIN, POSITIVE);  // Set the LCD I2C address

// Creat a set of new characters
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }  
};

void setup()
{
   int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));

  // Switch on the backlight
  pinMode ( BACKLIGHT_PIN, OUTPUT );
  digitalWrite ( BACKLIGHT_PIN, HIGH );
  
  lcd.begin(16,2);               // initialize the lcd 

   for ( int i = 0; i < charBitmapSize; i++ )
   {
      lcd.createChar ( i, (uint8_t *)charBitmap[i] );
   }

  lcd.home ();                   // go home
  lcd.print("Hello, ARDUINO ");  
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print (" FORUM - fm   ");
  delay ( 1000 );
}

void loop()
{
   lcd.home ();
   // Do a little animation by writing to the same location
   for ( int i = 0; i < 2; i++ )
   {
      for ( int j = 0; j < 16; j++ )
      {
         lcd.print (char(random(7)));
      }
      lcd.setCursor ( 0, 1 );
   }
   delay (200);
}


2013/12/29

Notes About PCF8574 I2C LCD Using LiquidCrystal_I2C.h


IC Manufacturer
NXP - PCF8574P, PCF8574AP
TI - PCF8574N

Library
LiquidCrystal_I2C.h by Francisco Malpartida download from BitBucket Repository

Address
I2C address of PC8574 (all three address inputs grounded) = 0x20
I2C address of PC8574A (all three address inputs grounded) = 0x38

Pins Mapping (16 Pins 8574) (Schematic)
PCF8574.Pin1 -> GND
PCF8574.Pin2 -> GND
PCF8574.Pin3 -> GND
PCF8574.Pin4 (Port0) -> LCD.Pin11 (DB4)
PCF8574.Pin5 (Port1) -> LCD.Pin12 (DB5)
PCF8574.Pin6 (Port2) -> LCD.Pin13 (DB6)
PCF8574.Pin7 (Port3) -> LCD.Pin14 (DB7)
PCF8574.Pin9 (Port4) -> LCD.Pin4 (RS)
PCF8574.Pin10 (Port5) -> LCD.Pin5 (WR)
PCF8574.Pin11 (Port6) -> LCD.Pin6 (EN)
PCF8574.Pin14 (SCL) -> UNO.A5
PCF8574.Pin15 (SDA) -> UNO.A4
PCF8574.Pin16 (VDD) -> UNO.5V
PCF8574.Pin8 (VSS) -> UNO.GND

LCD Initialization
#include <Wire.h> // comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20)
lcd.begin(16,2) // in Setup()

Variations (Yourduino)
   Marked "YwRobot Arduino LCM1602 IIC V1" -> lcd.begin(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE) // also SainSmart LCD2004, DFRobot (DZRMO)
   Marked "Arduino-IIC-LCD GY-LCD-V1" -> lcd.begin(0x20, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE)
   Marked "LCD1602 IIC A0 A1 A2" -> lcd.begin(0x20, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE)

Example Code (Yourduino)
/* YourDuino.com Example Software Sketch
 16 character 2 line I2C Display
 Backpack Interface labelled "YwRobot Arduino LCM1602 IIC V1"
 terry@yourduino.com */

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
// Get the LCD I2C Library here: 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>

/*-----( Declare Constants )-----*/
/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x20);  // Set the LCD I2C address

/*-----( Declare Variables )-----*/
//NONE

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);  // Used to type in characters

  lcd.begin(16,2);   // initialize the lcd for 16 chars 2 lines, turn on backlight

// ------- Quick 3 blinks of backlight  -------------
  for(int i = 0; i< 3; i++)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on  

//-------- Write characters on the display ------------------
// NOTE: Cursor Position: (CHAR, LINE) start at 0  
  lcd.setCursor(0,0); //Start at character 4 on line 0
  lcd.print("Hello, world!");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("HI!YourDuino.com");
  delay(8000);  

// Wait and then tell user they can start the Serial Monitor and type in characters to
// Display. (Set Serial Monitor option to "No Line Ending")
  lcd.clear();
  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("Use Serial Mon");
  lcd.setCursor(0,1);
  lcd.print("Type to display");  


}/*--(end setup )---*/


void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{
  {
    // when characters arrive over the serial port...
    if (Serial.available()) {
      // wait a bit for the entire message to arrive
      delay(100);
      // clear the screen
      lcd.clear();
      // read all the available characters
      while (Serial.available() > 0) {
        // display each character to the LCD
        lcd.write(Serial.read());
      }
    }
  }

}/* --(end main loop )-- */


/* ( THE END ) */

2013/08/15

Analog Sensor Data Logger


Create data file name:MMDDhhmm.CSV where M means month, D means day, h means hour and m means minute respectively. Once the reset on Arduino board is pressed, a new logger file is created.

An altenative is to use a DS1307 RTC shield (such as RTC Sensor Shield) and a SD shield.

This is the new version of the post on May 01, 2012 with the difference of using Time.h library.

Pin Used

Analog pin 3 is used for LM35 temperature sensor.
Analog pins 4 and 5 are used for I2C protocol implemented by Maxim DS1307.
Digital pins 10, 11, 12, 13 are used for SPI protocol to save data file to micro SD card.

Time.h Download

http://playground.arduino.cc//Code/Time

Sketch

// File Name: AnalogDataLoggerTimeLibrary.ino
// The sketch works on Arduino IDE 1.05
#include <SD.h>
#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#define analogSensorStart 3
#define analogSensorEnd 3

File file; // test file
const uint8_t SD_CS = 10; // SD chip select
String file_name = ""; // file name should not prefix with "prefix_word"
char fn[] = "MMDDHHMM.CSV";
int i=0;
int displayAtSecond = 0;
time_t t;

//------------------------------------------------------------------------------
// call back for file timestamps 
void dateTime(uint16_t* date, uint16_t* time) {
  time_t timeStamp = now();

  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(year(timeStamp), month(timeStamp), day(timeStamp));

  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(hour(timeStamp), minute(timeStamp), second(timeStamp));

//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Wire.begin();
  setSyncProvider(RTC.get); // the function to get the time from the RTC
  if (timeStatus() != timeSet)
    Serial.println("Unable to sync with the RTC");
    else
    Serial.println("RTC has set the system time");
    
  // set date time callback function
  SdFile::dateTimeCallback(dateTime);

  t = now();
  if (month(t) < 10) {
      file_name = String(file_name + '0' + String(month(t), DEC));
    }
    else {
    file_name = String(file_name +String(month(t), DEC));
    }
  if (day(t) < 10) {
      file_name = String(file_name + '0' + String(day(t), DEC));
    }
    else {
    file_name = String(file_name +String(day(t), DEC));
    }
  if (hour(t) < 10) {
      file_name = String(file_name + '0' + String(hour(t), DEC));
    }
    else {
    file_name = String(file_name +String(hour(t), DEC));
    }
  if (minute(t) < 10) {
      file_name = String(file_name + '0' + String(minute(t), DEC));
    }
    else {
    file_name = String(file_name +String(minute(t), DEC));
    }

  file_name = String(file_name + ".CSV");

  for (i=0;i<=file_name.length();i++) {
    fn[i] = file_name.charAt(i);
  }

  if (!SD.begin(SD_CS)) {
    Serial.println("SD failed");
    while(1);
  }
  Serial.print("File Name: ");
  Serial.println(fn);
}
//------------------------------------------------------------------------------
void loop()
{
  t = now();
  if (displayAtSecond != second(t)) {
    analogSensorDataLogger();
    displayAtSecond = second(t);
  }
}

void analogSensorDataLogger() { 
  String data_string = "";
  data_string = String(year(t), DEC);
  data_string += "/";
  if (month(t) < 10) {
      data_string = String(data_string + '0' + String(month(t), DEC));
    }
    else {
    data_string = String(data_string +String(month(t), DEC));
    }
  data_string += "/";
  if (day(t) < 10) {
      data_string = String(data_string + '0' + String(day(t), DEC));
    }
    else {
    data_string = String(data_string +String(day(t), DEC));
    }
  data_string += " ";
  if (hour(t) < 10) {
      data_string = String(data_string + '0' + String(hour(t), DEC));
    }
    else {
    data_string = String(data_string +String(hour(t), DEC));
    }
  data_string += ":";
  if (minute(t) < 10) {
      data_string = String(data_string + '0' + String(minute(t), DEC));
    }
    else {
    data_string = String(data_string +String(minute(t), DEC));
    }
  data_string += ":";  
  if (second(t) < 10) {
      data_string = String(data_string + '0' + String(second(t), DEC));
    }
    else {
    data_string = String(data_string +String(second(t), DEC));
    }
  data_string += ",";

  //read sensor value from A0-A3 and append to the string
  for (int analogPin = analogSensorStart; analogPin <= analogSensorEnd; analogPin++)
    {
    int sensor = analogRead(analogPin);
    data_string += String(sensor);
    if (analogPin < analogSensorEnd) {
      data_string += ",";
      }
    }
  
  file = SD.open(fn, FILE_WRITE);
  if (file) {
    file.println(data_string);
    file.close();
    Serial.println(data_string);
    }
    else {
      Serial.print("error opening ");
      Serial.println(fn);
    }
}

2013/08/04

NTP Server Synchronized LCD Keypad Adjustable Clock With Temperature Using Time.h Library

This sketch extend from post on Aug. 01, 2013 by adding synchronizing with NTP server.The Uno will synchronize with NTP server every 6 hours and override the time adjusted by using LCD shield keypad. An alternative to synchronize at certain time is to use Alarm.alarmRepeat() function in <TimAlarms.h>. The latency is about 2 seconds in my case, adjust the latency according your Internet connection condition. The binary sketch size is 19,614 bytes.

Requirements:

1. Arduino Uno R3
2. RTC (DS1307) Sensor Shield
3. W5100 Ethernet Shield
4. LCD Keypad Shield
5. LM35 Temperature Sensor Breakout

Usage

1. Use <RIGHT> keypad to enter set mode.
2. Use <RIGHT> to navigate on parameter to be modified.
3. Use <UP> to set value of the aimed parameter.

4. Use <DOWN> to set value of the aimed parameter.
5. Use <SELECT> to save date and time to RTC.
6. Use <LEFT> to leave set mode.


Schetch

/*
 * TimeRTC.pde
 * example code illustrating Time library with Real Time Clock.
 * the sketch works on Arduino IDE 1.05
 * 1) modified by Befun Hung on Jul. 28, 2013 
 *    changing the sequence to year, month, day, hour, minute, second
 *    adding the day of week
 *    almost same function as sketch on May 1, 2012
 * 2) modified by Befun Hung on Jul. 29, 2013
 *    change display device to LCD Shield
 *    adding temperature readout from LM35
 *    the sketch does not contain delay() in the loop section 
 * 3) modified by Befun Hung on Jul. 31, 2013
 *    divide digitalClockDisplay() into dateDisplay(), weekdayDisplay(), timeDisplay() and temperatureDisplay()
 *    use time_t t to store the value of now()
 * 4) modified by Befun Hung on Aug. 04, 2013
 *    adding ntpSyncDS1307() to synchronize DS1307 real time clock with NTP server
 */

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7);

#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5

char *dayOfWeek[] = {"", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
int lcdKey = 0;
int adcKeyIn = 0;
time_t t;
int potPin = 3; // change potPin value to 0, 1, 2 for A0, A1, A2 respectly
float temperature = 0;
int displayAtSecond;

// Enter a MAC address for your controller bellow.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
unsigned int localPort = 8888; // local port to listen for UDP packets
IPAddress timeServer(140, 112, 2, 188); // ntp2.ntu.edu.tw NTP server
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// timeZoneOffset = (Time Zone) * 3600L eg. (+8) * 3600L = 28800L for Taipei, Taiwan
const long timeZoneOffset = 28800L; 
// sync to NTP server every "ntpSyncTime" seconds, set to 1 hour or more to be reasonable
unsigned long ntpSyncTime = 21600;
// keep track of how long ago we updated the NTP server
unsigned long ntpLastUpdate = 0;
// adjust the sync latency with computer NTP client in seconds 
unsigned int syncLatency = 2;

void setup()  {
  lcd.begin(16,2);
  lcd.print("*cheaphousetek*");
  lcd.setCursor(0,1);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     lcd.print("Unable to sync");
  else
     lcd.print("Sync system time ");
  displayAtSecond = second();
  delay(2000);
  lcd.clear();
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    lcd.setCursor(0,1);
    lcd.print("DHCP failed");
    for (;;);
  }
  Udp.begin(localPort);
}

void loop()
{
  if ((now() - ntpLastUpdate) >= ntpSyncTime) {
    ntpSyncDS1307();
  }
  // for reading keypad stroke to set the date and time once the RIGHT is pressed
  t = now();
  lcdKey = readLCDButton();
  if (lcdKey == btnRIGHT) {
    keypadSetDateTime();
  }
  // for LCD shield to disp date, day of the week, time and temperature once a second
  if (displayAtSecond != second(t)) { 
    digitalClockDisplay(); 
    displayAtSecond = second(t); 
  }
}

int readLCDButton() {
  adcKeyIn = analogRead(0);
  delay(200);
  // read the value from the sensor
  // my buttons when read are centered at these values: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adcKeyIn > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adcKeyIn < 73) return btnRIGHT;
  if (adcKeyIn < 237) return btnUP;
  if (adcKeyIn < 415) return btnDOWN;
  if (adcKeyIn < 623) return btnLEFT;
  if (adcKeyIn < 882) return btnSELECT;
  return btnNONE; // when all others fail, return this...
}

void digitalClockDisplay(){
  // digital clock display of the time
  dateDisplay();
  weekdayDisplay();
  timeDisplay();
  temperatureDisplay();  
}

void dateDisplay() {
  lcd.setCursor(0,0);
  lcd.print(year(t));
  lcd.print('-');
  if (month(t) < 10) {
    lcd.print('0');
  }
  lcd.print(month(t));
  lcd.print('-');
  if (day(t) < 10) {
    lcd.print('0');
  }
  lcd.print(day(t));
  // lcd.print(' ');
}

void weekdayDisplay() {
  lcd.setCursor(11,0);
  lcd.print(dayOfWeek[weekday()]);
}

void timeDisplay() {
  lcd.setCursor(0,1);
  if (hour(t) < 10) {
    lcd.print('0');
  }
  lcd.print(hour(t));
  lcd.print(':');
  if (minute(t) < 10) {
    lcd.print('0');
  }
  lcd.print(minute(t));
  lcd.print(':');
  if (second(t) < 10) {
    lcd.print('0');
  }
  lcd.print(second(t));
  // lcd.print(' ');
}

void temperatureDisplay() {
  int span = 10;
  long aRead = 0;
  unsigned long temp;
  
  for (int i=0;i<span;i++) {
    aRead = aRead + analogRead(potPin);
  }
  temperature = (aRead / span * 500.0 / 1024.0); // for other analog sensor change the constants
  printTenths(long (temperature * 10));
  lcd.setCursor(14,1);
  lcd.print(char(223));
  // lcd.setCursor(15,1);
  lcd.print('C'); 
}

void printTenths(long value) {
  // prints a value of 123 as 12.3
  lcd.setCursor(10,1);
  lcd.print(value / 10);
  lcd.setCursor(12,1);
  lcd.print('.');
  lcd.setCursor(13,1);
  lcd.print(value % 10);
}

void keypadSetDateTime() {
  int setYear=year(t), setMonth=month(t), setDay=day(t), setHour=hour(t), setMinute=minute(t), setSecond=second(t);
  int setVariable=0, checkStatus=0;
  
  dateDisplay();
  timeDisplay();
  while(true) {
    lcdKey = readLCDButton();
    switch(lcdKey) {
      case btnNONE:
      {
        lcd.blink();
        if (setVariable == 0) lcd.setCursor(3,0);
        if (setVariable == 1) lcd.setCursor(6,0);
        if (setVariable == 2) lcd.setCursor(9,0);
        if (setVariable == 3) lcd.setCursor(1,1);
        if (setVariable == 4) lcd.setCursor(4,1);
        if (setVariable == 5) lcd.setCursor(7,1);
        break;
      }
      case btnRIGHT:
      {
        setVariable = (setVariable + 1) % 6;
        break;
      }
      case btnLEFT:
      {
        lcd.noBlink();
        lcd.clear();
        return;
      }
      case btnUP:
      {
        if (setVariable == 0) {
          setYear = ((setYear + 1) % 100) + 2000;
          lcd.setCursor(0,0);
          lcd.print(setYear);
        }
        if (setVariable == 1) {
          setMonth = (setMonth % 12) + 1;
          lcd.setCursor(5,0);
          if (setMonth < 10) {
            lcd.print('0');
            lcd.print(setMonth);
          }
          else {
            lcd.print(setMonth);
          }
        }
        if (setVariable == 2) {
          setDay = (setDay % 31) + 1;
          lcd.setCursor(8,0);
          if (setDay < 10) {
            lcd.print('0');
            lcd.print(setDay);
          }
          else {
            lcd.print(setDay);
          }
        }
        if (setVariable == 3) {
          setHour = (setHour + 1) % 24;
          lcd.setCursor(0,1);
          if (setHour < 10) {
            lcd.print('0');
            lcd.print(setHour);
          }
          else {
            lcd.print(setHour);
          }
        }
        if (setVariable == 4) {
          setMinute = (setMinute + 1) % 60;
          lcd.setCursor(3,1);
          if (setMinute < 10) {
            lcd.print('0');
            lcd.print(setMinute);
          }
          else {
            lcd.print(setMinute);
          }
        }
        if (setVariable == 5) {
          setSecond = (setSecond + 1) % 60;
          lcd.setCursor(6,1);
          if (setSecond < 10) {
            lcd.print('0');
            lcd.print(setSecond);
          }
          else {
            lcd.print(setSecond);
          }
        }
        break;
      }
      case btnDOWN:
      {
        if (setVariable == 0) {
          setYear = ((setYear - 1) % 100) + 2000;
          lcd.setCursor(0,0);
          lcd.print(setYear);
        }
        if (setVariable == 1) {
          setMonth = ((setMonth - 1) % 12);
          if (setMonth == 0) {
            setMonth = setMonth + 12;
          }
          lcd.setCursor(5,0);
          if (setMonth < 10) {
            lcd.print('0');
            lcd.print(setMonth);
          }
          else {
            lcd.print(setMonth);
          }
        }
        if (setVariable == 2) {
          setDay = ((setDay - 1) % 31);
          if (setDay == 0) {
            setDay = setDay + 31;
          }
          lcd.setCursor(8,0);
          if (setDay < 10) {
            lcd.print('0');
            lcd.print(setDay);
          }
          else {
            lcd.print(setDay);
          }
        }
        if (setVariable == 3) {
          setHour = (setHour - 1 + 24) % 24;
          lcd.setCursor(0,1);
          if (setHour < 10) {
            lcd.print('0');
            lcd.print(setHour);
          }
          else {
            lcd.print(setHour);
          }
        }
        if (setVariable == 4) {
          setMinute = (setMinute - 1 + 60) % 60;
          lcd.setCursor(3,1);
          if (setMinute < 10) {
            lcd.print('0');
            lcd.print(setMinute);
          }
          else {
            lcd.print(setMinute);
          }
        }
        if (setVariable == 5) {
          setSecond = (setSecond - 1 + 60) % 60;
          lcd.setCursor(6,1);
          if (setSecond < 10) {
            lcd.print('0');
            lcd.print(setSecond);
          }
          else {
            lcd.print(setSecond);
          }
        }
        break;
      }
      case btnSELECT:
      {
        if ((setMonth == 1 || setMonth == 3 || setMonth == 5 || setMonth == 7 || setMonth == 8 || setMonth == 10 || setMonth == 12) && setDay <= 31) checkStatus = 1;
        if ((setMonth == 4 || setMonth == 6 || setMonth == 9 || setMonth == 11) && setDay <=30) checkStatus = 1;
        if ((setMonth == 2 && (setYear % 4) == 0) && setDay <= 29) checkStatus = 1;
        if ((setMonth == 2 && (setYear % 4) != 0) && setDay <= 28) checkStatus = 1;
        if (checkStatus) {
          setTime(setHour, setMinute, setSecond, setDay, setMonth, setYear);
          RTC.set(now());
        }
        break;
      }
    }
  }
}

void ntpSyncDS1307() {
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait to see if a replay is available
  delay(1000);
  if (Udp.parsePacket()) {
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
    // the timstamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract 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;
    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800L;
    // substract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears + timeZoneOffset + syncLatency;
    setTime(epoch);
    RTC.set(epoch);
    ntpLastUpdate = now();
  }
}

// send an NTP request to the time server at the given address
unsigned long 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 clodk
  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);
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}