Clock, I know, its been done.

My first project is to build a countdown clock from a 4 digit, 7 segment display. To start off on the basics I made a sketch and circuit to simply make a one digit 7 segment display count down from 9 to 0. However when I made this, I built it basically off of the blink routine, with assignment of each individual LED of the 7 segment to a pin and simply turning on and off pins in groups with a delay between. I want to simplify this so that I can move on to the 4 digit, which I know will require multiplexing (I'll ask about that in a later thread). I don't know how to write the code so that way I can have each number I want represented be assigned in the int part of sketch, or how to program arduino to control the pins with that int beginning. Could someone give me a nudge in the right direction?

Are you using any external hardware, other than the 7-segment displays and current limit resistors?

I would envision something like this, with your particular 7 segment displays and probably a PNP transistor instead of NPN (had that symbol readily available).
To multiplex, you drive the segments that you want on Low and turn on the transistor.

As for the other stuff, check out the stopwatch code here
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1292540097/30
it writes the time out via shift register (controlling 12V 7-segment displays), replace that with your direct drive multiplex code instead.

That code counts up; change the logic so that as you decrement the lowest digit, when it gets to 0, everything above rolls over:
ex, from 60:00, everything rolls over to 59:59, then at 59:50, 2 digits roll over to 59:49, at 59:00 3 digits roll over to 58:59, at 50:00 4 digits roll over to 49:59, etc.

I have 10:00 countdown timer, does the same thing.

So here is my code. I want to make it less redundant. I don't know how to do that cool window thing that I see all over the forum though.
I want to simplify this before I delve into the multiplexing and counting codes.

int ledPins[] = {2,3,4,5,6,7,8};


void setup() {                
  pinMode(ledPins[0], OUTPUT);//makes the 7 segment go to an 8, then blank
  pinMode(ledPins[1], OUTPUT);
  pinMode(ledPins[2], OUTPUT);
  pinMode(ledPins[3], OUTPUT);
  pinMode(ledPins[4], OUTPUT);
  pinMode(ledPins[5], OUTPUT);
  pinMode(ledPins[6], OUTPUT);
  digitalWrite(ledPins[0], LOW);
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], LOW);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], HIGH);
  digitalWrite(ledPins[1], HIGH);
  digitalWrite(ledPins[2], HIGH);
  digitalWrite(ledPins[3], HIGH);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], HIGH);  
  digitalWrite(ledPins[6], HIGH);
  delay(1000);
}

void loop() {
  digitalWrite(ledPins[0], LOW);//makes digit into a 0
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], LOW);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], HIGH);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 9
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 8
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], LOW);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 7
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], HIGH);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], HIGH);  
  digitalWrite(ledPins[6], HIGH);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 6
  digitalWrite(ledPins[1], HIGH);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], LOW);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 5
  digitalWrite(ledPins[1], HIGH);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], HIGH);//makes digit into a 4
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], HIGH);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], LOW);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 3
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], HIGH);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], LOW);//makes digit into a 2
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], HIGH);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], LOW);
  digitalWrite(ledPins[5], HIGH);  
  digitalWrite(ledPins[6], LOW);
  delay(1000);
  digitalWrite(ledPins[0], HIGH);//makes digit into a 1
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], HIGH);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], HIGH);  
  digitalWrite(ledPins[6], HIGH);
  delay(1000);
}

The 'cool window thing'
go back and modify your post
before the start of the code listing, click the # sign above, then put your listing in the middle of the
'code' and '/code' .
Let me read what you have in the meantime...

Man that's ugly code :slight_smile:

in setup maybe

for (int i = 0; i < 7; i++) {
   pinMode(ledPins[i], OUTPUT);
   digitalWrite(ledPins[i], LOW);

}

and repeat without the pinMode() bit after the delay for the HIGH setting.

What a shame you need a single pin from PORTB, it would be better to directly write to the port, but anyway maybe a writeDigit function like this

void writeDigit (byte bitpattern) {

   for (int i = 0; i < 7; i++) {
      digitalWrite(ledPins[i], (bitpattern & 1) == 0 ? LOW : HIGH);
      bitpattern >> 1;
   }
}

Then in the main loop

writeDigit (B01000000); // 0 
writeDigit (B00010000); // 9 
writeDigit (B00000000); // 8

etc

Rob

Redundant - make an array of your bits to be high/low

number_to_display [ 0 ] = B00100000; // '0' filled in bit 7, 6-5-4-3-2-1-0 come from your hi/lo listing
numbet_to_display [ 1 ] = B01111001;// '1'

then write out via shift register

shiftout(datapin,clockpin, MSBFIRST, number_to_display[tens_minutes]);

or set up a parallel port to write it out:

From the old forum in a posting by westfw:

"You can write to the output ports a full byte at a time by "dropping" below the level of the arduino libraries as using the gcc/avr capabilities directly:

