Search This Blog

Showing posts with label Clock. Show all posts
Showing posts with label Clock. Show all posts

Monday, February 21, 2011

Arduino based "crazy clock" idea

I thought of something fun to do with them, to make an analog crazy clock or backwards clock.
I have some small stepper motors from adafruit.
The arduino could keep time, and drive the steppers to move the hands in any pattern you want.
This could mimic a watch I've seen where the hours are out of order.
http://www.blogcdn.com/www.luxist.com/media/2009/05/franck-muller-crazy-hours-watch-blue.jpg

Just writing it down to come back to it later if I get bored

Monday, February 14, 2011

Arduino LCD Countdown Clock

Quickie project for a desktop clock that counts down to when my work project has to be done, then counts how many weeks it is late.


The design is the "raw electronics" look.  The arduino is mounted on the back of the large LCD display by nothing more than a stacked header, and hot glued to a small piece of wood for a base.

The code is built on top of the basic example for a clock that syncs from the PC, found here:
The Arduino Time Library on the Arduino Playground
http://www.arduino.cc/playground/Code/Time

When plugged into the PC and using the Arduino serial monitor, it waits for you to enter a unix timestamp.
You can generate these from web sites like these ones:
http://www.timestampgenerator.com/
http://www.unixtimestamp.com/index.php

They have the form of seconds since Jan 01 1970, type in T1297687386
Type that in the start the clock.  There are PC programs out there that run a host to send that string, like gobetwino if you want to do that to, you don't need to.  This is just a manual start.

Change this variable in the code to the unix timestamp of the event you want to count down to
signed long tapeout = 1309539600;

The hardware is nothing more than an arduino interfaced to a huge 20x4 backlit LCD module, using the 4 bit wide parallel communication mode.  The pinout is a very slight mod to the descriptions in the Arduino examples, because I like to group the pins all on one header.   This is exactly like the setup in the Arduino examples.

I use an external wall wart as power, so it doesn't have to be plugged into the PC all the time.

Here is the code




* Sketch for 4x20 LCD to display current time and date, and countdown of weeks, days, hours, min to an event
 *
 */

#include <Time.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6 , 5, 4, 3, 2);

#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
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message

signed long tapeout = 1309539600;

// to make sure the display is cleared once a day
int yesterday = 0;
int weeksleft = 0;
int daysleft = 0;
int hoursleft = 0;
int minleft = 0;


void setup()  {
  lcd.begin(20, 4);
  lcd.clear();
  //backlight on pin 8
  pinMode(8, OUTPUT);
  digitalWrite(8, LOW);
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
  Serial.println("Unix Timestamp");
  Serial.println("Example T1297674000");
  lcd.setCursor(0,0);
  lcd.print("Waiting for PC time sync...");
}

void loop(){  
  if(Serial.available() )
  {
    processSyncMessage();
    digitalWrite(8, HIGH);
  }
  if(timeStatus()!= timeNotSet)
  {
    digitalClockDisplay();
  
    // clear the display if the day changes to clear glitches
    if (day() != yesterday) {
        //lcd.clear();
        yesterday = day();
    }
  }
  delay(20000);  //can be set to 1000, this makes the display more stable
}

