Chapter 9: Keeping Time



We have looked at keeping time with computers several times in earlier Smiley's Workshops, prior to the Arduino 101 series. These articles are not quite as novice friendly as the Arduino 101 series, but they contain a lot of information about computer time that the more curious reader might want to read to get more low level detail than we will see in this article. The first article: Smiley's Workshop 48: It's about time was published in the July 2012 Nuts&Volts magazine and can also be found in the www.smileymicros.com articles and downloads section. That article had some general C programming theory and then discussed a design for a PCB with the DS1307 RTC (Real Time Clock) and how to use it with an Arduino. Next there is a series of articles Smiley's Workshops 54, 55, 56 and 57 in Nuts&Volts where we greatly expanded on the RTC by building an alarm clock with a C# based PC side application that works in concert with an Arduino Proto Shield Alarm Clock. These articles were published in the January, February, March and April 2013 Nuts&Volts and are available on the Smiley Micros web site. There are also projects kits for these articles available from the Nuts&Volts web store. In this article we will that a much higher level look at computer time keeping and learn to use some very novice friendly applications available for the Arduino.

You can download the Arduino source code for this chapter from:
a101_ch9_supplemental.zip


 

Chapter 9: Keeping Time



We have looked at keeping time with computers several times in earlier Smiley's Workshops, prior to the Arduino 101 series. These articles are not quite as novice friendly as the Arduino 101 series, but they contain a lot of information about computer time that the more curious reader might want to read to get more low level detail than we will see in this article. The first article: Smiley's Workshop 48: It's about time was published in the July 2012 Nuts&Volts magazine and can also be found in the www.smileymicros.com articles and downloads section. That article had some general C programming theory and then discussed a design for a PCB with the DS1307 RTC (Real Time Clock) and how to use it with an Arduino. Next there is a series of articles Smiley's Workshops 54, 55, 56 and 57 in Nuts&Volts where we greatly expanded on the RTC by building an alarm clock with a C# based PC side application that works in concert with an Arduino Proto Shield Alarm Clock. These articles were published in the January, February, March and April 2013 Nuts&Volts and are available on the Smiley Micros web site. There are also projects kits for these articles available from the Nuts&Volts web store. In this article we will that a much higher level look at computer time keeping and learn to use some very novice friendly applications available for the Arduino.

You can download the Arduino source code for this chapter from:
a101_ch9_supplemental.zip


Keeping Time with the Arduino


Before we begin let it be known that a raw Arduino isn't all that good at keeping clock time. It may gain or lose several seconds in a day, which is just fine for some of the applications we will do later in Arduino 101 where we record data for no more than a day. If you really need long term accuracy then refer to the above mentioned articles.

Computer Time


In case you didn't know, time began on January 1, 1970. Or at least Unix time began then and since that auspicious moment many computers have counted the seconds. As of September 1, 2014 the count is 1,409,529,600 or about one and a half billion seconds. [This factoid courtesy of http://www.epochconverter.com/epoch/timestamp&#45list.php] That, folks, is one whopping big number! But it can be stored in a 32&#45bit integer, which is a measly four bytes of data.

The world will end in 2038


Using Unix time, everything will be just fine &#45 until 2038 when the seconds exceed the capacity of a 32-bit integer and time will end! Sort of like it did in 2012 when the Mayan calendar ended and so did the world. Except of course it didn't, the Mayans merely started their calendar over again or would have if it hadn't been for that conquistador thing. We can expect the 2038 problem to be much like the Y2K (Year 2000) timekeeping problem that was going to bring the world, as we knew it, to a screeching halt, according to the media hysterics - only it didn't. It did, however, employ a bunch of programmers for a few years, and the Y2.038K problem will probably do the same.

In the meantime…


Unix provided C functions and data types that let's folks express those Unix time seconds as more meaningful (to us) units such as calendar dates and clock times. This can get fairly arcane and fortunately, like many other complex computing problems, some generous folks have given us an Arduino library - Time - that makes things much easier for us. We will install this library in the Arduino directory in Lab 1.

