Yet another binary clock w/ external clock source.

Hi,

this is my first real application with arduino, but it’s still not working, now I’ve reached a point where I can’t go on.

/* Arduino binary clock by Paco
 *
 * uses an external 1 hz source provided by a cheap quartz clock
 * http://www.josepino.com/circuits/?one_second_timebase.jpc
 *
 * code under GPL License
 */

byte ledpin[] = {2,3,4,5,6,7,8,9,10,11,12,13,14};
byte num_pins = 13;
byte clocksrc = 19;  // external clock
byte setbtn = 18;  // set button
byte hourbtn = 17;  // hour++ button
byte minbtn = 16;  // minutes++ button
byte hour[] = {0,0};  // for ease I've tried hour[0]hour[1]:minutes[0]minutes[1]
byte minutes[] = {0,0};
byte seconds = 0;

void setTime(byte h[], byte m[]){  // adjusts the time with aid from the three pushbuttons
  while(digitalRead(setbtn)) {
    if(!digitalRead(hourbtn)) {  // hour adjustment
      if(h[0]==2 && h[1]==3) {  // if hour=23 netx will be 00
        h[0]=0;
        h[1]=0;
      } else if(h[1]==9) {
        h[1]=0;
        h[0]++;
      } else
        h[1]++;
      printTime(hour, minutes);
    }
    delay(100);
    
    if(!digitalRead(minbtn)) {  // minute adjustment
      if(m[0]==5 && m[1]==9) {
        m[0]=0;
        m[1]=0;
      } else if(m[1]==9) {
        m[1]=0;
        m[0]++;
      } else
        m[1]++;
      printTime(hour, minutes);
    }
    delay(100);
  }
}

