Sensor Examples

This is a collection of Arduino code examples.  Some good techniques mixed with some questionable.  Take the best and leave the rest.  Everything is GPL3.


Date/Time with Local Temperature (for Mega)


 What it is called:Date/Time with Local Temperature (for Mega)
 What it does:Displays the time, date and day of the week on first line of the LCD, and shows the local temperature on the second line which alternates every 3 seconds from degrees C to degrees F  
 What it takes:Mega (easy to modify for any board), TMP36 temperature sensor, serial LCD (can be modified for parallel) 
 What pins are used:Digital 2, Analog 0, Serial TX1 (18) 
 What libraries: Metro, Time

Parts:

Display Example:





Wiring:



Code & Comments:

Look at the real time clock example for a better way to set the clock on a regular basis.

/*
 Time and Temperature Display Using a Serial LCD with an Arduino Mega
 Uses Serial1 - temp in F/C with TMP36 - 9600 baud
 from http://sites.goggle.com/site/MeasuringStuff
 follow these steps:
 1. upload and wait for LED 13 to light (steady)
 2. open serial monitor and place epoch time in the send box preceded by a T, e.g. T127093930, press send, then a T will be sent back
 (you can get the unix time from  http://www.epochconverter.com/  )
 3. push the button connected to pin 2 (takes it high) to start the endless loop
 displays time date day and temperature in deg C and F
 */

// ----------------------- include libraries / defines ------------------
#include <Time.h>
#include <Metro.h>

// straight from the library example
// T1262347200 is noon Jan 1 2010 see epochconverter.com for current unix time display
#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by Unix time_t as ten ASCII digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

// --------------------- global variables -------------------------------

byte ledPin =  13;
byte letsStartPin = 2;
char theDay[22]="SunMonTueWedThrFriSat";
char mon[37]="JanFebMarAprMayJunJulAugSepOctNovDec";
Metro line1Refresh = Metro(1000); 
Metro line2Refresh = Metro(5000);
byte toggleFlag=0;
float tempF;
float tempC;
// checks to see if you bypassed the serial time setup step
byte realTimeInputFlag=0;
//unix time is UTC - correct as necessary in units of seconds
long int timeCorrection=(-4*3600);
//collect the last 20 (depth) temp samples and display inc(reasing) or dec(reasing) on temp display
byte atvDepth=20;
byte atv[20];
byte atvKounter=0;
int atvAvg;


// ------------------------- start setup ---------------------------------
void setup() {

  // first initialize both serial ports:
  Serial.begin(9600);
  Serial1.begin(9600);
  backlightOn();
  clearLCD();

  // next signal ready to start by turning on LED 13 
  // also set pin 2 to LOW
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  pinMode(letsStartPin,INPUT);

  // loop waits until you enter unix time in the following format T1262347200 from the serial monitor
  // and responds by sending back the T character (a library function of proecessSyncMessage
  // it then continues looping until letsStartPin goes high (must press the button and make digital pin 2 go high!);
  do { 
    if(Serial.available()) 
    {
      processSyncMessage();
      realTimeInputFlag=1;
    }
  } 
  while (digitalRead(letsStartPin) == LOW);

  // housekeeping things and use Jan 1 2000 (with -4 hour correction) if you don't feel like setting the clock
  if (realTimeInputFlag==0){
    setTime(946684800);
    Serial.println(realTimeInputFlag);
  }
  digitalWrite(ledPin, LOW);  
}
// ------------------------- end setup ------------------------------------

// ------------------------------------------------------------------------
// ------------------------- endless loop ---------------------------------
// ------------------------------------------------------------------------
void loop() {
  if (line1Refresh.check() == 1) {
    clearLCD();
    printTime();
    printTemp();
  }
  if (line2Refresh.check() == 1) {
    if (toggleFlag==0){
      toggleFlag=1;
    }
    else {
      toggleFlag=0;
    } 
  }
}
// ------------------------------------------------------------------------
// ----------------- end of endless loop ----------------------------------
// ------------------------------------------------------------------------

// ----------------- subroutine calls -------------------------------------

// -------- Time & Temperature printing and flag toggling ------------------------