The Time library provides timekeeping functionality using the Arduino by it self, or with external timekeeping devices such as the DS1307 RTC. You can write code to get the time and date as second, minute, hour, day, month and year. And it lets us keep time in the earlier mentioned Unix time seconds which is more convenient to handle and store than traditional date and time notations. Also it lets us set up alarms. Rather than repeating all the functions here, please refer to http://playground.arduino.cc/Code/Time. Don't worry though if this seems a bit much, we will only be using a subset of what is available and we will keep it as simple as possible to fulfill our meager requirements. We will, however, use a brand-new program - to us anyway - that will let us set the time on the Arduino very accurately. This program is Processing, and as we will see in a moment, it looks kind of familiar…

Processing


The Processing IDE is shown in Figure 1. Look familiar? It should because the Arduino IDE is built from a version of Processing.

Figure 1: Processing IDE



You will want to visit processing.org and take a look at all the marvelous things Processing is used for. It was developed initially to provide a simple set of tools so that artists could use some of the visual tools that were becoming available in Java. Fortunately since Processing is artist-simple to use and the Arduino IDE is based on it, we won't have to learn much new stuff to use it. In Lab 2 we will use a Processing module provided by the folks that wrote the Time library that lets us use the PC to set the time on the Arduino.

Lab 1: Using the Arduino Time library


The Time library is not part of the standard Arduino download, so you'll have to download it and set it up yourself. After downloading the library we will write code to let us set the date and time.

Parts Required:
1 Arduino
1 Computer with Internet connection

Estimated time for this lab: 20 minutes

Check off when complete:
You can get the Time.zip file at http://playground.arduino.cc/Code/Time. Download this file and unzip it. This will provide a Time directory.
Next find your Arduino directory (usually in drive C:, for instance I have Arduino 1.0.5 located at C:/Arduino105).
Copy the Time directory to the Arduino libraries directory. Figure 2 shows my Windows Explorer with the file copied to the correct directory. It must be in the libraries directory for the Arduino IDE to find library.

Figure 2: Put Time in the libraries directory



Next you want to verify that The Arduino IDE can find the Time library. Open the Arduino IDE. Open the Arduino IDE and then click on the Sketch/Import Library menu item. You should see the Time library as shown in Figure 3. This verifies that you have successfully added the library to the Arduino directory.

Figure 3: Import Time



Click on 'Time' it will add #include to your source code as shown in Figure 4. You are now ready to write code that will use the Time library.

Figure 4: Add Time header



Open the File/Examples/Time/Examples/TimeSerial as shown in Figure 5.

Figure 5: Select TimeSerial example



In the Setup() function change the baud rate from 9600 to 57600.
In the requestSync() function, remove the 'BYTE' parameter from the Serial.print() function.
Run the program and open the Serial Monitor. You will see the message: "7Waiting for sync message" displayed as shown in Figure 7.
In a computer browser open http://www.unixtimestamp.com/ as shown in Figure 6.

Figure 6: unixtimestamp.com


QUICKLY copy the Unix time value, which was 1405096354 when I did this exercise as shown in Figure 7.
ALSO QUCKLY paste this value into the Serial Monitor output box preceded by a 'T' as shown in Figure 7. The QUICKLY is because the seconds that it takes to copy, paste and send the Unix time will create an offset of several seconds between the real time, in the opinion of the PC, and the time learned by the Arduino.
NOTE: months later when I retried this the value would not paste into the Serial Monitor so I had to type the T followed by the timestamp numbers to get this to work.

Figure 7: Send Unix timestamp to the Arduino



The Serial Monitor will begin to display the time and date as shown in Figure 8.
Note that the time is expressed as a 24-hour clock also known as military time.
Also note that the time is UTC, Coordinated Universal Time that is more or less synonymous with Greenwich Mean Time (GMT).
Note that converting UTC to your time zone (if you live in the USA) requires considering daylight savings time. I live in the Eastern time zone which is UTC-5:00, but since daylight savings time is in effect it is actually UTC-4:00. The time shown in Figure 8, 16:32 was UTC-4:00 or 16:32 - 4:00 = 12:32.

Figure 8: Data and time on the Serial Monitor

 

Lab 2: Using Processing to set the Arduino time.


Hand typing the Unix timestamp is not so hard, but chances are you will not get the exact seconds this way. You could add a couple of seconds to the total, but you could also use Processing to set it more accurately than you can by hand.

