randtekk
Published © LGPL

Retro 1980s LED Clock/Count Up Timer

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

IntermediateWork in progress7,442
Retro 1980s LED Clock/Count Up Timer

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Red LED display-4 digit,
×1
Photo resistor
Photo resistor
×1
Resistor 1k ohm
Resistor 1k ohm
×4
Resistor 560 ohm
×1
General Purpose Transistor NPN
General Purpose Transistor NPN
×1
5 mm LED: Red
5 mm LED: Red
×4
Real Time Clock Module, DS3231
×1

Story

Read more

Schematics

Retro LED Clock/Timer Schematic-Updated

Schematic for Retro Clock

Fritzing Schematic-RetroClock

Code

Retro Clock/Timer Code

Arduino
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); 

}

Credits

randtekk

randtekk

5 projects • 20 followers

Comments