Project in progress
Retro 1980s LED Clock/Count Up Timer

Retro 1980s LED Clock/Count Up Timer © LGPL

A retro digital clock with count up timer feature and automatic dimming to match ambient light conditions.

  • 3,736 views
  • 4 comments
  • 17 respects

Components and supplies

About this project

Overview

I started the clock project mainly because I thought it would be fun to make a retro LED digital clock. I also had been wanting a simple count-up timer to use for timing various tasks of relatively short duration, involved in the manufacture of a device I make which is then sold by a local company. It uses an Arduino Nano clone, a DS3231 Real Time Clock module, and a 4 digit LED display. I have also added a column of 4 5mm LEDs to the left of the clock display. They are used for AM/PM indication in clock mode, and Hours in timer mode. It is all constructed on a 2 3/4" x 2" prototyping board. Also used: 3 momentary contact pushbutton switches, wire, solder, 2K resistor, 4 1K resistors, a 560 ohm resistor, a photo-resistor, a NPN general purpose transistor, Dupont pins and headers. This project is still a work in progress, which I hope to make into a full tutorial once it is completed. Schematic and code (for the 4 LED column) have been updated

Circuitry

Nearly all of the wiring is done on the back of the proto-board (shown below). The display, RTC module, Nano, and 3 momentary contact push buttons all mount on the front of the board. The Nano is actually mounted in what some would consider an inverted position-the pins come through the board inserted from the bottom of the board. To make this work, I used strips of male header pins, with the pins pushed through the black plastic boss until one end is flush with the plastic. This allows slightly lower profile, and more favorable pin positioning for my circuit layout.

The circuitry is straightforward, the RTC communicates with the Nano over the I2C bus. Clock/timer data is sent to the LED display. A top-mounted photo-resistor connects to analog pin 7, and is used to automatically select one of 6 display brightness levels, based upon the level of ambient light striking the photo-resistor. PWM pulses from Nano pin D6 are routed to the base of transistor Q1 to control the brightness of the discreet LEDs by PWM switching of the return (ground) path of the LEDs..

Buttons

The buttons work as follows:

The left button (button 1) places into timer mode, and pauses/restarts the timer. Pressing and holding button 1 for 3 seconds toggles display of the leading zero of hours below 10, if clock is in 12 hour mode.

The middle button (button 2) is used in Clock mode to display the date, and in Timer mode to reset the timer to zero. Timer reset only works if timer is paused.

The right button (button 3) toggles between Clock mode and Timer mode displays. The clock can be displayed when the timer is running. Holding button 3 for 3 seconds enters Clock Set mode. Holding button 3 for 6 seconds toggles 12 hour/24 hour modes.

In clock set mode, buttons 1 and 2 are up/down buttons, button 3 accepts the current value and advances to the next. It is also used to save the clock setting at the end of the clock setting sequence.

Features Coming Soon: Clock setting via USB, Serial transmission of the Timer data (for time tracking program(s) on PC), EEPROM storage of configuration values, countdown timer, Alarm, maybe even FM radio. (Alarm and radio features would probably require a slightly larger cabinet to implement)

Code

Retro Clock/Timer CodeArduino
Controls the Retro clock/timer
#include <RTClib.h>
#include <tm1637.h>
#include <Wire.h>

RTC_DS3231 rtc;  
DateTime NOW;
bool timedOut;
bool modeClock;
bool modeTimer;
bool modeDateClock;
bool timerRunning;// use for pausing timer

uint8_t button1 = 11;// Pin Definitions
uint8_t button2 = 10;
uint8_t button3 = 9;
uint8_t led0 = 2;
uint8_t led1 = 3;
uint8_t led2 = 4;
uint8_t led3 = 5;
uint8_t ldr = A7;
uint8_t ledPWMPin = 6;

const int AM = 1;// Constants to set indicator LEDs to AM or PM or OFF (led0 = AM, led3=PM)
const int PM = 5;
const int NONE = 0;

uint8_t MONTHx = 0;// Field editing flags for setting clock
uint8_t DAYx = 1;
uint8_t YEARx = 2;
uint8_t DAYofWEEKx = 3;
uint8_t HOURx = 4;
uint8_t MINUTEx = 5;

long lapStartMillis;// Timer Lap Start Value
long totalMillis;// Timer Lapsed Time Count

uint8_t brightness;
bool clockMode_12 = true;
bool leadingZero = false;
char dspVal[8];// Char array to store values to be sent to display