void printTime() {
  selectLineOne();
  Serial1.print(hour());
  printDigits(minute());
  //printDigits(second());
  Serial1.print(" ");
  byte qq=((weekday()-1)*3);
  Serial1.print(theDay[qq]);
  Serial1.print(theDay[qq+1]);
  Serial1.print(theDay[qq+2]);
  Serial1.print(" ");
  Serial1.print(day());
  Serial1.print(" ");
  byte q=(month()-1)*3;
  Serial1.print(mon[q]);
  Serial1.print(mon[q+1]);
  Serial1.print(mon[q+2]);
  Serial1.print(" ");
}

void printTemp() {
  int analog0=analogRead(0);
  float volts=(analog0/1023.0)*5.02;
  tempC=100.*volts-50.;
  tempF=tempC*9./5.+32.;
  if (atvKounter>=atvDepth)
  {
    atvKounter=0;
  }
  else
  {
    atvKounter++;
  }
  // use map to save some memory for this noncritical calc
  analog0=map(analog0,0,1023,0,255);
  atv[atvKounter]=byte(analog0);
  atvAvg=0;
  for (byte i=0;i<atvDepth;i++)
  {
    atvAvg=atvAvg+int(atv[i]);
  }
  atvAvg=atvAvg/atvDepth;
  selectLineTwo();
  if (toggleFlag==0) 
  {
    Serial1.print(tempF,1);
    Serial1.print(" deg F ");
  }
  else 
  {
    Serial1.print(tempC,1);
    Serial1.print(" deg C ");
  } 
  if (atvAvg<analog0)
  {
    Serial1.print("inc");
  }
  else if (atvAvg>analog0)
  {
    Serial1.print("dec");
  }
  else
  {
    Serial.print("   ");
  }
}

// --------------------------- Subroutines from the time library examples ------------------------

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

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of header & 10 ASCII digits
    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'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number
          // get time from epochconverter.com
          // or in bash
          // date +%s -ud"Apr 10, 2010 12:48:30"   
        }
      }   
      pctime=pctime+timeCorrection; // pctime is UTC, correct as needed 
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }  
  } 
}

// -------------------- SerialLCD Functions ---------------------------------
// you don't need all of these

void selectLineOne(){  //puts the cursor at line 0 char 0.
  Serial1.print(0xFE, BYTE);   //command flag
  Serial1.print(128, BYTE);    //position
  delay(2);
}

void selectLineTwo(){  //puts the cursor at line 2 char 0.
  Serial1.print(0xFE, BYTE);   //command flag
  Serial1.print(192, BYTE);    //position
  delay(2);
}

void goTo(int position) { //position = line 1: 0-19, line 2: 20-39, etc, 79+ defaults back to 0
  if (position<20){ 
    Serial1.print(0xFE, BYTE);   //command flag
    Serial1.print((position+128), BYTE);    //position
  }
  else if (position<40){
    Serial1.print(0xFE, BYTE);   //command flag
    Serial1.print((position+128+64-20), BYTE);    //position 
  }
  else if (position<60){
    Serial1.print(0xFE, BYTE);   //command flag
    Serial1.print((position+128+20-40), BYTE);    //position
  }
  else if (position<80){
    Serial1.print(0xFE, BYTE);   //command flag
    Serial1.print((position+128+84-60), BYTE);    //position              
  } 
  else { 
    goTo(0); 
  }
  delay(2);
}

void clearLCD(){
  Serial1.print(0xFE, BYTE);   //command flag
  Serial1.print(0x01, BYTE);   //clear command.
  delay(2);
}

void backlightOn(){  //turns on the backlight
  Serial1.print(0x7C, BYTE);   //command flag for backlight stuff
  Serial1.print(157, BYTE);    //light level (157 is brightest).
  delay(2);
}

void backlightOff(){  //turns off the backlight
  Serial1.print(0x7C, BYTE);   //command flag for backlight stuff
  Serial1.print(128, BYTE);     //light level for off.
  delay(2);
}

void backlight50(){  //sets the backlight at 50% brightness
  Serial1.print(0x7C, BYTE);   //command flag for backlight stuff
  Serial1.print(143, BYTE);     //light level for off.
  delay(2);
}