void printTime(byte h[], byte m[]) {  // outputs the time to the leds in binary, n00b way ;)
  switch(h[0]) {
    case 0:
      digitalWrite(ledpin[0],LOW);
      digitalWrite(ledpin[1],LOW);
      break;
    case 1:
      digitalWrite(ledpin[0],HIGH);
      digitalWrite(ledpin[1],LOW);
      break;
    case 2:
      digitalWrite(ledpin[0],LOW);
      digitalWrite(ledpin[1],HIGH);
      break;  
  }
  switch(h[1]) {
    case 0:
      digitalWrite(ledpin[2],LOW);
      digitalWrite(ledpin[3],LOW);
      digitalWrite(ledpin[4],LOW);
      digitalWrite(ledpin[5],LOW);
      break;
    case 1:
      digitalWrite(ledpin[2],HIGH);
      digitalWrite(ledpin[3],LOW);
      digitalWrite(ledpin[4],LOW);
      digitalWrite(ledpin[5],LOW);
      break;
    case 2:
      digitalWrite(ledpin[2],LOW);
      digitalWrite(ledpin[3],HIGH);
      digitalWrite(ledpin[4],LOW);
      digitalWrite(ledpin[5],LOW);
      break;
    case 3:
      digitalWrite(ledpin[2],HIGH);
      digitalWrite(ledpin[3],HIGH);
      digitalWrite(ledpin[4],LOW);
      digitalWrite(ledpin[5],LOW);
      break;
    case 4:
      digitalWrite(ledpin[2],LOW);
      digitalWrite(ledpin[3],LOW);
      digitalWrite(ledpin[4],HIGH);
      digitalWrite(ledpin[5],LOW);
      break;
    case 5:
      digitalWrite(ledpin[2],HIGH);
      digitalWrite(ledpin[3],LOW);
      digitalWrite(ledpin[4],HIGH);
      digitalWrite(ledpin[5],LOW);
      break;
    case 6:
      digitalWrite(ledpin[2],LOW);
      digitalWrite(ledpin[3],HIGH);
      digitalWrite(ledpin[4],HIGH);
      digitalWrite(ledpin[5],LOW);
      break;
    case 7:
      digitalWrite(ledpin[2],HIGH);
      digitalWrite(ledpin[3],HIGH);
      digitalWrite(ledpin[4],HIGH);
      digitalWrite(ledpin[5],LOW);
      break;
    case 8:
      digitalWrite(ledpin[2],LOW);
      digitalWrite(ledpin[3],LOW);
      digitalWrite(ledpin[4],LOW);
      digitalWrite(ledpin[5],HIGH);
      break;
    case 9:
      digitalWrite(ledpin[2],HIGH);
      digitalWrite(ledpin[3],LOW);
      digitalWrite(ledpin[4],LOW);
      digitalWrite(ledpin[5],HIGH);
      break;
  }
  switch(m[0]) {
    case 0:
      digitalWrite(ledpin[6],LOW);
      digitalWrite(ledpin[7],LOW);
      digitalWrite(ledpin[8],LOW);
      break;
    case 1:
      digitalWrite(ledpin[6],HIGH);
      digitalWrite(ledpin[7],LOW);
      digitalWrite(ledpin[8],LOW);
      break;
    case 2:
      digitalWrite(ledpin[6],LOW);
      digitalWrite(ledpin[7],HIGH);
      digitalWrite(ledpin[8],LOW);
      break;
    case 3:
      digitalWrite(ledpin[6],HIGH);
      digitalWrite(ledpin[7],HIGH);
      digitalWrite(ledpin[8],LOW);
      break;
    case 4:
      digitalWrite(ledpin[6],LOW);
      digitalWrite(ledpin[7],LOW);
      digitalWrite(ledpin[8],HIGH);
      break;
    case 5:
      digitalWrite(ledpin[6],HIGH);
      digitalWrite(ledpin[7],LOW);
      digitalWrite(ledpin[8],HIGH);
      break;
  }
  switch(m[1]) {
    case 0:
      digitalWrite(ledpin[9],LOW);
      digitalWrite(ledpin[10],LOW);
      digitalWrite(ledpin[11],LOW);
      digitalWrite(ledpin[12],LOW);
      break;
    case 1:
      digitalWrite(ledpin[9],HIGH);
      digitalWrite(ledpin[10],LOW);
      digitalWrite(ledpin[11],LOW);
      digitalWrite(ledpin[12],LOW);
      break;
    case 2:
      digitalWrite(ledpin[9],LOW);
      digitalWrite(ledpin[10],HIGH);
      digitalWrite(ledpin[11],LOW);
      digitalWrite(ledpin[12],LOW);
      break;
    case 3:
      digitalWrite(ledpin[9],HIGH);
      digitalWrite(ledpin[10],HIGH);
      digitalWrite(ledpin[11],LOW);
      digitalWrite(ledpin[12],LOW);
      break;
    case 4:
      digitalWrite(ledpin[9],LOW);
      digitalWrite(ledpin[10],LOW);
      digitalWrite(ledpin[11],HIGH);
      digitalWrite(ledpin[12],LOW);
      break;
    case 5:
      digitalWrite(ledpin[9],HIGH);
      digitalWrite(ledpin[10],LOW);
      digitalWrite(ledpin[11],HIGH);
      digitalWrite(ledpin[12],LOW);
      break;
    case 6:
      digitalWrite(ledpin[9],LOW);
      digitalWrite(ledpin[10],HIGH);
      digitalWrite(ledpin[11],HIGH);
      digitalWrite(ledpin[12],LOW);
      break;
    case 7:
      digitalWrite(ledpin[9],HIGH);
      digitalWrite(ledpin[10],HIGH);
      digitalWrite(ledpin[11],HIGH);
      digitalWrite(ledpin[12],LOW);
      break;
    case 8:
      digitalWrite(ledpin[9],LOW);
      digitalWrite(ledpin[10],LOW);
      digitalWrite(ledpin[11],LOW);
      digitalWrite(ledpin[12],HIGH);
      break;
    case 9:
      digitalWrite(ledpin[9],HIGH);
      digitalWrite(ledpin[10],LOW);
      digitalWrite(ledpin[11],LOW);
      digitalWrite(ledpin[12],HIGH);
      break;
  }
}