void digitalClockDisplay(){

  //turn on backlight only during workday
  if((hour() >= 8) & (hour() < 19)) digitalWrite(8, HIGH);
  else   digitalWrite(8, LOW);

  // digital clock display of the time
  lcd.setCursor(0,0);
  Serial.print(hour());
  lcd.print(hourFormat12());
  printDigits(minute());
  //printDigits(second());
  Serial.print("   ");
  if (isAM()) lcd.print(" AM ");
  if (isPM()) lcd.print(" PM ");
  Serial.print(dayStr(weekday()));
  lcd.print(dayStr(weekday()));
  Serial.print(" ");
  lcd.print(" ");
  lcd.setCursor(0,1);
  Serial.print(day());
  lcd.print(day());
  Serial.print(" ");
    lcd.print(" ");
  Serial.print(monthShortStr(month()));
    lcd.print(monthShortStr(month()));
  Serial.print(" ");
    lcd.print(" ");
  Serial.print(year());
    lcd.print(year());
  Serial.println();
  lcd.setCursor(0,2);
  if (tapeout < now()) {
      weeksleft = (now() - tapeout)/60/60/24/7;
      daysleft = (now() - tapeout)/60/60/24 - weeksleft*7;
      hoursleft = (now() - tapeout)/60/60 - daysleft*24 - weeksleft*7*24;
      minleft =  (now() - tapeout)/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
      lcd.print(   weeksleft   );
      lcd.print("wk ");
      lcd.print(   daysleft   );
      lcd.print("d ");
      lcd.print(   hoursleft   );
      lcd.print("h ");
      lcd.print(   minleft  );
      lcd.print("m ");
      lcd.setCursor(0,3);
      lcd.print("Late! OMG! Ship It!   ");
  } else {
      weeksleft = (tapeout - now())/60/60/24/7;
      daysleft = (tapeout - now())/60/60/24 - weeksleft*7 ;
      hoursleft = (tapeout - now())/60/60 - daysleft*24 - weeksleft*7*24;
      minleft =  (tapeout - now())/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
      lcd.print(   weeksleft   );
      lcd.print("wk ");
      lcd.print(   daysleft   );
      lcd.print("d ");
      lcd.print(   hoursleft   );
      lcd.print("h ");
      lcd.print(   minleft  );
      lcd.print("m  ");
      lcd.setCursor(0,3);
      lcd.print("To Santan Tapeout! ");
  }
}

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

void processSyncMessage() {
  lcd.clear();
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten 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  
        }
      }
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }
  }
}

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


Sunday, September 12, 2010

Arduino Ethernet Clock Code


// Code to run an internet enabled digital clock
// gets data off the web and parses it
// Tom Wilson 9/2010
// Hardware is an Arduino D, Ethernet shield, and a big 20x4 LCD

#include <Ethernet.h>
// Borrowed code from a couple blogs....
// DHCP support
// Author: Jordan Terrell - blog.jordanterrell.com
//http://blog.jordanterrell.com/post/Arduino-DHCP-Library-Version-04.aspx
#include "Dhcp.h"

//Code to parse and scrape out the data you want
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231812230

#include <LiquidCrystal.h>

// Include description files for other libraries used (if any)
#include <string.h>

// Define Constants
// Max string length may have to be adjusted depending on data to be extracted
#define MAX_STRING_LEN  21

// Setup vars
char tagStr[MAX_STRING_LEN] = "";
char dataStr[MAX_STRING_LEN] = "";
char tmpStr[MAX_STRING_LEN] = "";
char endTag[3] = {'<', '/', '\0'};
int len;
int line_num = 0;
int j = 0;

// Flags to differentiate XML tags from document elements (ie. data)
boolean tagFlag = false;
boolean dataFlag = false;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6 , 5, 4, 3, 2);

boolean ipAcquired = false;
byte mac[] = { 0xDE, 0xAD, 0xDE, 0xED, 0xBE, 0xEF };
//byte ip[] = { 192, 168, 1, 113 }; for non dhcp
//byte server[] = { 72, 14, 204, 99 }; // Google
//byte server[] = { 76, 13, 115, 78 }; // yahooapis
byte server[] = { 199, 211, 133, 239 }; // tycho.usno.navy.mil