void serCommand(){   //a general function to call the command flag for issuing all other commands   
  Serial1.print(0xFE, BYTE);
}

// ------------------------ the absolute end ---------------------------------------------------


The HS101 Humidity Sensor (Fail)


 What it is called:Relative Humidity Sensor 
 What it does: Measures the relative humidity of air based on a change of capacitance
 What it takes: Arduino, sensor, and some resistors
 What pins are used: Two examples, one uses 1 digital, the other uses 2 digital and 1 analog
 What libraries: LCD serial library (optional - can run with the serial monitor)

60 %RH

Wiring:

See the code for a crudely drawn schematic.

Explanation and Code:


The HS1101 Humidity Sensor is sold by Parallax.com for a very reasonable price.  The data sheet can be found here.  This device is essentially a variable capacitor that changes value in a fairly linear fashion corresponding to the relative humidity (RH) in accordance with this equation:

capacitance (in pF) = .34 pF * RH + 163.2 pF  at 25 degrees C (with a change of .04 pF per deg C)

To set up this sensor with the Arduino, you can use the equivalent of the RCtime function used by Parallax Pbasic code provided on their site.  The details for the Arduino equivalent function are given here.  An alternative is to use the setup shown in the capacitance measuring tutorial, which uses 2 digital and 1 analog pins, and it seems quite stable (for larger capacitances).