void setNewTime(byte h[], byte m[]) {  // adjusts new time every minute
  if(m[0]==5 && m[1]==9) {
    m[0]=0;
    m[1]=0;
    h[1]++;
  } else if(m[1]==9) {
    m[1]=0;
    m[0]++;
  } else
    m[1]++;
  if(h[0]==2 && h[1]==4) {
    h[0]=0;
    h[1]=0;
  } else if(h[1]==9) {
    h[1]=0;
    h[0]++;
  }
}

void setup(){
  /* debug */
  Serial.begin(9600);
  
  /* set leds as OUTPUT */
  for(int i=0; i<num_pins; i++) {
    pinMode(ledpin[i], OUTPUT);
  }
  
  /* set internal pullup resistors for pushbuttons and also for the clock source */
  digitalWrite(setbtn, HIGH);
  digitalWrite(hourbtn, HIGH);
  digitalWrite(minbtn, HIGH);
  digitalWrite(clocksrc, HIGH);

  setTime(hour, minutes);  // first thing we have to do is adjust time
}

void loop(){
  if(digitalRead(clocksrc)) {  // desperately needs a fix
    /* debug */
    Serial.println("tick");
    seconds++;
    /* debug */
    Serial.println(seconds, DEC);
    if(seconds==60) {
      seconds=0;
      setNewTime(hour, minutes);
      /* debug */
      Serial.println("set new time");
      printTime(hour, minutes);
    }
    delay(100);  // this is a workaround for preventing the clock from ticking more than once per second
  }              // probably the shit that makes the clock don't work properly
}

I think I know where the problem resides but I don’t know how to solve it. So please help me with this. Also any corrections on code optimization or even coding style will be helpful for me to continue learning.

Thank you very much.

Paco
PS. Sorry for my english.

Forget to say that the clock works great for a few minutes then goes crazy.

The arduino clock uses a quartz crystal so you don’t have to connect an external 1 hz source for your clock. There is a library in the playground called DateTime that can do the timekeeping for you : http://www.arduino.cc/playground/Code/DateTime
(the library could also be easily modified to be driven from an external source if you needed to do that)

Here is a sketch that uses this library to produce binary time on the serial port as well as driving the pins in your array.

I hope it is some help for your clock.

Have fun!

#include <DateTime.h>

byte ledpin[] = {
  2,3,4,5,6,7,8,9,10,11,12,13,14};
byte num_pins = 13;
byte setIncBtn = 19;  // increment the min or hour if button pressed
byte setDecBtn = 18;  // decrement  as above
byte hourbtn = 17;  // set hour button (used with inc or dec button)
byte minbtn = 16;  // set minutes button as above


void setTime(){  // adjusts the time with aid from the three pushbuttons

  while(!digitalRead(setIncBtn)) {
    Serial.print( '>');
    if(!digitalRead(hourbtn))  // hour adjustment      
      DateTime.sync(DateTime.now() + 3600);  
    else if(!digitalRead(minbtn))   // minute adjustment
      DateTime.sync(DateTime.now() + 60);      
    printTime();
    delay(100);
  }
  while(!digitalRead(setDecBtn)) {
     Serial.print( '<');
    if(!digitalRead(hourbtn))  // hour adjustment      
      DateTime.sync(DateTime.now() - 3600);  
    else if(!digitalRead(minbtn))   // minute adjustment
      DateTime.sync(DateTime.now() - 60);      
    printTime();
    delay(100);
  }
}

void printBinary( int digit, int pinIndex, int binaryPlaces){
  for(int i=binaryPlaces-1; i >= 0; i--){
     int bit = digit & (1 << i);
     if( bit == 0 ){
        digitalWrite(ledpin[pinIndex++], LOW );
        Serial.print('0');     
     }
     else{
        digitalWrite(ledpin[pinIndex++], HIGH );
        Serial.print('1');    
     }
  }
}

