Project tutorial

Digital Clock with Auto Correction Display © CC BY-NC-ND

This clock can be rotated in any position keeping the digits readable even upside down or in a mirrored image!

  • 1,599 views
  • 0 comments
  • 3 respects

Components and supplies

Apps and online services

About this project

This project is about a digital clock with automatic correction of 7-Seg LED display and it is upgraded from my Digital Clock with Mirrored Display Driven by Accelerometers.

This clock can be rotated in any position keeping the digits readable even upside down or in a mirror image!

It is controlled by an Arduino and driven by accelerometers to find out the correct position in 3D coordinates.

Additionaly there is a feature to show the indoor ambient temperature in Celsius or in Fahrenheit degrees.

Now it is updated to Arduino 101.

The assemble is very simple and I hope you have fun using it!

Video 1

Video 2

1) Material List

MPU-6050 breakout:

The MPU-6050 breakout to be used with Arduino UNO consists in a triple axis accelerometer and gyroscope plus a temperature sensor with following specifications:

  • Chip: MPU-6050
  • Input Voltage: 3-5V
  • ADC: 16 bits
  • I/O: standard I2C
  • Gyroscope full-scale range: ±250, 500, 1000, 2000°/s
  • Accelerometer full-scale range: ±2, ±4, ±8, ±16g
  • Temperature sensor range: -40 to +85 ºC

Multi Function Shield (MFD):

The MFD can simplify and speed up the prototype development.

Main features:

  • 4 digit 7-segment LED display module driven by two serial 74HC595's
  • 4 x surface mount LED's in a parallel configuration
  • 10K adjustable precision potentiometer
  • 3 x independent push buttons
  • Piezo buzzer
  • DS18B20 temperature sensor interface
  • LM35 temperature sensor interface
  • Infrared receiver interface
  • Serial interface header for convenient connection to serial modules such as Bluetooth, wireless interface, voice module, a voice recognition module, etc.

Arduino 101:

This version of the Arduino is no longer produced despite having interesting features such as temperature sensor, a 6-axis accelerometer and a gyroscope on board.

It is very useful for this project avoiding an external MPU.

2) Assembly

The assembly is very simple and does not need any schematics:

  • Insert the Multi Shield into the Arduino.
  • Fasten the MPU-6050 breakout on the Arduino board using a tiny screw.

There only 04 jumper wires to be connected:

  • Red wire: Vcc (+5V)
  • Black wire: Gnd
  • Green wire: SCL of MPU-6050 breakout to port #6 in the Multi Shield.
  • Yellow wire: SDA of MPU-6050 breakout to port #5 in the Multi Shield.

3) Setup

There are 3 buttons to setup the clock:

  • Left button: Press to adjust the hours. Quickly press to set up step by step. Continuous press to advance the hours quickly.
  • Center button: Set the minutes. Continuous press to advance the hours quickly.
  • Right button: a quick press to move for temperature mode.

Note: In Temperature Mode is possible to change the status to Fahrenheit or Celsius pressing the Left button.

4) Code

The main functions of the code are:

  • Reading of accelerometers inclination angles.
  • Calculation of the transfer function for the 7-seg LED display (see pictures).

With the angles is possible to detect the spacial position of the clock and decide what routine will be released:

  • Front View - Clock Stand Up
  • Front View - Clock Upside Down
  • Mirror View - Clock Stand Up
  • Mirror View - Clock Upside Down

Code

Digital_Clock_Automatic_Rotation_Multi-Shield_Arduino_101_V1_1.inoArduino
Code for Arduino 101
/*
  Project:    Digital Clock with Automatic Rotation of 7-Seg LED
  Author:     LAGSILVA
  Hardware:   Arduino 101 / Multi-Function Shield  
  Revision:   V1.1 (Arduino 101)
  Date:       26.Ago.2018
  License:    CC BY-NC-ND 4.0
              (Attribution-NonCommercial-NoDerivatives 4.0 International)
*/

#define SDA_PORT PORTD
#define SDA_PIN 5
#define SCL_PORT PORTD
#define SCL_PIN 6

#include <CurieTimerOne.h>
#include <CurieIMU.h>

#include <Time.h>                               // Time library
#include <TimeLib.h>

// Module connection pins (Digital Pins)
#define LATCH_PIN 4                             // Arduino 101 conection on Pin #4  = Latch of Display Module
#define CLK_PIN 7                               // Arduino 101 conection on Pin #7  = Clock of Display Module
#define DATA_PIN 8                              // Arduino 101 conection on Pin #8  = Data of Display Module

#define BTN_1_PIN A1
#define BTN_2_PIN A2
#define BTN_3_PIN A3