The sensor is polarity sensitive, so make sure you have the signal lead going to the 5 volt source.  The ground pin goes to ground through a 10 Megohm resistor (i used 5 megOhms simply because I didn't have a 10 MegOhm, but the closer you get to 10 MegOhms the higher your resolution will be, that is more time for charge/decay).  A 680 ohm (220 to 1K ohm is fine) resistor connects from the junction of the sensor ground pin and the 5 megOhm resistor, and leads to digital pin 7.

What you are doing is measuring the RC time constant required to charge the nominal 180 pF capacitor (the capacitance of the humidity sensor at 55% RH) to 63% of the full voltage (5.07 volts for us).  The circuit uses digital pin 8 to discharge the capacitor, then effectively removes it by making it an input, and starts a charge through the 5 megOhm resistor using digital pin 7 as a HIGH.  The analog input pin measures the voltage increase, and provides a time in microseconds for the R/C circuit to reach 63% of 5.05 volts (647 of the 1023 full voltage count).  On a rainy day with the local weather station showing 96% RH the sensor outputs 248 pF, about 50 pF more than expected, although a bread board is undoubtedly adding capacitive and resistive errors.  Until more data is collected, we'll assume that .34 pF per RH holds, and we'll just shift the manufacturer's given data curve up a bit so that:

capacitance (pf) = .34*RH + 215.36

or,

RH = (capacitance-215.36)/.34  

This of course will be revisited after some more data points are taken.

Update/Note: I've had time a bit more time to work with these sensors using resistors up to 33 megOhms.  The bottom line is, in my estimation, that these sensors, providing a paltry .34 pF per %RH (if they do even that much), are junk.  That kind of capacitance is lost in the wiring, especially breadboard wiring.  Pay a little more and get something that works.  Looking at the characteristics, I believe even those using the 555 counter approach are just fooling themselves with the added complexity of the 555 circuitry.  Considering that the base capacitance is 180 pF, and I easily pick up 60 pF in breadboard wiring, 180.34 pF is just not within the resolution of a breadboarded, or even wired, circuit - maybe a thoughtfully layed out pc board with some type of signal amplification.  I wasted $5 on this one.  See the HSM-20G example for a better solution.

/*  Humidity sensor
*
*   https://sites.google.com/site/measuringstuff/other
*   theory explained and lots of code taken from:
*   http://arduino.cc/en/Tutorial/CapacitanceMeter
*
*/

// humidity sensor defs -----------------------------------------------------------------------------
// analog pin for measuring capacitor voltage
#define analogPin      0    
// pin to charge the capacitor - connected to one end of the charging resistor
#define chargePin      7     
// pin to discharge the capacitor
#define dischargePin   8         
// change this to whatever resistor value you are using in MegOhms
// F formatter tells compliler it's a floating point value
#define resistorValue  5.0F 
#define RHslope        0.34F
#define RHconstant     215.36F
                                  
unsigned long startTime;          // time in microseconds
unsigned long elapsedTime;        // time in microseconds
float picoFarads;
int humidity;


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

void loop() 
{
  getHumidity();
  delay(4000);
  
}

int getHumidity()
{          
  // set chargePin to output
  pinMode(chargePin, OUTPUT);     
  digitalWrite(chargePin, LOW);
  // set discharge pin to output 
  pinMode(dischargePin, OUTPUT);  
  // set discharge pin LOW 
  digitalWrite(dischargePin, LOW);          
  while(analogRead(analogPin) > 10)
  {       
     // make sure the cap is discharged
  }
  // makes it high impedance
  pinMode(dischargePin, INPUT);
  // set chargePin HIGH and capacitor charging  
  digitalWrite(chargePin, HIGH); 
  startTime = micros();
  while(analogRead(analogPin) < 648)
  {       
     // 647 is 63.2% of 1023, which corresponds to full-scale voltage 
  }
  elapsedTime= micros() - startTime;
  // picoFarads is given when using microseconds and megohms 
  picoFarads = (((float)elapsedTime) / resistorValue);   
  
  Serial.print(elapsedTime);       // print the value to serial port
  Serial.println(" uS  ");         // print units and carriage return
  Serial.print(picoFarads,2);
  Serial.println(" pF   ");
  
  humidity=(int)((picoFarads-RHconstant)/RHslope);
  
  Serial.print(humidity);
  Serial.println(" % humidity ");
  
  return humidity;   
}

And here is the RCtime method (less precise but takes only one digital pin):

/* RCtime
 *   Duplicates the functionality of the Basic Stamp's RCtime
 *   Allows digital pins to be used to read resistive analog sensors
 *   One advantage of this technique is that is can be used to read very wide ranging inputs.
 *   (The equivalent of 16 or 18 bit A/D)
 *  

 Schematic
                  +5V
                   |
                   |
                  ___
                  ___    Sensing Cap
                   |      .001 ufd  (change to suit for required resolution)
                   |      (102) pfd
                   |
sPin ---\/\/\/-----.
       220 - 1K    |
                   |
                   \   
                   /     Variable Resistive Sensor
                   \     Photocell, phototransistor, FSR etc.
                   /
                   |
                   |
                   |
                 _____ 
                  ___
                   _

*/

int sensorPin = 7;              // 220 or 1k resistor connected to this pin
float capacitance = 0;
float avgCapacitance = 0;
long unsigned startTime;
long unsigned elapsedTime;
// resistance in MegOhms
float resistance=3.0;
float fudgeFactor=1.1;
float RHslope=0.34;
float RHconstant=155.0;
int humidity;

void setup()                    // run once, when the sketch starts
{
   Serial.begin(9600);
   Serial.println("start");      // a personal quirk 
}
void loop()                     // run over and over again
{

   Serial.println( RCtime4RH(sensorPin) );
   delay(2000);

}

int RCtime4RH(int sensPin)
{  
   int avg = 12; 
   avgCapacitance=0;
   for(byte k=0;k<avg;k++)
   {
   long result = 0;
   pinMode(sensPin, OUTPUT);       // make pin OUTPUT
   digitalWrite(sensPin, HIGH);    // make pin HIGH to discharge capacitor - study the schematic
   delay(1);                       // wait a  ms to make sure cap is discharged

   pinMode(sensPin, INPUT);        // turn pin into an input and time till pin goes low
   digitalWrite(sensPin, LOW);     // turn pullups off - or it won't work
   startTime=micros();
   while(digitalRead(sensPin)){    // wait for pin to go low
   }
   elapsedTime=micros()-startTime;
   capacitance=(fudgeFactor*(elapsedTime/resistance));
   avgCapacitance=avgCapacitance+capacitance;
   delay(10);
   }
   avgCapacitance=avgCapacitance/(float)avg;
   humidity=(int)((avgCapacitance-RHconstant)/RHslope);
   return humidity;    
}  


SCP1000 Pressure & Temperature Sensor


 What it is called:The Parallax VTI SCP1000 Ressure and Temperature Sensor
 What it does:Measures atmospheric pressure and localized temperature
 What it takes:Arduino Duemilanove or Mega, VTI SCP1000 sensor, 3 10K and 1 1K resistor
 What pins are used: Duemilanove uses 10-13, Mega uses 50-53 for SPI communications
 What libraries: None

Parts:

Arduino
Parallax VTI SCP1000 sensor
3 10K resistors
1 1K resistor

Wiring:




Display Example:

from serial monitor:

Initialize High Speed Constant Reading Mode
PRESSURE (Pa)[98045]
PRESSURE (Atm)[0.968]
TEMP C [28]
TEMP F [82]
--------------------------
PRESSURE (Pa)[98044]
PRESSURE (Atm)[0.968]
TEMP C [28]
TEMP F [82]
--------------------------

Comments:

This is a very nice sensor. Works as advertised. I haven't tried multiple sensors on the spi bus, and that may be the Achilles heel. The other problem is that SPI, on the Duemilanove, uses too many digital pins. If you're going to use spi, If I had any thought of further expansion, I would go with an Arduino mega. You're especially going to have problems if you use a DUemilanove with a parallel LCD and spi (save your sanity and use a serial LCD). Too many wires, and too many pins.

Explanation & Code:
/*
SCP1000 (parallax board on 5v arduino mega)
code from Conor with fixes by BLP from thread:
( http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213217330/5#5 )
uses pins 10, 11, 12 ,13  for Duemilanove or 53, 51, 50, 52 for Arduino Mega
Must use resistors with a 5 volt Arduino talking to this 3.3 volt SPI sensor. 
See: http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=65
Parallax SCP1000      ArduinoD/ArduinoMega      
1   VSS/GND           gnd      
2   AVDD              3.3 v
3   TRIG              Connect to gnd if not used      
4   DRDY (Int)        n/a      
5   DVDD              3.3 V      
6   PD                connect to gnd if not used      
7   SCLK              pin 13/52 using 10K resistor
8   MOSI              pin 11/51 using 10K resistor
9   MISO              pin 12/50 straight through (no resistor needed)
10  CSB               pin 10/53 using 1K with 10K 3.3v pull up from
                        sensor side of 1K 
*/

// define spi bus pins
// set for mega change pins for duemilanove
#define SLAVESELECT 53   // CS/SS pin 10 or 53
#define SPICLOCK 52      // clk pin 13 or 52
#define DATAOUT 51 //MOSI pin 11 or 51
#define DATAIN 50 //MISO pin 12 or 50
#define UBLB(a,b)  ( ( (a) << 8) | (b) )
#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )

//Addresses
#define REVID 0x00 //ASIC Revision Number
#define OPSTATUS 0x04   //Operation Status
#define STATUS 0x07     //ASIC Status
#define START 0x0A      //Constant Readings
#define PRESSURE 0x1F   //Pressure 3 MSB
#define PRESSURE_LSB 0x20 //Pressure 16 LSB
#define TEMP 0x21       //16 bit temp

char rev_in_byte;    
int temp_in;
unsigned long pressure_lsb;
unsigned long pressure_msb;
unsigned long temp_pressure;
unsigned long pressure;

void setup()
{
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //disable device  
  
  SPCR = B01010011; //MPIE=0, SPE=1 (on), DORD=0 (MSB first), MSTR=1 (master), CPOL=0 (clock idle when low), CPHA=0 (samples MOSI on rising edge), SPR1=0 & SPR0=0 (500kHz)
  clr=SPSR;
  clr=SPDR;
  delay(10);
  Serial.begin(9600);
  delay(500);

  Serial.println("Initialize High Speed Constant Reading Mode");
  write_register(0x03,0x09);
}

void loop()
{
  
  rev_in_byte = read_register(REVID);
  
  pressure_msb = read_register(PRESSURE);
  pressure_msb &= B00000111;
  pressure_lsb = read_register16(PRESSURE_LSB);
  pressure_lsb &= 0x0000FFFF;  // this is BLP's fix
  pressure = UBLB19(pressure_msb, pressure_lsb);
  pressure /= 4;
  
  Serial.print("PRESSURE (Pa)[");
  Serial.print(pressure, DEC);
  Serial.println("]");
  
  Serial.print("PRESSURE (Atm)[");
  float pAtm=float(pressure)/101325.0;
  Serial.print(pAtm, 3);
  Serial.println("]");
  
  temp_in = read_register16(TEMP);
  float tempC = float(temp_in)/19.0; // use 20 by the spec sheet - my board seems closer to 19
  Serial.print("TEMP C [");
  Serial.print(tempC , 0);
  Serial.println("]");
  float tempF = tempC*1.8 + 32;
  Serial.print("TEMP F [");
  Serial.print(tempF , 0);
  Serial.println("]");
  Serial.println("--------------------------");
  delay(2500);
  
}

char spi_transfer(volatile char data)
{
  SPDR = data;  // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission
  {
  };
  return SPDR;  // return the received byte
}


char read_register(char register_name)
{
    char in_byte;
    register_name <<= 2;
    register_name &= B11111100; //Read command
  
    digitalWrite(SLAVESELECT,LOW); //Select SPI Device
    spi_transfer(register_name); //Write byte to device
    in_byte = spi_transfer(0x00); //Send nothing, but we should get back the register value
    digitalWrite(SLAVESELECT,HIGH);
    delay(10);
    return(in_byte);
  
}

unsigned long read_register16(char register_name)
{
    byte in_byte1;
    byte in_byte2;
    float in_word;
    
    register_name <<= 2;
    register_name &= B11111100; //Read command

    digitalWrite(SLAVESELECT,LOW); //Select SPI Device
    spi_transfer(register_name); //Write byte to device
    in_byte1 = spi_transfer(0x00);    
    in_byte2 = spi_transfer(0x00);
    digitalWrite(SLAVESELECT,HIGH);
    in_word = UBLB(in_byte1,in_byte2);
    return(in_word);
}

void write_register(char register_name, char register_value)
{
    register_name <<= 2;
    register_name |= B00000010; //Write command

    digitalWrite(SLAVESELECT,LOW); //Select SPI device
    spi_transfer(register_name); //Send register location
    spi_transfer(register_value); //Send value to record into register
    digitalWrite(SLAVESELECT,HIGH);



DS1307 Real Time Clock 


 What it is called: DS1307 Real Time Clock (from Futurelec)
 What it does: Keeps current time using a battery backup
 What it takes: Arduino, Real Time Clock
 What pins are used: 4 (sda) and 5 (scl) on duemilonova, 20 and 21 on Mega 
 What libraries: Time, DateTime, Wire, DS1307RTC

Parts:

Arduino - any type

Wiring:
Uses the i2c bus, pins 4 (sda) and 5 (scl) (labeled on the clock board) on the Duemilanova, and 20 and 21 on the Mega.  Doesn't require pullup resistors (they are set by library code).  Board also needs a ground and +5v connection.  Four connections; very straight forward. Tested on the Mega and the Duemilanova.  Here is a nice wiring example (the futurelec just puts it all on a PC board).


Display Example:

When inserting 'epochtime' (code set 1):

Waiting for epochtime message, a Txxxxxxxxxx string where x is a number
Example: Epoch timestamp T946684800 gives Sat, 01 Jan 2000 00:00:00 GMT
T
18:43 Fri Jul 2 2010

Setting the real time clock and the arduino (code set 2) :

Waiting for epochtime message, a Txxxxxxxxxx string where x is a number
Example: Epoch timestamp T946684800 gives Sat, 01 Jan 2000 00:00:00 GMT
T
Setting arduino clock
Setting RTC clock
The next line is the arduino clock from epoch set
13:00 Sat Jul 3 2010
The next line is the arduino clock from RTC set
RTC has set the system time
13:00 Sat Jul 3 2010

Set time using the RTC (code set 3):

RTC has set the system time
13:11 Sat Jul 3 2010

Comments:

A real time clock is a must for anyone that needs current time to be displayed or logged and unplugs their arduino often (or places it in a sleep state).  Prior to having a realtime clock, I was always jumping through the hoops of entering 'epoch time', and that gets old fast (although I have supplied the code for that method as well since it works well for a constantly powered system).

Explanation & Code:

There are three code sets here.  The first code set is for setting time manually using epoch time.  You must manually enter unix 'epochtime' via the serial monitor (not something you want to do repeatedly).   The second code set will set the real time clock as well as the Arduino using the manual epochtime method. The third and final code set is for setting a clock using the real time clock only.  All the overhead is toosed out, but of course you need to be sure the real time clock is set first (use code set 2). Remember, pins differ between the Duemilanova and the Mega!

----------- example 1: Setting the internal clock without a real time clock --------------------------------
----------- pass epoch time via the serial monitor ------------------------------------------------------------------ 

#include <Time.h>  
#include <DateTime.h>

/* 
 * epochTimeSet.pde
 * code set 1 of 3 of epochtime series
 * almost the same as the included TimeSerial.pde except it works
 * Set arduino time using epoch (unix) time
 * Time set message consists of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * for example, send the text on the next line using the Serial Monitor to set the clock to noon Jan 1 2010
 * T1262347200 
 * 
  goto www.epochtime.com
  copy the time
  load the program 
  led 13 will come on
  open the serial monitor
  type T and paste in the epochtime
  modify the epoch time to be about 20 seconds in the future
  the time will look something like this: T1262304000
  wait for the current epochtime from the website to match your entered time
  press send
 *
 */ 

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

char theDay[22]="SunMonTueWedThrFriSat";
char mon[37]="JanFebMarAprMayJunJulAugSepOctNovDec";
//unix time is UTC/GMT - correct as necessary in units of seconds
//for EST with daylight savings
long int timeCorrection=(-4*3600);

void setup()  
{
  Serial.begin(9600);
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  Serial.println("Waiting for epochtime message, a Txxxxxxxxxx string where x is a number");
  Serial.println("Example: Epoch timestamp T946684800 gives Sat, 01 Jan 2000 00:00:00 GMT");
  // wait for a serial message of 11 characters
  do
  {
  }
  while (Serial.available() < TIME_MSG_LEN);
  getEpochTime();
  digitalWrite(13,LOW); // on if synced, off if needs refresh  
}

void loop()
{     
    printTime();  
    delay(1000);
}


void printTime() 
{
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  // uncomment seconds if you want them
  //Serial.print(":");
  //printDigits(second());
  Serial.print(" ");
  byte qq=((weekday()-1)*3);
  Serial.print(theDay[qq]);
  Serial.print(theDay[qq+1]);
  Serial.print(theDay[qq+2]);
  Serial.print(" ");
  byte q=(month()-1)*3;
  Serial.print(mon[q]);
  Serial.print(mon[q+1]);
  Serial.print(mon[q+2]);
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.println(year());
}

void getEpochTime() 
{
    // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.println(c);  
    if( c == TIME_HEADER ) 
    {       
      time_t pctime = 0;
      // convert remaining 10 characters to numbers
      // where's atoi when you need him? 
      for(int i=0; i < TIME_MSG_LEN -1; i++)
      {   
        c = Serial.read();          
        if( c >= '0' && c <= '9')
        {   
          // as close to magic as I've seen - must be subtracting ascii values
          // hardly the way to demonstrate "an easy to use language/IDE" 
          pctime = (10 * pctime) + (c - '0') ;    
        }
      }
      pctime=pctime+timeCorrection;   
      setTime(pctime); 
   }
 }

----------- example 2: Setting the internal arduino clock and the real time clock --------------------------------

#include <Time.h>  
#include <DateTime.h>
#include <Wire.h>  
#include <DS1307RTC.h>

/* 
 * epochTimeSetBothArduinoAndRTC.pde
 *
 * Time set messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 * T1262347200 
 * 
  goto www.epochtime.com
  copy the time
  load the program 
  led 13 will come on
  open the serial monitor
  type T and paste in the epochtime
  modify the epoch time to be about 20 seconds in the future
  the time will look something like this
  T1262304000
  wait for the current epochtime from the website to match your entered time
  press send
*  
  hardware: futurelec 1307 real time clock hooked to:
  +5,gnd, sda (pin4, or 20 on the mega), scl (pin 5, or 21 on the mega)
  no pull up resistors needed (on board)
  output: serial monitor
 *
 */ 

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

char theDay[22]="SunMonTueWedThrFriSat";
char mon[37]="JanFebMarAprMayJunJulAugSepOctNovDec";
//unix time is UTC/GMT - correct as necessary in units of seconds
//for EST with daylight savings
long int timeCorrection=(-4*3600);

void setup()  
{
  Serial.begin(9600);
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  Serial.println("Waiting for epochtime message, a Txxxxxxxxxx string where x is a number");
  Serial.println("Example: Epoch timestamp T946684800 gives Sat, 01 Jan 2000 00:00:00 GMT");
  // wait for a serial message of 11 characters
  do
  {
  }
  while (Serial.available() < TIME_MSG_LEN);
  getEpochTime();
  digitalWrite(13,LOW); // on if synced, off if needs refresh
  Serial.println("The next line is the arduino clock from epoch set");
  printTime();
  Serial.println("The next line is the arduino clock from RTC set");
  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");      
  }
  delay(5000);
}

void loop()
{     
    printTime(); 
    delay(5000);
}


void printTime() 
{
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  // uncomment seconds if you want them
  //Serial.print(":");
  //printDigits(second());
  Serial.print(" ");
  byte qq=((weekday()-1)*3);
  Serial.print(theDay[qq]);
  Serial.print(theDay[qq+1]);
  Serial.print(theDay[qq+2]);
  Serial.print(" ");
  byte q=(month()-1)*3;
  Serial.print(mon[q]);
  Serial.print(mon[q+1]);
  Serial.print(mon[q+2]);
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.println(year());
}

void getEpochTime() 
{
    // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.println(c);  
    if( c == TIME_HEADER ) 
    {       
      time_t pctime = 0;
      // convert remaining 10 characters to numbers
      // where's atoi when you need him? 
      for(int i=0; i < TIME_MSG_LEN -1; i++)
      {   
        c = Serial.read();          
        if( c >= '0' && c <= '9')
        {   
          // as close to magic as I've seen - must be subtracting ascii values
          // hardly the way to demonstrate "an easy to use language/IDE" 
          pctime = (10 * pctime) + (c - '0') ;    
        }
      }
      pctime=pctime+timeCorrection;
      Serial.println("Setting arduino clock");  
      setTime(pctime); 
      Serial.println("Setting RTC clock");
      RTC.set(pctime);
   }
 }


----------- example 3: Setting the internal arduino clock and the real time clock --------------------------------
----------- assumes you have your RTC set to the correct time using code set 2 ------------------------------

#include <Time.h>  
#include <DateTime.h>
#include <Wire.h>  
#include <DS1307RTC.h>

/* 
 * TimeSetUsingRTC.pde
 * code set 1 of 3 of epochtime series
  * use code set 2 to set the RTC first, if it has not been set to current time
 * 
  hardware: futurelec 1307 real time clock hooked to:
  +5,gnd, sda (pin4, or 20 on the mega), scl (pin 5, or 21 on the mega)
  no pull up resistors needed (on board)
  and set to proper time
  output to: serial monitor
 *
 */ 

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

char theDay[22]="SunMonTueWedThrFriSat";
char mon[37]="JanFebMarAprMayJunJulAugSepOctNovDec";

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");      
  }
  delay(1000);
}

void loop()
{     
    printTime(); 
    delay(5000);
}

void printTime() 
{
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  // uncomment seconds if you want them
  //Serial.print(":");
  //printDigits(second());
  Serial.print(" ");
  byte qq=((weekday()-1)*3);
  Serial.print(theDay[qq]);
  Serial.print(theDay[qq+1]);
  Serial.print(theDay[qq+2]);
  Serial.print(" ");
  byte q=(month()-1)*3;
  Serial.print(mon[q]);
  Serial.print(mon[q+1]);
  Serial.print(mon[q+2]);
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.println(year());
}

 

Comments