Parts Required:
1 Arduino
1 Computer with Internet connection

Estimated time for this lab: 20 minutes

 Check off when complete:
Download Processing 2 from www.processing.org. This application is large so the download may take a while.
Open the Processing IDE as shown in Figure 9.

Figure 9: Open the Processing IDE


NOTE: After publishing this page several folks had trouble as reported in the forum at:
http://arduinoclassroom.com/index.php/forum/welcome-mat/320-chapter-9-lab-2
Folks using the iMac can modify the following as pointed out by rocketscientist on that forum thread:
OK. I got it to work on my iMac. I made the changes you suggested, and instead of using "COM#", I entered "/dev/tty.usbmodemfd141" which is the serial port on my machine. I get a nice steady stream of time stamps increasing by 1 second in the Processing IDE black window.
When folks have problems with the Arduino Classroom and then persist to find a solution - they make this website more valuable for all users everwhere!


Either cut and paste, or type in the following program into the Processing IDE. [Or open the a101_ch9_receive_serial.pde program - note this file is located in a101_ch9_supplemental.zip that you can find on the Nuts&Volts web site page for this article and on the www.arduinoclassroom.com Chapter 9 web page.]

  
// a101_ch9_receive_serial.pde Joe Pardue 7/11/14
// Processing program to receive strings from the Arduino

import processing.serial.*;

Serial mySerial;  // Create object from Serial class
String input;     // Data received from the serial port

void setup()
{
  // Find the COM port you are using by looking in the Arduino
  // Tools/SerialPort menu item.
  mySerial = new Serial(this, "COM5", 57600); 
}

void draw()
{
  if ( mySerial.available() > 0) 
  {   // If data is available,
// put it in the input string
    input = mySerial.readStringUntil('\n'); 
  } 
  println(input); //print it out in the console
}


Leave the Processing IDE open, but do not run the program yet.
Either cut and paste, or type in the following program into the Processing IDE. [Or open the a101_ch9_hello_world.ino program - note this file is located in a101_ch9_supplemental.zip that you can find on the Nuts&Volts web site page for this article and on the www.arduinoclassroom.com Chapter 9 web page.]

  
// a101_ch9_hello_world.ino Joe Pardue 7/11/14

void setup() 
{
  Serial.begin(57600);
}
void loop()
{
  Serial.println("Hello, world!"); // send Hello, world!
  delay(250); // pause for 1/4 second
}


Compile and run the Arduino program first.
In the Processing program line: mySerial = new Serial(this, "COM6", 57600); make certain that the COM# is the one you are actually using
Compile and run the Processing program second.
The order is important because the Arduino has to open the COM port first.
You will see the Processing console (the black area at the bottom of the Processing IDE) begins to print "Hello, world!" as shown in Figure 10.

Figure 10: Processing receive serial



Now that you have tested the Processing and Arduino serial connections, reload the Arduino TimeSerial example shown in Lab 1. Compile and run that program

NOTE: THIS DUPLICATES MATERIAL IN THE PRIOR LAB AND IS REPEATED TO HELP REINFORCE LEARNING.

In the Processing IDE load the SyncArduinoClock program that is located in a101_ch9_supplemental.zip that you can find on the Nuts&Volts web site page for this article and on the www.arduinoclassroom.com Chapter 9 web page.] We will not discuss this file since it uses some features that are beyond the scope of this article.

In the SyncArduinoClock directory you will find a readme.txt file that says the following:
SyncArduinoClock is a Processing sketch that responds to Arduino requests for
time synchronization messages.

The portIndex must be set the Serial port connected to Arduino.

Download TimeSerial.pde onto Arduino and you should see the time
message displayed when you run SyncArduinoClock in Processing.
The Arduino time is set from the time on your computer through the
Processing sketch.

MAKE CERTAIN YOU SUBSTITUTE THE SERIAL PORT THAT THE ARDUINO IS USING FOR THE PORTINDEX IN THE SYNCARDUINOCLOCK Setup() MODULE.

Run SyncArduinoClock in Processing and you will see a blank window appear as shown in Figure 11.
Click on this window and the correct time will be sent to the Arduino, which will then print the date and time to the Processing console as we see in Figure 11.