//    Front:       Upside Down:     Upside Down Mirror:     Front Mirror:
//      A               D                    D                   A
//     ----            ----                 ----                ----
//  F |    | B      C |    | E           E |    | C          B |    | F
//     -G -            -G -                 -G -                -G -
//  E |    | C      B |    | F           F |    | B          C |    | E
//     ----            ----                 ----                ----
//      D               A                    A                   D
//

//   Chars Code {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, , C, F}
byte N[] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6, 0xC6, 0x9C, 0x8E};

int hora, minuto;
int unidadeHora, unidadeMinuto, dezenaHora, dezenaMinuto, delayRefresh;
byte mirror, tempStatus, lastStatus, tCF;
unsigned long ti;
boolean ajustaHora = true, ajustaMinuto = true, mostraTemperatura = true;

// Variaveis para armazenar valores dos sensores
float AcX, AcY, AcZ;
int Temp;


void setup() {

  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);

  pinMode(BTN_1_PIN, INPUT);
  pinMode(BTN_2_PIN, INPUT);
  // pinMode(BTN_3_PIN, INPUT);

  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  CurieTimerOne.start(200000, kbdRead);

  CurieIMU.begin();

  // Set the accelerometer range to 2G
  CurieIMU.setAccelerometerRange(2);

  mirror = 1;             // Front View (No Mirror as default)
  tempStatus = 0;
  lastStatus = 0;
  tCF = 0;

}


void loop() {

  delayRefresh = 50;

  Temp = (CurieIMU.readTemperature() / 512) + 13;          // Read the temperature in Celsius degrees (C)

  CurieIMU.readAccelerometerScaled(AcX, AcY, AcZ);            // Read the accelerometer axis

  if (AcX < 0 && AcZ > 0) {
    mirror = 1;                                               // Front View (No Mirror)
  }

  if (AcX < 0 && AcZ < 0) {
    mirror = 3;                                               // Upside Down Mirror View
  }

  if (AcX > 0 && AcZ < 0) {
    mirror = 2;                                               // Front Mirror View
  }

  if (AcX > 0 && AcZ > 0) {
    mirror = 4;                                               // Front View (Upside Down)
  }

  hora = hour();
  minuto = minute();
  unidadeHora = hora % 10;
  dezenaHora = hora / 10;
  unidadeMinuto = minuto % 10;
  dezenaMinuto = minuto / 10;

  if (tempStatus == 0) {                                                        // Display only the Time (HH:MM)

    ti = millis();                                                              // Initial time for blinking dot

    while ((millis() - ti) < delayRefresh) {                                    // Timer in miliseconds to refresh the display

      if (mirror < 3) {                                                         // No Mirror (1) or Front Mirror (2) mode
        displayChars(N[dezenaHora], mirror, 0);                                 // Display Digit 0
        displayChars(N[unidadeHora], mirror, 1);                                // Display Digit 1
        displayChars(N[dezenaMinuto], mirror, 2);                               // Display Digit 2
        displayChars(N[unidadeMinuto], mirror, 3);                              // Display Digit 3
        displayChars(0, 1, 3);                                                  // Clear Digit 3 (last digit)
      }

      if (mirror >= 3) {                                                        // Up Side Down Mirror (3) or Front Upside Down (4) mode
        displayChars(N[dezenaHora], mirror, 3);                                 // Display Digit 3
        displayChars(N[unidadeHora], mirror, 2);                                // Display Digit 2
        displayChars(N[dezenaMinuto], mirror, 1);                               // Display Digit 1
        displayChars(N[unidadeMinuto], mirror, 0);                              // Display Digit 0
        displayChars(0, 1, 0);                                                  // Clear Digit 0 (last digit)
      }

      displayChars(1, 1, 1);                                                    // Display Dot at Digit 1

    }

  }

  if (tempStatus == 1) {                                                        // Display only the Temperature (C or F)

    if (tCF == 1) {
      Temp = Temp * 9 / 5 + 32;
    }

    ti = millis();                                                              // Initial time for blinking dot

    while ((millis() - ti) < delayRefresh ) {                                   // Timer in miliseconds to refresh the display

      if (mirror < 3) {                                                         // No Mirror (1) or Front Mirror (2) mode
        displayChars(N[Temp / 10], mirror, 0);                                  // Display tenth of Temperature
        displayChars(N[Temp % 10], mirror, 1);                                  // Display unit of Temperature
        displayChars(N[10], mirror, 2);                                         // Display symbol of Degrees
        if (tCF == 0) {
          displayChars(N[11], mirror, 3);                                       // Display "C (symbol of Celsius Degrees)
        }
        else {
          displayChars(N[12], mirror, 3);                                       // Display "F" (symbol of Fahrenheit Degrees)
        }
        displayChars(0, 1, 3);                                                  // Clear Digit 3 (last digit)
      }

      if (mirror >= 3) {                                                        // Up Side Down Mirror (3) mode
        displayChars(N[Temp / 10], mirror, 3);                                  // Display tenth of Temperature
        displayChars(N[Temp % 10], mirror, 2);                                  // Display unit of Temperature
        displayChars(N[10], mirror, 1);                                         // Display symbol of Degrees
        if (tCF == 0) {
          displayChars(N[11], mirror, 0);                                       // Display "C (symbol of Celsius Degrees)
        }
        else {
          displayChars(N[12], mirror, 0);                                       // Display "F" (symbol of Fahrenheit Degrees)
        }
        displayChars(0, 1, 0);                                                  // Clear Digit 0 (last digit)
      }

    }

  }

}