PORTD = (byte) myvalue; // replace myvalue with number_to_display[tens_minutes]

Note that this will require you to figure out which pins on the arduino match up with which ports and bits ( PORTD is the only port where all the bits of the port go directly to arduino pins (0-7)) and it MAY introduce HW dependencies; other versions of arduino may or may not maintain the same mapping between arduino "pins" and AVR "ports and bits." "

There may be other ways to do this parallel write also.

Good info, I will tinker with this and post my success/epic fail.

The atmega328 doesn't really seem to be set up for parallel writes, more for serial in/out.
You might take a look at shiftout, or SPI for writing your data out.
I write to 8 digits using SPI talking to a MAX7221, no flickering in the display at all.

// ***********************************************************************************************
// Loop here endlessly, checking if time or score needs updating, if wireless message came in, 
// if touch lights are on
// ***********************************************************************************************
void loop()
{
  // check if time needs updating
  if (time_running == 1)  // time is counting down   {
    unsigned long currentMillis = millis();  // see how long its been

    if (currentMillis - previousMillis >= interval) // more than our quarter second interval?
    {
      // save the last time we okayed time updates 
      previousMillis = currentMillis; 
      // cycle the colon state - turn it off/on twice a second
     // one of the digits has colon ||'d into bit 7 before writing it, to go on/off
     quarter_interval = quarter_interval+1;
      if (colon == 0x80) // toggle the state of the colon bit
      {
        colon = 0x00;
      }
      else
      {
        colon = 0x80;
      }
      update_time = 1;   //  enable time display to be updated

      if (quarter_interval == 4) // we hit the one second update time
      {
        quarter_interval = 0;
        // update the time digits
        // cases: 
        // 0:01, final second - stop time, disable touch lights, sound buzzer
        // Tens of seconds rollover: time = x:50, x:40, x:30, x:20, x:10: decrement tens of seconds, rollover seconds to 9
        // Minutes rollover: time = 9:00, 8:00, etc. 2:00, 1:00: decrement ones of minutes, rollover tens of 
        // seconds to 5, ones of seconds to 9
          // 10:00: Roll all the digits over
        // otherwise: just roll over the seconds

        // Case: Final Second
        if ((minutes_ones == 0) && (seconds_tens == 0) && (seconds_ones == 1)) // don't need minutes_tens, can't have 10:01
        {
          time_running = 0;  // stop time running
          seconds_ones = 0;  // clear the last second
          updated = 1;  // fake a Case complete flag
          
        }  // end of  if final second

        // Case: x:50, x:40, x:30, x:20, x:10
        if ((seconds_tens >0) && (seconds_ones == 0))  // case for the last tens of seconds 
        {
          seconds_tens = seconds_tens - 1;  // decrement the tens
          seconds_ones = 9;  // rollover the ones
          updated = 1;
        }  // end of if 10 of seconds rollover

        // Case: 9:00, 8:00, etc 2:00, 1:00
        if ((minutes_ones > 0) && (seconds_tens == 0) && (seconds_ones == 0)) // case for the last ones of minutes
        { 
          minutes_tens = 0x00;  //
          minutes_ones = minutes_ones - 1;  // decrement the minutes
          seconds_tens = 5;  // rollover the tens of seconds;
          seconds_ones = 9;  // rollover the ones of seconds;
          updated = 1;
        } // end of if minutes rollover

        // Case: starting from 10:00
        if (minutes_tens == 0x01)  // roll over all digits
        {
          minutes_tens = 0x00;  // rollover the tens of minutes
          minutes_ones = 9;  // rollover the ones of mints;
          seconds_tens = 5;  // rollover the tens of seconds;
          seconds_ones = 9;  // rollover the ones of seconds; 
          updated = 1;
        } // end of if 10:00 rollover

        // General Case: just decrement the seconds
        if (updated == 0)  // nothing else updated - but don't decrement if = 0.
        {
          seconds_ones = seconds_ones - 1;
        }
        updated = 0;  // reset for next pass thru
      } // end of if quarter_interval
    } // end of reaching our interval
  } // end of if time_running
  else
  {
    update_time = 0;   // no time update this time around - probably don't need this
  }

// other code ...

} // end void loop

and elsewhere I have code that writes the data out whenever update_time==1, then resets it to 0 to wait for the next update
so you can see that the majority of the time the elapsed time is not at the 250mS or 1000mS point, and all this gets skipped so the code do other stuff.

Graynomad:

for (int i = 0; i < 7; i++) {

pinMode(ledPins[i], OUTPUT);
   digitalWrite(ledPins[i], LOW);

}




and repeat without the pinMode() bit after the delay for the HIGH setting.

Rob, what is this i=0 stuff, i don't understand how that works.

Thanks. I haven't gotten through all of the foundations yet.