LED Clock

Difficulty Level = 3 [What's this?]

I harvested this LED clock display from an ancient VCR and wrote an Arduino sketch to drive the display. First I experimented with the leads to understand which leads controlled what behavior. There are 4 digits on the display and there are 4 corresponding leads for positive voltage to drive them (the Arduino pins connected with the resistors). Then there are 7 ground pins (the yellow wires) that correspond to the seven segments on each digit (well, the leftmost digit only has 2 segments). There’s also a pin for the colon but one of the LEDs is burned out.

ClockShield!

ClockShield!

This display is driven in a typical manner by multiplexing between the 7 segments of each digit. The display is driven by sinking current on each of the seven segments in sequence, and sending current into the leads for any digit that needs to display that segment. Ouch, that’s confusing, so I’ll give an example. The first display ground pin (connected to pin 2 on the Arduino) is for the horizontal middle segment. Some numbers need the horizontal middle segment turned on, right? Numbers ’0′, ’2′, ’3′, ’4′, ’5′, ’6′, ’8′, and ’9′. So, the code sets the ground pin for this segment to LOW (to sink current), and for each of the four digits that need that segment, we set the digit pin to HIGH. If the number to display is ’1027′, then when Arduino pin 2 is LOW (for the horizontal middle segment), we set the digit pins HIGH for the two middle digits (the ’0′ and the ’2′). Then we repeat this process for each of the 7 segments. If we do it fast enough, then persistence of vision makes it look like the LEDs are all on at the same time.

If you are unfamiliar with this multiplexing I’ve tried to explain, then study the code for the sketch. The array ‘number’ contains the information about what segments need to be on for each number. This might seem hard to understand at first, but I can guarantee an “ah ha!” moment when you get it.

// These are indexes into the groundPins array
#define MIDDLE 0
#define UPPER_L 1
#define LOWER_L 2
#define BOTTOM 3
#define LOWER_R 4
#define UPPER_R 5
#define TOP 6

int groundPins[7] = {2, 3, 4, 5, 6, 7, 8};
int digitPins[4] = {9, 10, 11, 12}; // positive voltage supply for each of the 4 digits
int ON = HIGH;
int OFF = LOW;
int number[10][7]; // holds information about which segments are needed for each of the 10 numbers
int digit[4]; // holds values for each of the 4 display digits

int hours = 12;
int minutes = 8;
int elapsedMinutes = 0;
int seconds = 0;

void setup()
{
  initNumber();

  for(int i=0; i < 7; i++) {
    pinMode(groundPins[i], OUTPUT);
    digitalWrite(groundPins[i], HIGH);
  }
  for(int i=0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], LOW);
  }
}

void loop() {
  int n = 0;
  unsigned long time = millis() - (elapsedMinutes * 60000);
  seconds = (time / 1000);
  if (seconds > 60) {
    seconds = 0;
    minutes++;
    elapsedMinutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours > 12) {
        hours = 1;
      }
    }
  }

  n = (hours * 100) + minutes;
  setDigit(n);

  for(int g=0; g < 7; g++) {
    digitalWrite(groundPins[g], LOW);
    for(int i=0; i < 4; i++) {
      if (digit[i] < 0) {
        continue;
      }
      digitalWrite(digitPins[i], number[digit[i]][g]);
    }
    delay(getDelay());
    digitalWrite(groundPins[g], HIGH);
  }
}

void setDigit(int n) {
  n = n % 2000;
  digit[0] = n % 10;
  digit[1] = (n / 10) % 10;
  if ((digit[1] == 0) && (n < 10)) {
    digit[1] = -1;
  }
  digit[2] = (n / 100) % 10;
  if ((digit[2] == 0) && (n < 100)) {
    digit[2] = -1;
  }
  digit[3] = (n / 1000) % 10;
  if (digit[3] == 0) {
    digit[3] = -1;
  }
}

int getDelay() {
  if (millis() > 10000) {
    return 0;
  } else {
    return (int) (((10000 - millis()) / 10000.0) * 125);
  }
} 

void initNumber() {
  number[0][MIDDLE]  = OFF;
  number[0][UPPER_L] = ON;
  number[0][LOWER_L] = ON;
  number[0][BOTTOM]  = ON;
  number[0][LOWER_R] = ON;
  number[0][UPPER_R] = ON;
  number[0][TOP]     = ON;

  number[1][MIDDLE]  = OFF;
  number[1][UPPER_L] = OFF;
  number[1][LOWER_L] = OFF;
  number[1][BOTTOM]  = OFF;
  number[1][LOWER_R] = ON;
  number[1][UPPER_R] = ON;
  number[1][TOP]     = OFF;

  number[2][MIDDLE]  = ON;
  number[2][UPPER_L] = OFF;
  number[2][LOWER_L] = ON;
  number[2][BOTTOM]  = ON;
  number[2][LOWER_R] = OFF;
  number[2][UPPER_R] = ON;
  number[2][TOP]     = ON;

  number[3][MIDDLE]  = ON;
  number[3][UPPER_L] = OFF;
  number[3][LOWER_L] = OFF;
  number[3][BOTTOM]  = ON;
  number[3][LOWER_R] = ON;
  number[3][UPPER_R] = ON;
  number[3][TOP]     = ON;

  number[4][MIDDLE]  = ON;
  number[4][UPPER_L] = ON;
  number[4][LOWER_L] = OFF;
  number[4][BOTTOM]  = OFF;
  number[4][LOWER_R] = ON;
  number[4][UPPER_R] = ON;
  number[4][TOP]     = OFF;

  number[5][MIDDLE]  = ON;
  number[5][UPPER_L] = ON;
  number[5][LOWER_L] = OFF;
  number[5][BOTTOM]  = ON;
  number[5][LOWER_R] = ON;
  number[5][UPPER_R] = OFF;
  number[5][TOP]     = ON;

  number[6][MIDDLE]  = ON;
  number[6][UPPER_L] = ON;
  number[6][LOWER_L] = ON;
  number[6][BOTTOM]  = ON;
  number[6][LOWER_R] = ON;
  number[6][UPPER_R] = OFF;
  number[6][TOP]     = ON;

  number[7][MIDDLE]  = OFF;
  number[7][UPPER_L] = OFF;
  number[7][LOWER_L] = OFF;
  number[7][BOTTOM]  = OFF;
  number[7][LOWER_R] = ON;
  number[7][UPPER_R] = ON;
  number[7][TOP]     = ON;

  number[8][MIDDLE]  = ON;
  number[8][UPPER_L] = ON;
  number[8][LOWER_L] = ON;
  number[8][BOTTOM]  = ON;
  number[8][LOWER_R] = ON;
  number[8][UPPER_R] = ON;
  number[8][TOP]     = ON;

  number[9][MIDDLE]  = ON;
  number[9][UPPER_L] = ON;
  number[9][LOWER_L] = OFF;
  number[9][BOTTOM]  = ON;
  number[9][LOWER_R] = ON;
  number[9][UPPER_R] = ON;
  number[9][TOP]     = ON;
}

Now for the fun. The getDelay() method returns a delay based on how long the sketch has been running. First we start with a longer delay (125ms) between each segment so you can see visually how the digits are being rendered. Over the course of 10 seconds, we reduce the delay to 0. This way you can see exactly how quickly rendering the display causes you to see the digits without ficker even though each segment is being displayed separately! Cool, huh?




Published by Michael, on October 25th, 2009 at 9:53 pm. Filed under: Arduino,Level 3. | 4 Comments |





4 Responses to “LED Clock”

  1. this clock is very good, and the initial animation is a very good idea.

    I modified it for working on a Common Cathode Display.

    a question, do you considered in your sketch the Digit1 on the rihgt or left ?
    normally the datasheet of display consider Digit1 on left.

    a tips, use official name for 7 segment, a,b,c,d,e,f,g in the sketch give more readibility.

    Comment by Testato on October 10, 2010 at 4:53 PM



  2. [...] some parts and found some nice 4 segment LED displays. I found some code for a simple clock at nootropicdesign, and it did something pretty neat. It slowed down multiplexing so you could see it, then it would [...]

    Pingback by Multiplexing for a 7 year old | The Custom Geek on June 29, 2011 at 2:53 AM



  3. I was looking for something to repair a 4 digit LED clock that I built in the 70′s using a AY51224A clockchip.
    I have a prototype going using a CC 4 digit display 5461AS with a UNO and a DS1307 RTC. Initial time setting is done over the serial port, thereafter the battery in the RTC keeps the time even if power is removed. I wanted my clock to be 24 hrs so that has been too.
    Of course I kept the neat slow multiplex feature in with a switch to enable it as The Custom Geek did.
    This is my first Arduino project.
    Many thanks for the push in the right direction!

    Comment by gm4jjj on January 25, 2014 at 11:58 AM



  4. I have added my version with RTC and set time over USB with automatic drift calculation and correction at https://sourceforge.net/projects/arduinoledclock/ Enjoy – it is free.

    Comment by gm4jjj on February 4, 2014 at 11:57 AM



Leave a Reply

*