void displayChars(byte num, byte statusM, byte disp) {                            // Chars Display Routine

  byte k, charsM = 0;

  if (statusM == 1) {                                                             // No Mirror
    charsM = num;
  }

  if (statusM == 2) {                                                             // Front Mirror
    for (k = 0; k <= 7; k++) {
      charsM = bitWrite(charsM, 7 - k, bitRead(num, k));
    }
    charsM = (charsM << 4 | (charsM << 2) >> 4 & 12 ) | ((charsM & 64) >> 5);
  }

  if (statusM == 3) {                                                             // Upside Down Mirror
    for (k = 0; k <= 7; k++) {
      charsM = bitWrite(charsM, 7 - k, bitRead(num, k));
    }
    charsM = (charsM << 7 | (charsM << 1) & 124 ) | ((charsM & 64) >> 5);
  }

  if (statusM == 4) {                                                             // Front Upside Down
    charsM = ((num >> 2) << 5) | ((num >> 5 ) << 2) | (num & 2);
  }

  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLK_PIN, LSBFIRST, ~charsM);                                 // Display number
  shiftOut(DATA_PIN, CLK_PIN, LSBFIRST, 128 >> disp);                             // Set Digit (0-1-2-3)
  digitalWrite(LATCH_PIN, HIGH);

}


void kbdRead() {                                                                  // Push Buttons Reading

  ajustaHora = digitalRead(BTN_1_PIN);
  ajustaMinuto = digitalRead(BTN_2_PIN);
  mostraTemperatura = digitalRead(BTN_3_PIN);

  if (!ajustaHora && tempStatus == 0) {                                           // Set Hour
    adjustTime(3600);
    delayRefresh = 150;
  }

  if (!ajustaMinuto && tempStatus == 0) {                                         // Set Minute
    adjustTime(60);
    delayRefresh = 150;
  }

  if (!mostraTemperatura) {                                                       // Move to Temperature Mode
    tempStatus = (tempStatus + 1) % 2;
    delay(200);
  }

  if (!ajustaHora && tempStatus == 1) {                                           // Set to C or F
    tCF = (tCF + 1) % 2;
    delay(200);
  }

}
Digital_Clock_With_Automatic_Rotation_Using_Multi-Shield_V1_1.inoArduino
Code for Arduino UNO
/*   Project:    Digital Clock With Automatic Rotation of 7-Seg LED
 *   Author:     LAGSILVA
 *   Hardware:   Arduino 101 / Multi-Function Shield 
 *   Revision:   V1.1 (Arduino UNO R3)
 *   Date:       10.Jul.2018
 *   License:    CC BY-NC-ND 4.0
                 (Attribution-NonCommercial-NoDerivatives 4.0 International)
*/

#define SDA_PORT PORTD
#define SDA_PIN 5
#define SCL_PORT PORTD
#define SCL_PIN 6

#include <SoftWire.h>
#define MPU 0x68                                // I2C address for MPU6050
SoftWire Wire = SoftWire();

#include <Time.h>                               // Time library
#include <TimeLib.h>
#include <MsTimer2.h>                           // Timer library

// Module connection pins (Digital Pins)
#define LATCH_PIN 4                             // Arduino UNO conection on Pin #4  = Latch of Display Module
#define CLK_PIN 7                               // Arduino UNO conection on Pin #7  = Clock of Display Module
#define DATA_PIN 8                              // Arduino UNO conection on Pin #8  = Data of Display Module

#define BTN_1_PIN A1
#define BTN_2_PIN A2
#define BTN_3_PIN A3

//    Front:       Upside Down:     Upside Down Mirror:     Front Mirror:
//      A               D                    D                   A
//     ----            ----                 ----                ----
//  F |    | B      C |    | E           E |    | C          B |    | F
//     -G -            -G -                 -G -                -G -
//  E |    | C      B |    | F           F |    | B          C |    | E
//     ----            ----                 ----                ----
//      D               A                    A                   D
//

//   Chars Code
byte N[] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6, 0xC6, 0x9C, 0x8E};

int hora, minuto;
int unidadeHora, unidadeMinuto, dezenaHora, dezenaMinuto, delayRefresh;
byte mirror, tempStatus, tCF;
unsigned long ti;
boolean ajustaHora = true, ajustaMinuto = true, mostraTemperatura = true;


//Variaveis para armazenar valores dos sensores
int AcX, AcY, AcZ, Temp;


void setup() {

  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);

  pinMode(BTN_1_PIN, INPUT);
  pinMode(BTN_2_PIN, INPUT);
  pinMode(BTN_3_PIN, INPUT);

  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  MsTimer2::set(130, kbdRead);
  MsTimer2::start();

  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);

  //Inicializa o MPU-6050
  Wire.write(0);
  Wire.endTransmission(true);

  mirror = 1;             // Front View (No Mirror)
  tempStatus = 0;         // (0 = Time Mode / 1 = Temperature Mode)
  tCF = 0;                // (0 = Celsius / 1 = Fahrenheit)

}


void loop() {

  delayRefresh = 150;

  Wire.beginTransmission(MPU);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);

  //Solicita os dados do sensor
  Wire.requestFrom(MPU, 14, true);

  //Armazena o valor dos sensores nas variaveis correspondentes
  AcX = Wire.read() << 8 | Wire.read(); //0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  AcY = Wire.read() << 8 | Wire.read(); //0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ = Wire.read() << 8 | Wire.read(); //0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Temp = Wire.read() << 8 | Wire.read(); //0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)

  AcX = map(AcX, -16384, 16384, -90, 90);
  AcY = map(AcY, -16384, 16384, -90, 90);
  AcZ = map(AcZ, -16384, 16384, -90, 90);
  Temp = map(Temp, -16384, 16384, -40, 85) + 10;              // Personal correction factor for Temperature: +10


  if (-AcY > 0 && AcZ > 0) {
    mirror = 1;                                               // Front View (No Mirror)
  }

  if (AcY > 0 && -AcZ > 0) {
    mirror = 2;                                               // Mirror View
  }

  if (-AcY > 0 && -AcZ > 0) {
    mirror = 3;                                               // Mirror View (Upside Down)
  }

  if (AcY > 0 && AcZ > 0) {
    mirror = 4;                                               // Front View (Upside Down)
  }

  hora = hour();
  minuto = minute();
  unidadeHora = hora % 10;
  dezenaHora = hora / 10;
  unidadeMinuto = minuto % 10;
  dezenaMinuto = minuto / 10;

  if (tempStatus == 0) {                                                        // Display only the Time (HH:MM)

    ti = millis();                                                              // Initial time for blinking dot

    while ((millis() - ti) < delayRefresh) {                                    // Timer in miliseconds to refresh the display


      if (mirror < 3) {                                                         // No Mirror (1) or Front Mirror (2) mode
        displayChars(N[dezenaHora], mirror, 0);                                 // Display Digit 0
        displayChars(N[unidadeHora], mirror, 1);                                // Display Digit 1
        displayChars(N[dezenaMinuto], mirror, 2);                               // Display Digit 2
        displayChars(N[unidadeMinuto], mirror, 3);                              // Display Digit 3
        displayChars(0, 1, 3);                                                  // Clear Digit 3 (last digit)
      }

      if (mirror >= 3) {                                                        // Up Side Down Mirror (3) or Front Upside Down (4) mode
        displayChars(N[dezenaHora], mirror, 3);                                 // Display Digit 3
        displayChars(N[unidadeHora], mirror, 2);                                // Display Digit 2
        displayChars(N[dezenaMinuto], mirror, 1);                               // Display Digit 1
        displayChars(N[unidadeMinuto], mirror, 0);                              // Display Digit 0
        displayChars(0, 1, 0);                                                  // Clear Digit 0 (last digit)
      }

      displayChars(1, 1, 1);                                                    // Display Dot at Digit 1

    }

  }

  if (tempStatus == 1) {                                                        // Display only the Temperature (C or F)

    if (tCF == 1) {
      Temp = Temp * 9 / 5 + 32;
    }

    ti = millis();                                                              // Initial time for blinking dot

    while ((millis() - ti) < delayRefresh ) {                                   // Timer in miliseconds to refresh the display

      if (mirror < 3) {                                                         // No Mirror (1) or Front Mirror (2) mode
        displayChars(N[Temp / 10], mirror, 0);                                  // Display tenth of Temperature
        displayChars(N[Temp % 10], mirror, 1);                                  // Display unit of Temperature
        displayChars(N[10], mirror, 2);                                         // Display symbol of Degrees
        if (tCF == 0) {
          displayChars(N[11], mirror, 3);                                       // Display "C (symbol of Celsius Degrees)
        }
        else {
          displayChars(N[12], mirror, 3);                                       // Display "F" (symbol of Fahrenheit Degrees)
        }
        displayChars(0, 1, 3);                                                  // Clear Digit 3 (last digit)
      }

      if (mirror >= 3) {                                                        // Up Side Down Mirror (3) mode
        displayChars(N[Temp / 10], mirror, 3);                                  // Display tenth of Temperature
        displayChars(N[Temp % 10], mirror, 2);                                  // Display unit of Temperature
        displayChars(N[10], mirror, 1);                                         // Display symbol of Degrees
        if (tCF == 0) {
          displayChars(N[11], mirror, 0);                                       // Display "C (symbol of Celsius Degrees)
        }
        else {
          displayChars(N[12], mirror, 0);                                       // Display "F" (symbol of Fahrenheit Degrees)
        }
        displayChars(0, 1, 0);                                                  // Clear Digit 0 (last digit)
      }

    }

  }

}


void displayChars(byte num, byte statusM, byte disp) {                            // Chars Display Routine

  byte k, charsM = 0;

  if (statusM == 1) {                                                             // No Mirror
    charsM = num;
  }

  if (statusM == 2) {                                                             // Front Mirror
    for (k = 0; k <= 7; k++) {
      charsM = bitWrite(charsM, 7 - k, bitRead(num, k));
    }
    charsM = (charsM << 4 | (charsM << 2) >> 4 & 12 ) | ((charsM & 64) >> 5);
  }

  if (statusM == 3) {                                                             // Upside Down Mirror
    for (k = 0; k <= 7; k++) {
      charsM = bitWrite(charsM, 7 - k, bitRead(num, k));
    }
    charsM = (charsM << 7 | (charsM << 1) & 124 ) | ((charsM & 64) >> 5);
  }

  if (statusM == 4) {                                                             // Front Upside Down
    charsM = ((num >> 2) << 5) | ((num >> 5 ) << 2) | (num & 2);
  }

  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLK_PIN, LSBFIRST, ~charsM);                                 // Display number
  shiftOut(DATA_PIN, CLK_PIN, LSBFIRST, 128 >> disp);                             // Set Digit (0-1-2-3)
  digitalWrite(LATCH_PIN, HIGH);

}


void kbdRead() {        // Push Buttons Reading

  ajustaHora = digitalRead(BTN_1_PIN);
  ajustaMinuto = digitalRead(BTN_2_PIN);
  mostraTemperatura = digitalRead(BTN_3_PIN);

  if (!ajustaHora && tempStatus == 0) {                                           // Set Hour
    adjustTime(3600);
  }

  if (!ajustaMinuto && tempStatus == 0) {                                         // Set Minute
    adjustTime(60);
  }

  if (!mostraTemperatura) {                                                       // Move to Temperature/Time Mode
    tempStatus = (tempStatus + 1) % 2;
  }

  if (!ajustaHora && tempStatus == 1) {                                           // Set to C or F
    tCF = (tCF + 1) % 2;
  }

}

Comments

Similar projects you might like

Digital Clock with Mirrored Display Driven by Accelerometers

Project showcase by LAGSILVA

  • 14,365 views
  • 1 comment
  • 38 respects

Digital & Binary Clock In 8 Digits x 7 Segments LED Display

Project showcase by LAGSILVA

  • 1,827 views
  • 2 comments
  • 9 respects

Analog Clock with LED Matrix and Arduino

Project tutorial by LAGSILVA

  • 12,237 views
  • 8 comments
  • 39 respects

4-Stroke Digital Clock With Arduino

Project showcase by LAGSILVA

  • 11,103 views
  • 9 comments
  • 39 respects

Digital Clock with Arduino, RTC and Shift Register 74HC595

Project tutorial by LAGSILVA

  • 20,728 views
  • 16 comments
  • 46 respects

Digital And Binary Clock With Two LED Matrix And RTC

Project tutorial by LAGSILVA

  • 6,116 views
  • 10 comments
  • 27 respects
Add projectSign up / Login