Client client(server, 80);

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

  lcd.begin(20, 4);
  //backlight on pin 8
  pinMode(8, OUTPUT);
  digitalWrite(8, LOW);

  // some router may require a delay before it will route network packets
  // add a delay if needed:
  Serial.println("delaying...");
  delay(5000);
  Serial.println("getting ip...");
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("getting ip address...");
  int result = Dhcp.beginWithDHCP(mac);

  if(result == 1)
  {
    ipAcquired = true;
    digitalWrite(8, HIGH);
    
    byte buffer[6];
    Serial.println("ip acquired...");
    lcd.clear();

    Dhcp.getMacAddress(buffer);
    Serial.print("mac address: ");
    printArray(&Serial, ":", buffer, 6, 16);
  
    Dhcp.getLocalIp(buffer);
    Serial.print("ip address: ");
    printArray(&Serial, ".", buffer, 4, 10);

    //print the ip address to screen
    lcd.setCursor(0,0);
    lcd.print("IP Address obtained");
    lcd.setCursor(0,1);
    lcd.print(buffer[0],DEC);
    lcd.setCursor(3,1);
    lcd.print(".");
    lcd.setCursor(4,1);
    lcd.print(buffer[1],DEC);
    lcd.setCursor(7,1);
    lcd.print(".");
    lcd.setCursor(8,1);
    lcd.print(buffer[2],DEC);
    lcd.setCursor(11,1);
    lcd.print(".");
    lcd.setCursor(12,1);
    lcd.print(buffer[3],DEC);
  
    Dhcp.getSubnetMask(buffer);
    Serial.print("subnet mask: ");
    printArray(&Serial, ".", buffer, 4, 10);

    //print the ip address to screen
    lcd.setCursor(0,2);
    lcd.print(buffer[0],DEC);
    lcd.setCursor(3,2);
    lcd.print(".");
    lcd.setCursor(4,2);
    lcd.print(buffer[1],DEC);
    lcd.setCursor(7,2);
    lcd.print(".");
    lcd.setCursor(8,2);
    lcd.print(buffer[2],DEC);
    lcd.setCursor(11,2);
    lcd.print(".");
    lcd.setCursor(12,2);
    lcd.print(buffer[3],DEC);
  
    Dhcp.getGatewayIp(buffer);
    Serial.print("gateway ip: ");
    printArray(&Serial, ".", buffer, 4, 10);


    Dhcp.getDhcpServerIp(buffer);
    Serial.print("dhcp server ip: ");
    printArray(&Serial, ".", buffer, 4, 10);
  
    //print the ip address to screen
    lcd.setCursor(0,3);
    lcd.print(buffer[0],DEC);
    lcd.setCursor(3,3);
    lcd.print(".");
    lcd.setCursor(4,3);
    lcd.print(buffer[1],DEC);
    lcd.setCursor(7,3);
    lcd.print(".");
    lcd.setCursor(8,3);
    lcd.print(buffer[2],DEC);
    lcd.setCursor(11,3);
    lcd.print(".");
    lcd.setCursor(12,3);
    lcd.print(buffer[3],DEC);
  
    Dhcp.getDnsServerIp(buffer);
    Serial.print("dns server ip: ");
    printArray(&Serial, ".", buffer, 4, 10);
  
    delay(5000);
    /*
    Serial.println("connecting...");

    if (client.connect()) {
      Serial.println("connected");
      client.println("GET /search?q=arduino HTTP/1.0");
      client.println();
    } else {
      Serial.println("connection failed");
    }
    */
  
  }
  else {
    Serial.println("unable to acquire ip address...");
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("unable to acquire ip address");
  }

  delay(1000);


  Serial.println("connecting...");
  lcd.setCursor(0,0);
  lcd.print("Connecting...     ");


  if (client.connect()) {
    Serial.println("connected");
    digitalWrite(8, HIGH);
    lcd.clear();

    delay(2000);
    client.println("GET  /cgi-bin/timer.pl HTTP/1.0");  //get military time
    client.println();
  
  } else {
    Serial.println("connection failed");
    digitalWrite(8, LOW);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Connection Failed    ");
  }

}

void loop()
{

  line_num = 0;
  delay(1000);

  Serial.println("connecting...");
  
  while (client.available()) {
    serialEvent();
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    Serial.print("client.status = ");
    Serial.println(client.status(),DEC);

   client.stop();

  Serial.println("connecting...");

  delay(2000);
  if (client.connect()) {
    digitalWrite(8, HIGH);
    Serial.println("connected");
    client.println("GET  /cgi-bin/timer.pl HTTP/1.0");  //get military time
    client.println();
  
  } else {
    digitalWrite(8, LOW);
    Serial.println("connection failed");
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Connection Failed    ");
  }
  }
}

