Binary Clock

I'm new at Arduino stuff so I built a simple binary clock [smiley=smiley.gif]! It displays hours and minutes and blinks the led on pin 13 every second. I tried to redo it so that you could set it, but the minute value jumps from 10 to 15! Does anybody know how to fix it? :-?

Hi dahari1,
How can a binary clock jump to 15? :wink:

It will be easier to suggest a fix if you posted the code.

Well, it works fine until it gets to 10 then it jumps to 15. :stuck_out_tongue: I'll post the code as soon as I can.

How can a binary clock jump to 15?

I'm desperately trying to come up with a good second half for "There are 15 kinds of binary clocks ... " but I have never been that creative when it comes to things like that.
:-X

I'm desperately trying to come up with a good second half for "There are 15 kinds of binary clocks ... " but I have never been that creative when it comes to things like that.

...."ones that are accurate, and those with overflows..."

;D

I accidentally fixed the program! But here it is anyway!

int hr1 = 2;
int hr2 = 3;
int hr3 = 4;
int hr4 = 5;
int mn1 = 6;
int mn2 = 7;
int mn3 = 8;
int mn4 = 9;
int mn5 = 10;
int mn6 = 11;
int pm = 12;
int sec = 13;
int hrc;
int mnc;
int secc;

void setup()
{
pinMode(hr1, OUTPUT);
pinMode(hr2, OUTPUT);
pinMode(hr3, OUTPUT);
pinMode(hr4, OUTPUT);
pinMode(mn1, OUTPUT);
pinMode(mn2, OUTPUT);
pinMode(mn3, OUTPUT);
pinMode(mn4, OUTPUT);
pinMode(mn5, OUTPUT);
pinMode(mn6, OUTPUT);
pinMode(pm, OUTPUT);
pinMode(sec, OUTPUT);
hrc = 1;
mnc = 0;
secc = 0;
}

void loop()
{
  secc = secc + 1;
  digitalWrite(sec, HIGH);
  delay(10);
  digitalWrite(sec, LOW);
  if (secc == 60)
  {
    secc = 0;
    mnc = mnc + 1;
    if (mnc == 60)
    {
      mnc = 0;
      hrc = hrc + 1;
      if (hrc == 13)
      {
        hrc = 1;
      }
    }
  }
  
  switch (mnc)
  {
    case 0:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 1:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 2:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 3:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 4:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 5:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 6:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 7:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 8:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 9:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 10:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 11:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 12:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 13:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 14:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 15:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, LOW);
    break;
    
    case 16:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 17:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 18:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 19:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 20:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 21:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 22:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 23:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 24:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 25:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 26:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 27:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 28:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 29:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 30:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 31:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, HIGH);
    digitalWrite(mn6, LOW);
    break;
    
    case 32:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 33:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 34:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 35:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 36:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 37:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 38:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 39:
    digitalWrite(mn1, HIGH);
    digitalWrite(mn2, HIGH);
    digitalWrite(mn3, HIGH);
    digitalWrite(mn4, LOW);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    break;
    
    case 40:
    digitalWrite(mn1, LOW);
    digitalWrite(mn2, LOW);
    digitalWrite(mn3, LOW);
    digitalWrite(mn4, HIGH);
    digitalWrite(mn5, LOW);
    digitalWrite(mn6, HIGH);
    bre

Huh, my program is so big it wouldn't put it all on there, but you get the general idea. The problem was that I was simply missing the "break;" statements for cases 11 - 14 in the switch, so it scrolled through 11 - 14 as fast as it could!

You would be better off replacing the massive switch() statement with
something like the following:

digitalWrite(mn1, mnc & 1);
digitalWrite(mn2, (mnc >> 1) & 1);
digitalWrite(mn3, (mnc >> 2) & 1);
digitalWrite(mn4, (mnc >> 3) & 1);
digitalWrite(mn5, (mnc >> 4) & 1);
digitalWrite(mn6, (mnc >> 5) & 1);

If you don't understand why that works, let that be an exercise to go
figure out why it works! :slight_smile: and why it uses much less memory!

Wow your code is a bit long and as you have found it is error prone.

If you dive a little deeper into the Arduino hardware you will find that digital I/O pins 2 through 7 are connected to the output port named D and digital I/O pins 8 through 13 are connected to output port named B.

It would make the code much simpler if you could connect the 6 minute LEDs to port D and the 4 hour, PM and sec LEDs to port B. That is you can set all of the LEDs at once for a particular port by assigning the appropriate value into either the PORTB or PORTD registers on the mega328 or mega168 chip.

Your setup() routine to set ports B and D as outputs (replacing all of the pinMode functions) would look something like this:

 int hrc;
 int mnc;
 int secc;
 int PM;

void setup() {
   DDRB = 0xFF;
   DDRD = 0xFF;
   PORTB = 0;
   PORTD = 0;
   Serial.begin(9600);

  // set time
  secc = 0;
  mnc = 0;
  hrc = 0;
  PM = 0;
}

and core part of the routine to set the minutes and hours might look something like this:

void loop() {
  secc = secc + 1;
  if (secc == 60)
  {
    secc = 0;
    mnc = mnc + 1;
    if (mnc == 60)
    {
      mnc = 0;
      hrc = hrc + 1;
      if (hrc == 12)
      {
        PM = 16; // bit value for PM indicator
      }
      if (hrc == 13)
      {
        hrc = 1;
      }
      
      // need to handle case for PM going to AM
      // PM = 0;
    }
  }
  
 // Using these test lines affects accuracy
 //Serial.print("Mins: "); 
 //Serial.print(mnc * 4, HEX);
 //Serial.print(" Hrs: ");
 //Serial.println(hrc + PM, HEX);
 
 // display minutes - need to shift 2 bits to the left
 PORTD = mnc << 2;
 
 // display hours, PM, and secs
 PORTB = hrc + PM + 32;
 
 // turn off seconds LED
 delay(500);
 PORTB = hrc + PM;
 
 // now need to wait remainder of a second
 // there is a small inaccuracy here because of the time
 // taken to update the LEDS
 delay(500);
}

I didn’t deal with the PM indicator properly but as I didn’t find that in your posted code either, I will leave it to you to resolve.

If you cannot move the LEDs on the digitial I/O pins to match what I am suggesting, it will still work. You just need to set the appropriate bit patterns into each of the PORTB and PORTD registers.

You don’t need to use low level direct port i/o to derive binary values and drive pins. The following example uses the Arduino bitRead function to convert from decimal to binary. The advantage of doing this using the arduino pins is that any group of sequential pins can be used for each of the digits.

// bitSet
// demonstrates using the bitSet function to convert a decimal number to Binary


const int nbrHrBits = 4;   // the maximum number of bits in the binary number for hours
const int firstHrPin = 3;  // first pin is connected to the least significant bit of the binary number

const int nbrMinBits = 6;  // minutes
const int firstMinPin = 6;

const int nbrSecBits = 6;  // seconds
const int firstSecPin = 14;  // the analog pins are used as digital to display  seconds

// macros from DateTime.h
/* Useful Constants */
#define SECS_PER_MIN  (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY  (SECS_PER_HOUR * 24L)

/* Useful Macros for getting elapsed time */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)  
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) 

void setup() 
{ 
  for(int i=0; i < nbrHrBits; i++)
    pinMode(i + firstHrPin, OUTPUT);
  for(int i=0; i < nbrMinBits; i++)
    pinMode(i+firstMinPin, OUTPUT);
  for(int i=0; i < nbrSecBits; i++)
    pinMode(i+firstSecPin, OUTPUT);     
} 


void loop()
{
  long time = millis() / 1000;
  int hours = numberOfHours(time);
  int minutes = numberOfMinutes(time);
  int seconds = numberOfSeconds(time);

  showBinary(hours,nbrHrBits,firstHrPin);
  showBinary(minutes,nbrMinBits,firstMinPin); 
  showBinary(seconds,nbrSecBits,firstSecPin);

  delay(1000); 
} 

// this function sets the pins starting from firstPin to the binary value of the given number
void showBinary( int number, int firstPin, int nbrPins)
{
  for(int bit=0; bit < nbrPins; bit++)
  {
    boolean isBitSet =  bitRead(number, bit); // isBitSet will be true if given bit is set i[b][/b]n this channel
    digitalWrite(bit + firstPin, isBitSet);      
  }  
}

Wow, I really didn't know you could do things like that. But I guess I can learn from it. :smiley: By the way my program was not quite complete, it did not have anything to do with am or pm and you couldn't set it. :-[

The code I posted above uses a 24 hour clock. To convert that to a 12 hour clock you can use the following function:

byte hours24To12(byte hours){
  if( hours == 0 )
    return 12; // 12 midnight
  else if( hours  > 12)
    return hours - 12 ;
  else
    return hours ;
}

Determining AM/PM is easier, if the 24 hour value is < 12 its AM , otherwise its PM

You don't need to use low level direct port i/o to derive binary values and drive pins. The following example uses the Arduino bitRead function to convert from decimal to binary. The advantage of doing this using the arduino pins is that any group of sequential pins can be used for each of the digits.

Mem, of course your code is better. I am still learning too. It might not be obvious to the OP but by using the call to millis() you have also avoided the problem of inaccuracy by using the System time rather than a delay loop.

It might not be obvious to the OP but by using the call to millis() you have also avoided the problem of inaccuracy by using the System time rather than a delay loop.

yep.

Mike, I was curious why you chose to use direct port i/o instead of digitalWrite. digitalWrite is one of the fundamental capabilities of Arduino and is almost always the best choice for controlling pins.

will you be posting the full PDE or code when this is 100% working? :slight_smile:
I fancy trying to build one but lack any and all programming skills XD

I create a serial binary clock.
I did pwm on pin13, and it drives out the led in binary serially

  • low pwm for zero
  • high pwm for one

LSB to MSB

  • hour: 4 bits
  • 10 minute digit: 3 bits
  • 1 minute digit: 4 bits

I did this as a quick project since it required no external circuit.
Of course I put the 100ohms between reset and Vcc so I don’t reset the circuit if I turn on the Arduino software or access the serial port

The program also dumps to the serial port including the time in milliseconds (more of a debug for me).

Time can be set through the serial port.

But setting the is a little hard since I display the time 3times a minute (of course that can be hardcoded) and waits until the display is done.

I thought this is a good beginner’s project for people starting off.
Also allowed me to validate my own time keeping program.

Measuring the gain/loss right now. Want to see how accurate I can get it. Right now losing 100ms/hour.

Next stop an Ambient Orb (with a clock/hour signal feature).

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247846222

Sorry, did I post something wrong here?

I was not sure either what that meant. Perhaps he is hinting that he would like to see your code. :wink:

something about posting code in a code box or quote, and not posted in the main message.

like this

also i would like to see the finished code :slight_smile: