janux
Published © GPL3+

JX Clock (ASC)

Need a digital clock? Make it yourself!

BeginnerFull instructions provided1 hour139
JX Clock (ASC)

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
SparkFun 7-Segment Serial Display - Red
SparkFun 7-Segment Serial Display - Red
×1
Seeed Studio DS1307 Generic RTC Module
×1
Resistor 10k ohm
Resistor 10k ohm
×1
Photo resistor
Photo resistor
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
×3

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Optional if you want to mount everything on a perforated base

Story

Read more

Schematics

JX Clock schematics

Designed with Autodesk Eagle

Fritzing assembly (updated)

I had inverted the two Pins CLK and DIO, I updated the drawing. Sorry.

Top view of the prototype

Code

JX Clock

C#
/*
JX ASC [Another Stupid Clock] :D
Written on December 2024 by Janux
*/

#include "RTClib.h"         //Adafruit RTClib v2.1.4
#include "GyverTM1637.h"    //GyverTM1637     v1.4.2
#include <arduino-timer.h>  //arduino-timer   v3.0.1

#define CLK 2        //Display clock pin
#define DIO 3        //Display data pin
#define BRI 5        //button S1 brigtness
#define ADJ 6        //button S2 adjust
#define SET 7        //button S3 setup
#define LightPIN A0  //analog pin for photocell
#define CLOCKMODE 1  //Normal mode
#define SETUPMODE 2  //Setup mode


byte mode = CLOCKMODE;
byte hour, minute, second;
byte lastSecond = 0, digit = 0;
bool Update, flag;
unsigned long lastPress;
DateTime time;

//Brightness: GyverTM1637 lib accept value from 0 to 7 but some cheaper module not vary over 4
const byte maxBrightness = 4;  //25, 50, 75, 100%
byte BRIGHTNESS = 0;           //0 = auto
byte autoLevel;

RTC_DS1307 rtc;                       // create a rtc object
GyverTM1637 disp(CLK, DIO);           // create a display object
auto timer = timer_create_default();  // create a timer with default settings

bool SERIALDEBUG = true;

void setup() {
  Serial.begin(57600);

  pinMode(SET, INPUT_PULLUP);  // Buttons pins as input
  pinMode(ADJ, INPUT_PULLUP);
  pinMode(BRI, INPUT_PULLUP);

  rtc.begin();                 //Initialize DS1307 module

  // ==========================================================================================================
  //  Compile time compensation
  //
  bool both = false;
  bool setClockTime = both;           // if true set the DS1307 clock at the compile DateTime
  bool applyTimeCompensation = both;  // if true apply a timGap compiling compensation to RTC Clock
  const int timeGap = 8;              // # of compensation seconds

  // ==========================================================================================================
  //
  //  1) set setClockTime to true and upload the code to Arduino
  //     the internal clock of the RTC module will be updated with the system date and time;
  //     if even applyTimeCompensation is true the internal clock of the RTC module will be moved
  //     forward by the number of seconds assigned to the timeGap const;
  //
  //  2) set both setClockTime and applyTimeCompensation to false and re-upload the code to Arduino
  //     for the second time or upload other code that does not update the RTC time;
  //
  //  NOTE: When applyTimeCompensation is true it is better to disable the serial monitor before upload
  //        this is because if the serial monitor is active the code will be executed twice after upload.
  // ==========================================================================================================

  if (setClockTime) {
    // Next line sets the DS1307 time to the exact date and time (Computer datetime) the sketch was compiled:
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

    if (applyTimeCompensation) {
      DateTime now = rtc.now();
      // Next line sets the DS1307 time to the date and time + timeGap the sketch was compiled 
      rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second() + timeGap));
    }
  }
  // ==========================================================================================================

  disp.brightness(BRIGHTNESS);
  timer.every(500, updateClock);  //update display every 500 millis (0.5 second)
}

void loop() {
  mainClock();
  if (SERIALDEBUG) PrintToSerial();
}

void mainClock() {

  switch (mode) {
    // ----------------------------------------------------------------------
    // NORMAL OPERATION
    // ----------------------------------------------------------------------
    case CLOCKMODE:

      if (Update) {
        disp.displayClockScroll(hour, minute, 75);
        Update = false;
      }
      timer.tick();

      // ----------------------------------------------------------------------
      // Button BRI change Brightness: 0 Auto, >0 manual
      // ----------------------------------------------------------------------
      if (buttonPress(BRI)) {
        BRIGHTNESS++;
        if (BRIGHTNESS > maxBrightness) BRIGHTNESS = 0;
        if (BRIGHTNESS > 0) {
          disp.brightness(BRIGHTNESS - 1);
        } else {
          disp.point(false);
          disp.displayByte(_A, _u, _t, _o);
          delay(1000);
        }
      }

      // ----------------------------------------------------------------------
      // Button SET ENTER in SETUP MODE and select hours digits
      // ----------------------------------------------------------------------
      if (buttonPress(SET)) {
        disp.point(true);
        disp.displayClock(hour, minute);
        digit = 0;
        mode = SETUPMODE;
      }
      break;

      // ----------------------------------------------------------------------
      // SETUP MODE
      // ----------------------------------------------------------------------
    case SETUPMODE:
      flashDigit(digit);  //start flashing current digit

      // ----------------------------------------------------------------------
      // BUTTON SET in setup mode SELECT minutes or EXIT SETUP without change
      // ----------------------------------------------------------------------
      if (buttonPress(SET)) {
        digit += 2;
        if (digit < 4) {
          disp.displayClock(hour, minute);
        } else {
          digit = 0;
          mode = CLOCKMODE;  //return to normal clock
        }
      }

      // ----------------------------------------------------------------------
      // BUTTON ADJ in setup mode CHANGE hours or minutes VALUE
      // ----------------------------------------------------------------------
      if (buttonPress(ADJ)) {
        if (digit == 0) hour++;
        if (hour > 23) hour = 0;

        if (digit == 2) minute++;
        if (minute > 59) minute = 0;
      }

      // ----------------------------------------------------------------------
      // BUTTON BRI in SETUP MODE save new time to rtc and EXIT SETUP
      // ----------------------------------------------------------------------
      if (buttonPress(BRI)) {
        rtc.adjust(DateTime(time.year(), time.month(), time.day(), hour, minute, 0));  //update rtc value
        disp.displayClock(hour, minute);
        mode = CLOCKMODE;  //return to normal clock
      }
      break;
  }
}

// Called by timer
void updateClock() {

  time = rtc.now();
  hour = time.hour();
  minute = time.minute();
  second = time.second();

  toggleDots();
  if (BRIGHTNESS < 1) autoBrightness();

  Update = true;  //enable display update
}

// --------------------------------------------------------------------------------------------------------
// Flashes dots
// --------------------------------------------------------------------------------------------------------
void toggleDots() {
  flag = !flag;
  disp.point(flag);
}

// --------------------------------------------------------------------------------------------------------
// Auto adjust display brigtness
// --------------------------------------------------------------------------------------------------------
void autoBrightness() {
  int maxLight = 1024;
  autoLevel = constrain(map(analogRead(LightPIN), 0, maxLight, 0, maxBrightness), 0, maxBrightness);
  disp.brightness(autoLevel);
}

// --------------------------------------------------------------------------------------------------------
// Flashes hours or minutes when setting the time
// --------------------------------------------------------------------------------------------------------
void flashDigit(byte xpos) {
  flag = !flag;
  if (flag) {
    disp.displayClock(hour, minute);
  } else {
    disp.displayByte(xpos + 0, _empty); //clear the tens
    disp.displayByte(xpos + 1, _empty); //clear the units
  }
  delay(250);
}

// --------------------------------------------------------------------------------------------------------
// buttonPress function with debouncing
// --------------------------------------------------------------------------------------------------------
bool buttonPress(byte button) {
  if (digitalRead(button) == LOW) {                     //Detect whether the button is pressed
    unsigned long nowPress = millis();
    unsigned long buttonChange = nowPress - lastPress;  //Compared to the last time the button was pressed
    if (buttonChange > 500) {                           //Whether the key spacing is greater than 500ms
      lastPress = millis();                             //Record the time when the key is pressed
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}

// --------------------------------------------------------------------------------------------------------
// Print RTC Time and some debug informations on serial monitor
// --------------------------------------------------------------------------------------------------------
void PrintToSerial() {
  char timebuf[] = "00:00:00";
  if (Serial) {
    if (second != lastSecond) {

      sprintf(timebuf, "%02d:%02d:%02d", hour, minute, second);
      Serial.print(F("RTC Time: "));
      Serial.print(timebuf);

      Serial.print(F("\t LightLevel= "));
      Serial.print(analogRead(LightPIN));
      if (BRIGHTNESS < 1) {
        Serial.print(F(" -> Auto Brightness= "));
        Serial.println(autoLevel);
      } else {
        Serial.print(F(" - Manual Brightness= "));
        Serial.println(BRIGHTNESS);
      }

      lastSecond = second;
    }
  }
}

//eof

Credits

janux
4 projects • 18 followers
I have always been a technology enthusiast, at 13 I started using a soldering iron and I already knew what a transistor was.
Contact

Comments

Please log in or sign up to comment.