void setup() {

  Serial.begin(9600);
  timedOut = false;
  if (! rtc.begin()) {// start RTC module communication
    Serial.println("Couldn't find RTC");
    //while (1);
  }
  if (rtc.lostPower()) {// This will initialize clock setting after battery change etc. when clock HAS NOT been set
    Serial.println("RTC needs set!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);
  pinMode(led0, OUTPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(ledPWMPin, OUTPUT);
  digitalWrite(led0, LOW);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);

  pinMode(ldr, INPUT);
  brightness = 3;
  modeClock = true;
  NOW = rtc.now();

  ledSetBrightness(3);
  ledSequence(1);
  ledSequence(0);
  tm1637Init(7, 8); // clock, data pins of LED Display
  tm1637SetBrightness(brightness);
}//  ******************************************* End of setup

void ledSequence(int cmd) {
  // display short sequences on the LED column.
  //Turn all LEDs OFF to start
  digitalWrite(led0, LOW);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
  if (cmd) {
    digitalWrite(led0, HIGH);
    delay(100);
    digitalWrite(led1, HIGH);
    delay(100);
    digitalWrite(led2,  HIGH);
    delay(100);
    digitalWrite(led3,  HIGH);
    delay(100);
    digitalWrite(led0, LOW);
    delay(100);
    digitalWrite(led1, LOW);
    delay(100);
    digitalWrite(led2,  LOW);
    delay(100);
    digitalWrite(led3,  LOW);
    delay(100);

  }
  else {
    digitalWrite(led3, HIGH);
    delay(100);
    digitalWrite(led2, HIGH);
    delay(100);
    digitalWrite(led1,  HIGH);
    delay(100);
    digitalWrite(led0,  HIGH);
    delay(100);
    digitalWrite(led3, LOW);
    delay(100);
    digitalWrite(led2, LOW);
    delay(100);
    digitalWrite(led1,  LOW);
    delay(100);
    digitalWrite(led0,  LOW);
    delay(100);
  }

}//  ******************************************* End of ledSequence

long numberGet(uint8_t myField, int startVal, int maxVal) {
  // Get user input for setting clock/timer/etc.
  bool gotNumber = false;

  //bool timeOut = millis()+10000;
  timedOut = false;
  int debounce = 30;
  char dspTemp[8];
  
  while (!gotNumber) {
    NOW = rtc.now();// This is only done here to provide flashing digits when setting.
    switch (myField) {
      case 0:

        if (NOW.second() & 1) {
           Serial.println("Setting Month");
          sprintf(dspTemp, "%02d   ", startVal);
        }
        else {
          sprintf(dspTemp, "  :  " );
        }

        break;
      case 1://day
        Serial.println("Setting Day");
        if (NOW.second() & 1) {
          sprintf(dspTemp, "   %02d", startVal);
        }
        else {
          sprintf(dspTemp, "  :  " );
        }

        break;
      case 2://year
        Serial.println("Setting Year");
        if (NOW.second() & 1) {
          sprintf(dspTemp, "%02d %02d", startVal / 100, startVal % 100);
        }
        else {
          sprintf(dspTemp, "     " );
        }

        break;

      case 4://hour
        if (NOW.second() & 1) {
          sprintf(dspTemp, "%02d   ", startVal);
        }
        else {
          sprintf(dspTemp, "  :  " );
        }

        break;

      case 5://minute
        if (NOW.second() & 1) {
          sprintf(dspTemp, "   %02d", startVal);
        }
        else {
          sprintf(dspTemp, "  :  " );
        }
        break;
    }
    tm1637ShowDigits(dspTemp);

    // Check for button presses here
    if (digitalRead(button1) == LOW) {
      delay(debounce);
      if (digitalRead(button1) == LOW) {

        while (digitalRead(button1) == LOW) { // Lets pause until button released

        }
      }
      startVal--;
      //timeOut = millis() + 10000;
      delay(300);
    }
    if (digitalRead(button2) == LOW) {
      delay(debounce);
      if (digitalRead(button2) == LOW) {

        while (digitalRead(button2) == LOW) { // Lets pause until button released

        }
      }
      startVal++;
      //timeOut = millis() + 10000;
      delay(300);
    }
    if (digitalRead(button3) == LOW) {
      delay(debounce);
      if (digitalRead(button3) == LOW) {

        while (digitalRead(button3) == LOW) { // Lets pause until button released

        }
      }
      gotNumber = true;
      if (myField < 5) { // DON'T delay if minutes field is being set.
        delay(300);
      }

    }
  }

  if (startVal > maxVal) {
    startVal = 0;
  }
  if (startVal < 0) {
    startVal = maxVal;
  }
  return (startVal);
}//  ******************************************* End of numberGet


void clockSet() {
  bool doneSetting = false;
  bool settingMonth = true;
  bool settingDay = false;
  bool settingWeekDay = false;
  bool settingYear = false;
  bool settingHours = false;
  bool settingMinutes = false;
  int myMonth, myDay, myYear, myHour, myMinute;

  NOW = rtc.now();
  myMonth = NOW.month();
  myDay = NOW.day();
  myYear = NOW.year();
  myHour = NOW.hour();
  myMinute = NOW.minute();
  Serial.println(myMonth);
  Serial.println(myDay);
  Serial.println(myYear);
  Serial.println(myHour);
  Serial.println(myMinute);

  while (!doneSetting) {

    while (settingMonth & !timedOut) { // Month Set routine here
      myMonth = numberGet(MONTHx, myMonth, 12);
      settingMonth = false;
      settingDay = true;
    }
    while (settingDay & !timedOut) {
      //Day Set Routine here
      myDay = numberGet(DAYx, myDay, 31);
      settingDay = false;
      settingYear = true;
    }
    while (settingYear & !timedOut) {
      // Year Set Routine here
      myYear = numberGet(YEARx, myYear, 3000);
      settingYear = false;
      settingHours = true;
    }
    while (settingHours & !timedOut) {
      // hour Set Routine here
      myHour = numberGet(HOURx, myHour, 23);
      settingHours = false;
      settingMinutes = true;
    }
    while (settingMinutes & !timedOut) {
      // Minute Set Routine here
      myMinute = numberGet(MINUTEx, myMinute, 59);
      settingMinutes = false;
      doneSetting = true;
    }

  }
  if (!timedOut) {
    rtc.adjust(DateTime(myYear, myMonth, myDay, myHour, myMinute, 0));
  }
  timedOut = false;
}//  ******************************************* End of clockSet

void ledSet(int setting) {// Set the 4 LEDs that display timer hours count/AM/PM
  static int oldSetting;

  if (oldSetting != setting) { // only update if setting changes
    //Turn all LEDs OFF to start
    digitalWrite(led0, LOW);
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);

    if (setting > 4) { // Display PM indication
      digitalWrite(led3, HIGH);
    }
    else {
      if (setting > 3) {
        digitalWrite(led3, HIGH);
      }
      if (setting > 2) {
        digitalWrite(led2, HIGH);
      }
      if (setting > 1) {
        digitalWrite(led1, HIGH);
      }
      if (setting > 0) {
        digitalWrite(led0, HIGH);
      }
    }
    oldSetting = setting;
  }
}//  ******************************************* End of ledSet

void ledSetBrightness(int setting) {
// Setting multipliers were chosen by trial and error, to best match the display brightness settings. 
// Other LED/resistor/display combinations may require different values. 
  Serial.println( setting);
  if (setting == 1) {
    analogWrite(ledPWMPin, setting * 25);
  }
  if (setting == 2) {
    analogWrite(ledPWMPin, setting * 25);
  }
  if (setting == 3) {
    analogWrite(ledPWMPin, setting * 40);
  }
  if (setting == 4) {
    analogWrite(ledPWMPin, setting * 50);
  }
  if (setting == 5) {
    analogWrite(ledPWMPin, setting * 51);
  }

}//  ******************************************* End of ledSetBrightness

void showClock() {

  NOW = rtc.now();
  int myHour = NOW.hour();
  bool morning = (myHour < 12); //
  int myMin = NOW.minute();
  if (myHour > 12) {

    myHour -= (12 * clockMode_12); //Displays 12 or 24 hour modes
  }
  if (NOW.second() & 1) {
    ledSet(NONE);
    if ((myHour < 10) && clockMode_12 && !leadingZero) {
      sprintf(dspVal, " %01d:%02d", myHour, myMin);

    }
    else {
      sprintf(dspVal, "%02d:%02d", myHour, myMin);

    }

  }
  else {
    if (morning) {
      ledSet(AM);
    }
    else {
      ledSet(PM);
    }
    if ((myHour < 10) && clockMode_12 && !leadingZero) {
      sprintf(dspVal, " %01d %02d", myHour, myMin);

    }
    else {
      sprintf(dspVal, "%02d %02d", myHour, myMin);
    }
  }

}//  ******************************************* End of showClock

void showTimer() {

   
  long currentMillis = totalMillis;

  if (timerRunning) {
    currentMillis = totalMillis + (millis() - lapStartMillis);
  }
  currentMillis /= 1000; // convert to seconds
  int tmrHours = (currentMillis / 60) / 60;
  if (tmrHours > 4) {
   
    tmrHours -= 4;
  }
  int curMins = (currentMillis / 60) % 60;
  int curSecs = currentMillis % 60;

  sprintf(dspVal, "%02d:%02d", curMins, curSecs);
  ledSet(tmrHours);

}//  ******************************************* End of showTImer

void readButtons() {

  long holdTimer;
  int debounce = 30;

  if (digitalRead(button3) == LOW) {
    delay(debounce);
    if (digitalRead(button3) == LOW) {
      holdTimer = millis();
      while (digitalRead(button3) == LOW) { // Lets pause until button released

      }
      if (millis() > holdTimer + 5000) {
        Serial.println ("clock Mode Changed");
        clockMode_12 = !clockMode_12;
        ledSequence(1);
        ledSequence(0);
        ledSequence(1);
        ledSequence(0);
      }

      else if (millis() > holdTimer + 2300) {
        ledSequence(1);
        Serial.println("Setting Clock");
        clockSet();

      }

      else {

        if (modeClock) {
          modeTimer = true;
          modeClock = false;
        }
        else if (modeTimer) {
          modeClock = true;
          modeTimer = false;
        }
        else if (modeDateClock) {

          modeClock = true;
          modeDateClock = false;
        }
      }

      delay(500);
    }
  }


  if (digitalRead(button1) == LOW) {
    delay(debounce);
    if (digitalRead(button1) == LOW) {

      holdTimer = millis();
      while (digitalRead(button1) == LOW) { // Lets pause until button released

      }
      if (millis() > holdTimer + 2300) {
        Serial.println ("Leading Zero Changed");
        leadingZero = !leadingZero;
        ledSequence(0);
        ledSequence(1);
      }
      else {
        modeTimer = true;
        modeClock = false;
        timerRunning = !timerRunning;
        if (timerRunning) { // Lap has just been started
          lapStartMillis = millis();

        }
        else { // Lap ending,
          totalMillis += millis() - lapStartMillis;

        }
      }
    }
  }
  if (digitalRead(button2) == LOW) {
    delay(debounce);
    if (digitalRead(button2) == LOW) {
      holdTimer = millis();

      while (digitalRead(button2) == LOW) { // Lets pause until button released

      }
      if (millis() > holdTimer + 6000) {
        Serial.println("Set Clock");
        delay(1000);
      }

      else if (millis() > holdTimer + 3000) {
        clockMode_12 = !clockMode_12;
      }

      else {
        if (!timerRunning) {
          totalMillis = 0;// Reset timer to 0
          sprintf(dspVal, "%02d %02d", 0, 0);
          tm1637ShowDigits(dspVal);

        }

      }
      delay(500);
    }
  }
}//  ******************************************* End of readButtons

void lightMeter() { //  Used to read light level and set brightness of LEDs/Display
  static int oldBrt;
  int myBrt = 6 - (analogRead(ldr) / 150 - 1);// Read value from Light Dependent Resistor,
  // convert to value from 1 to 5
  if (oldBrt != myBrt) {// Only adjsut if light reading changes
    ledSetBrightness(myBrt);
    tm1637SetBrightness(myBrt);
    oldBrt = myBrt;
  }
}//  ******************************************* End of lightMeter

void loop() {

  readButtons();// Check to see if any buttons are pressed
  lightMeter();// check/adjust display brightness if needed

  if (modeClock) {
    showClock();
  }
  else if (modeTimer) {
    showTimer();
  }
  tm1637ShowDigits(dspVal); 

}

Schematics

Retro LED Clock/Timer Schematic-Updated
Schematic for Retro Clock
Clock schematic updated ya5qzc99ha
Fritzing Schematic-RetroClock
Clock fritzing c5p1ojvwno

Comments

Similar projects you might like

Retro View Timer

Project tutorial by yilmazyurdakul

  • 976 views
  • 1 comment
  • 2 respects

Adaptive LED Morse Code Decoder and Timer Interrupt

Project tutorial by shjin

  • 1,359 views
  • 0 comments
  • 12 respects

Smartphone-Controlled Helmet with LED Turn Indicators

Project showcase by Kristjan Berce

  • 2,189 views
  • 0 comments
  • 8 respects

Arduino 32x8 LED Matrix Info Display

Project showcase by ericBcreator

  • 23,275 views
  • 32 comments
  • 40 respects

Morse Code Kitchen Timer

Project showcase by oklima

  • 1,537 views
  • 0 comments
  • 8 respects

Music Reactive LED Strip

Project showcase by buzzandy

  • 23,857 views
  • 51 comments
  • 59 respects
Add projectSign up / Login