Figure 11: Run Processing SyncArduinoClock

 

Lab 3: One numeral clock


Now that we can tell the time, what if we don't have a PC with a USB serial connection to send that time out to a serial terminal? Well we could display the time on the Arduino using the 7&#45segment LED. But, you may well ask, how can we display all that information on a single digit display? We could do something similar to what we learned in Lab 5 of Chapter 8 where we built "The World's Smallest Moving Message Sign?" And we could then display the hour, minute and second, say 1:35:12, as H01 M35 S12. By controlling the timing of the character output, this makes a nominally readable display if you know what you are looking for and pay attention.

Parts Required:
1 Arduino
1 Computer with Internet connection
1 Arduino Proto Shield and jumper wires
1 7-segment LED
1 100 ohm resistor

Estimated time for this lab: 1 hour

Check off when complete:
Build the circuit shown in Chapter 8 Lab 4. The Figures from that lab are repeated here in Figures 12, 13 and 14 for your convenience. Notice that this circuit uses a single 100 ohm resistor between the 7-segment LED anode pin 3 and the 5-volt power supply.

Figure 12: 7-seg LED breadboard

 

Figure 13: 7-seg LED schematic

 

Figure 14: 7-seg LED photo



Either cut and paste, or type in the following program into the Arduino IDE. [Or open the a101_ch9_time_display.ino program - note this file is located in a101_ch9_supplemental.zip that you can find on the Nuts&Volts web site page for this article and on the www.arduinoclassroom.com Chapter 9 web page.]


  
// a101_ch9_time_display.pde Joe Pardue 7/13/14
// Modification of TimeSerial.ped
 
#include  

// time sync to PC is HEADER 
// followed by unix time_t as ten ascii digits
#define TIME_MSG_LEN  11   
// Header tag for serial time sync message
#define TIME_HEADER  'T'   
// ASCII bell character requests a time sync message 
#define TIME_REQUEST  7    

byte integer[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 
                  0x6D, 0x7D, 0x07, 0x7F, 0x6F,
                  0x08};
byte character[] = {0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71,
                    0x6F, 0x76, 0x30, 0x1E, 0x70, 0x38,
                    0x15, 0x54, 0x3F, 0x73, 0x67, 0x50, 
                    0x6D, 0x78, 0x3E, 0x1C, 0x2A, 0x46, 
                    0x6E, 0x52};

#define DPMASK 0x80
#define GMASK 0x40
#define FMASK 0x20
#define EMASK 0x10
#define DMASK 0x08
#define CMASK 0x04
#define BMASK 0x02
#define AMASK 0x01

#define DPPIN 9
#define GPIN 13
#define FPIN 12
#define EPIN 6
#define DPIN 7
#define CPIN 8
#define BPIN 10
#define APIN 11

#define PAUSE 500

// lowest segment starts with LED 6
// hightest segment ends with LED 12
int low = 6;
int high = 13;

void setup()  {
  
   // Set LED pin modes to output
  for(int i = low; i <=high; i++){
    pinMode(i, OUTPUT);
  }  
  
  Serial.begin(57600);
  Serial.println("a101_ch8_time_display rev 1.0");  
  //set function to call when sync required
  setSyncProvider( requestSync);  
  Serial.println("Waiting for sync message");
}

void loop(){    
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)   
  {
    // on if synced, off if needs refresh  
    digitalWrite(13,timeStatus() == timeSet); 
    sevenSegDisplay();  
  }
  delay(1000);
}

//********************************************//
// Functions to display the time on the 7-seg LED
//********************************************//
void sevenSegDisplay(){ 
  // show the hour
  setLEDs('H');
  delay(PAUSE);
  showDigits(hour());
  delay(PAUSE*2);
  
  // show the minute
  setLEDs('M');
  delay(PAUSE);
  showDigits(minute());
  delay(PAUSE);     
 
   // show the second
  setLEDs('S');
  delay(PAUSE);
  showDigits(second());
  delay(PAUSE);  
}