void printTime() { 

  DateTime.available();
  
  printBinary(DateTime.Hour / 10, 0, 2);   // digit, pin index, number of binary places
  Serial.print(" ");
  printBinary(DateTime.Hour % 10, 2, 4);
  Serial.print(":");
  printBinary(DateTime.Minute / 10, 6, 3);
  Serial.print(" ");
  printBinary(DateTime.Minute % 10, 9, 4);
  Serial.println();
     

  Serial.print(DateTime.Hour,DEC);
  Serial.print(":");
  if(DateTime.Minute < 10)
    Serial.print('0');
  Serial.print(DateTime.Minute,DEC);
  Serial.println();  
 
}

void setup(){
  /* debug */
  Serial.begin(9600);
  DateTime.sync(1230768000); // set Jan 1 2009 as the default time


  /* set leds as OUTPUT */
  for(int i=0; i<num_pins; i++) {
    pinMode(ledpin[i], OUTPUT);
  }

  /* set internal pullup resistors for pushbuttons and also for the clock source */
  digitalWrite(setIncBtn, HIGH);
  digitalWrite(setDecBtn, HIGH);
  digitalWrite(hourbtn, HIGH);
  digitalWrite(minbtn, HIGH);

}

void loop(){
time_t prevtime;
  setTime();
  if( prevtime != DateTime.now() ){
      printTime(); 
      prevtime = DateTime.now();
  }
  delay(100);  
}

Hi,

didn't know about the DateTime library, the idea of using the external clock was because I had read that the delay function was inaccurate.

Thank you very much for enlighten me and also for improving the code. ;)

Paco

hmm… that might be an easy way to do it. datetime must be based on the millis() function. that was way off when i tried it last, but likely because i used a ceramic resonator.
the best way i found was to run the atmega with the 8mhz internal resonator, and attach a 32.768kHz watch crystal. then if you set things up right you can get a interrupt exactly once every second. this way you can do a lot more with your processor without having to constantly check if the time has changed. here is a demo:

int ledPin = 19;

//  every second!!!!  ;)
ISR(TIMER2_OVF_vect) {
    digitalWrite(ledPin, HIGH);
    delay(100);
    digitalWrite(ledPin, LOW);
}
void setup() {
  pinMode(ledPin, OUTPUT);
  TCCR2A = 0;
  TCCR2B = 0;   // stop the timer
  TCNT2 = 0;   // reset the counter
  ASSR = (1 << AS2);  // select watch crystal as clock source       
  TCCR2B = (1 << CS22) | (1 << CS20);  // set prescaler to 128
  TIMSK2 = (1 << TOIE2);   // enable interrupt
}
void loop() {

}

i made a really cool binary pocket watch with this method:

the lights slowly fade in and out giving it a sweet blue glow, and making it really hard to photograph. :o

That Binary watch looks like fun, any chance of a video?

Probably not necessary for your application but if you wanted to write a sketch that used more date and time functionality with an external watch crystal, here is what you could do to drive DateTime from an external 1hz source:

In DateTime.h declaration of the now method, add the volatile modifier and move the declaration from private to public.
public:
volatile time_t sysTime; // moved from private to public
// all other public declarations are unchanged

In the DateTime.cpp file, comment out all code in the DateTime.now method except the line that returns sysTime.
time_t DateTimeClass::now(){
return sysTime;
}

Here is a fragment from a sketch:

#include <DateTime.h>

//  every second!!!!  ;)
ISR(TIMER2_OVF_vect) {
     DateTime.sysTime++;
}

void setupTimer(){
  TCCR2A = 0;
  TCCR2B = 0;   // stop the timer
  TCNT2 = 0;   // reset the counter
  ASSR = (1 << AS2);  // select watch crystal as clock source      
  TCCR2B = (1 << CS22) | (1 << CS20);  // set prescaler to 128
  TIMSK2 = (1 << TOIE2);   // enable interrupt 
  
}
void setup() {
  Serial.begin(9600);
  setupTimer();
}

void  loop(){
// you can use any of the published DateTime code here ?.
}