// Process each char from web
void serialEvent() {

   // Read a char
char inChar = client.read();
   //Serial.print(".");

   if (inChar == '<') {
      addChar(inChar, tmpStr);
      tagFlag = true;
      dataFlag = false;

   } else if (inChar == '>') {
      addChar(inChar, tmpStr);

      if (tagFlag) {    
         strncpy(tagStr, tmpStr, strlen(tmpStr)+1);
      }

      // Clear tmp
      clearStr(tmpStr);

      tagFlag = false;
      dataFlag = true;    
    
   } else if (inChar != 10) {
      if (tagFlag) {
         // Add tag char to string
         addChar(inChar, tmpStr);

         // Check for </XML> end tag, ignore it
         if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) {
            clearStr(tmpStr);
            tagFlag = false;
            dataFlag = false;
         }
      }
    
      if (dataFlag) {
         // Add data char to string
         addChar(inChar, dataStr);
      }
   }

   // If a LF, process the line
   if (inChar == 10 ) {

/*
      Serial.print("tagStr: ");
      Serial.println(tagStr);
      Serial.print("dataStr: ");
      Serial.println(dataStr);
*/

      // Find specific tags and print data
      if (matchTag("<BR>")) {
         Serial.print(line_num);
         Serial.print(dataStr);
         Serial.println("");
         //lcd.setCursor(0,line_num);  
         //lcd.print(dataStr);
         if ((line_num > 0) & (line_num < 5)) {
             lcd.setCursor(0,line_num-1);  
             lcd.print(dataStr);
         } else {
             //line_num = 0;
         }
         line_num = line_num + 1;
         //if (line_num >4) line_num = 0;
      }

      
      // Clear all strings
      clearStr(tmpStr);
      clearStr(tagStr);
      clearStr(dataStr);

      // Clear Flags
      tagFlag = false;
      dataFlag = false;
   }
}

/////////////////////
// Other Functions //
/////////////////////

// Function to clear a string
void clearStr (char* str) {
   int len = strlen(str);
   for (int c = 0; c < len; c++) {
      str[c] = 0;
   }
}

//Function to add a char to a string and check its length
void addChar (char ch, char* str) {
   char *tagMsg  = "<TRUNCATED_TAG>";
   char *dataMsg = "-TRUNCATED_DATA-";

   // Check the max size of the string to make sure it doesn't grow too
   // big.  If string is beyond MAX_STRING_LEN assume it is unimportant
   // and replace it with a warning message.
   if (strlen(str) > MAX_STRING_LEN - 2) {
      if (tagFlag) {
         clearStr(tagStr);
         strcpy(tagStr,tagMsg);
      }
      if (dataFlag) {
      //   clearStr(dataStr);
      //   strcpy(dataStr,dataMsg);  just stop instead of killing the string
      }

      // Clear the temp buffer and flags to stop current processing
      clearStr(tmpStr);
      tagFlag = false;
      dataFlag = false;

   } else {
      // Add char to string
      if ((ch != '.') & (ch != ',')) str[strlen(str)] = ch;
   }
}

// Function to check the current tag for a specific string
boolean matchTag (char* searchTag) {
   if ( strcmp(tagStr, searchTag) == 0 ) {
      return true;
   } else {
      return false;
   }
}

void printArray(Print *output, char* delimeter, byte* data, int len, int base)
{
  char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

  for(int i = 0; i < len; i++)
  {
    if(i != 0)
      output->print(delimeter);
    
    output->print(itoa(data[i], buf, base));
  }

  output->println();
}

Got the arduino ethernet shield working

Ordered an ethernet shield from ebay, and it was shipped from Hong Kong.  It cost 9.95 plus another 9.95 to ship.  I got it in about a week.  I was kinda shocked it came so fast.  Plugged it in and the lights flashed.  Tried the ethernet client and server apps, neither would work.  Fooled with my router, trying to see what IP address was assigned to it.  It never showed up on the DHCP table in the router.  I decided it was busted.

Eventually I gave up and ordered for $39
http://www.hacktronics.com/Arduino/Arduino-Ethernet-Shield/flypage.tpl.html
I bought it through Amazon, but now i see it is out of stock.  It had an SD card slot and was much nicer than the chinese one i bought.  My router saw it immediately, and after changing the IP address to the one my router showed in the DHCP table, and changing the server to google for me.  This is done by
using cmd in the run box and opening a terminal window. type ping www.google.com and you will get back the local IP address for google.    Uploaded to the arduino and ba da bing, data started pouring back.

I found that someone had developed a DHCP version of the ethernet library, that worked perfectly
http://blog.jordanterrell.com/post/Arduino-DHCP-Library-Version-04.aspx
This was awesome.   You download and replace the Arduino libraries.  I had trouble at first getting it to find an IP address, until i notice the line that said some routers need a delay to work, and a delay statement commented out.   I uncommented it, and bingo.  The IP address was obtained at home , and also at work where we have a typical big company network monstrosity.

I used this and the tycho navy time site, and the yahoo stock download pages to write an app to pull some data down and made a little desk clock with an LCD display.  Within the weekend of getting the ethernet shield, my little toy was done!