// Display all time values as two digits
// use leading 0 if value less than 10
void showDigits(int digits){
  int high, low;
  
  if(digits > 59) high = 6;
  else if(digits > 49) high = 5; 
  else if(digits > 39) high = 4; 
  else if(digits > 29) high = 3; 
  else if(digits > 19) high = 2; 
  else if(digits > 9) high = 1; 
  else high = 0;
  
  low = digits - (high*10);
  
  setLEDs(high+48);
  delay(PAUSE);
  setLEDs(low+48);
  delay(PAUSE);
}

void setLEDs(int input){
  // verify input is integer or character
  if( (input > 47) & (input < 58) )
  { 
    input = integer[input - 48];
  } 
  else if ( (input > 64) & (input < 91) ) 
  { 
   input = character[input - 65]; 
  } 
  else // it isn't an integer or character
  {
   return; // do nothing if invalid input 
  }
  
  // Turn the segments on or off
  digitalWrite(DPPIN,!(DPMASK&input));
  digitalWrite(GPIN,!(GMASK&input));
  digitalWrite(FPIN,!(FMASK&input));
  digitalWrite(EPIN,!(EMASK&input));
  digitalWrite(DPIN,!(DMASK&input));
  digitalWrite(CPIN,!(CMASK&input));
  digitalWrite(BPIN,!(BMASK&input));
  digitalWrite(APIN,!(AMASK&input));
}

//********************************************//
// Functions to synchronize the time
//********************************************//
void processSyncMessage() {
  // if time sync available from serial port, update time
  // time message consists of a header and ten ascii digits
  while(Serial.available() >=  TIME_MSG_LEN ){  
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){
          // convert digits to a number
          pctime = (10 * pctime) + (c - '0') ;     
        }
      } 
      // Sync Arduino clock to time from the serial port
      setTime(pctime);   
    }  
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST); 
  // the time will be sent later in response to serial mesg
  return 0; 
}

Compile and run the program.
Do you find it easy to read the hours, minutes and seconds?

Lab 4: Cut the apron strings


So far we have used the Arduino tethered to the PC. This provides both power and a convenient way to program and talk to the Arduino. But we do have to ask, what is the use of learning about how to put time on the Arduino if it is can always get the time from the PC? And, of course, there isn't any reason to. We would only want to occupy the Arduino with the chore of keeping time if it is detached from a PC, say sitting out in the garden soaking up the sunshine while leisurely gathering data about the weather. If, say it takes the temperature every five minutes, it will need to know when five minutes have passed. And it will need to know which particular five minutes in a day of lots of five-minute intervals that this particular five minutes occurred. But since it isn't attached to a PC out in the garden, where will it get its power? From a battery of course, and the Arduino has a barrel connector so you can power it with a 9&#45volt battery using a snap connector as shown in Figure 15. You can get one at: http://www.adafruit.com/products/80.

Figure 15: 9-volt battery connector



You connect the 9-volt battery as shown in Figure 16, and you are now ready to run your Arduino away from your PC.

Figure 16: Arduino connected to 9-volt battery



This process of gathering information external to a computer is called data logging and it is used to record sensor readings over known intervals at known dates and times. In later chapters we will learn how to use sensors, but first we will learn how to keep time so that we can log record the sensor data and know when we took our readings.

Parts Required:
1 Arduino
1 Computer with Internet connection
1 9-volt with barrel and snap connections
1 9-volt battery

Estimated time for this lab: 15 minutes (+24 hours)

Check off when complete:
Attach a 9-volt battery to the snap connections as shown in Figure 15.
Plug the 9-volt battery to the Arduino barrel connector as shown in Figure 16.
Calibrate the clock as you did in Lab 2.
Remove the USB connector and wait 24 hours.
DO NOT plug in the USB cable. If you attempt to contact the Arduino via USB it will reset and you will lose the time and have to start over.
Refer to your PC time clock for the correct time and then compare this to the time being displayed on Arduino.
What is your error in seconds per day?

As we said earlier, this isn't a particularly accurate clock. In order to get really good accuracy you'll need to use an external RTC (Real Time Clock) like what was discussed in the Smiley's Workshops mentioned above. However, as we will see when we look at data logging, our clock is good enough to time a day's worth of measurements and you can resync it each day when you upload the data you have logged.