Project tutorial

Complete Digital Clock Including Alarm and Motion Sensor © CC BY-NC-ND

Complete Digital Clock including many features: Alarm, Temperature, Humidy, Dew Point, RTC and PIR (Presence Infrared Sensor).

  • 13,694 views
  • 12 comments
  • 51 respects

Components and supplies

Apps and online services

About this project

Hello everybody,

I have done several designs of digital clocks for Arduino using LEDs and LCD displays, but this one is more special because I added other features like alarm and motion sensor (PIR).

Main features

  • PIR (Presence Infrared Sensor)
  • RTC (real-time clock)
  • Alarm
  • Temperature
  • Humidity
  • Water dew point
  • Encoder to set the time and alarm
  • Permanent memory for time and alarm data even when the power supply is off

Main functions of the PIR

  • Activates the display only when movement is detected around the clock.
  • Turns off the alarm if any movement is detected.

If you or your children have a deep sleep and it is difficult to wake up in the morning, this last function is perfect for you because the alarm remains activated with a noisy buzzing until the sensor detects the movement of your body.

You should definitely get out of bed and keep moving!

Shake your body!

Video

1) Bill of Materials

  • Arduino UNO
  • Arduino NANO (optional)
  • Display CATALEX 4 digits x 7 segments (TM1637)
  • PIR sensor module
  • RTC module (DS1307)
  • Temperature & Humidity sensor module (DHT11)
  • Rotary Encoder Decoder module (KY-040)
  • Buzzer 5V
  • Sensor Shield for Arduino UNO (optional)
  • Sensor Shield for Arduino Nano (optional)
  • Wires
  • Protoboard (optional)

2) Assembly

The assembly of these components is very easy.

Just follow the assembly diagram and pay attention to the connections between the components.

Here is the summary of the main signal pins of the sensors and modules to be connected in the Arduino:

Components X Arduino Pin

  • Display DIO X Digital Pin #2
  • Display CLK X Digital Pin #3
  • Encoder SW X Digital Pin #4
  • Encoder DT X Digital Pin #5
  • Encoder CLK X Digital Pin #6
  • PIR X Digital Pin #7
  • Buzzer X Digital Pin #8
  • DHT11 X Digital Pin #10
  • RTC SDA X Analog Pin #A4
  • RTC SCL X Analog Pin #A5

Note: In the diagram is shown the Arduino Nano for an application in a more compact size, but in the photos you can see my prototype using an Arduino Uno and a Sensor Shield to facilitate the whole assembly, but of course you can use protoboards to connect All Components.

3) Setup

  • LED Display

When the digital clock is run and detect the presence of someone close to it, all features will be displayed on the LED Display for a period of two seconds of visualization for each one and according to the following sequence:

Time >> Temperature >> Humidity >> Dew Point

Symbols of:

  • 1) Time: Hours & Minutes
  • 2) Temperature: in degrees Celsius (ºC)
  • 3) Humidity: in percentage (%)
  • 4) Dew Point: in degrees Celsius, , but seen on the display with a different symbol to avoid confusion with the temperature feature.

Important: The LED display will continue to function only when someone is moving around the clock. If no movement is detected, the display will turn off.

  • Rotary Encoder & Switch

The use of rotary encoders reduces the amount of keys to the settings and also simplifies their functionality for users.

In this project the rotary encoder is used when necessary to set the time and the alarm as follows:

  • Press the encoder key once to initialize the settings.
  • Turn the encoder to set the alarm time
  • Press the encoder key once to go to the next step
  • Turn the encoder to set the alarm minutes
  • Press the encoder key once
  • Turn the encoder to turn the alarm on or off
  • Press the encoder key once to go to the next step
  • Rotate the encoder to set the
  • Press the encoder key once
  • Rotate the encoder to set the minutes of time
  • Press the encoder key once
  • Turn the encoder to turn the time settings on or off
  • Press the key once to complete the settings.

Note: The time and alarm settings are stored in the RTC memory. Even if you turn off the Arduino's power supply, the RTC will keep all data due to its own 3V battery in the module.

  • PIR

The PIR module has two keys for adjustment:

  • Sensitivity to presence (movements) around the sensor.
  • Time to keep the sensor on.

This both settings you can do as you prefer. Personally, I set the sensitivity to almost the maximum and I set the time to show all the features on the LED display only once (approximately 8 to 10 seconds).

  • Dew Point

This is important information that gives you an idea of the level of human comfort due to the temperature and humidity of the ambient air.

Definition (from Wikipedia):

"is the temperature at which airborne water vapor will condense to form liquid dew. A higher dew point means there will be more moisture in the air"

Dew Point greater than 20 °C (68 °F) is considered uncomfortable and greater than 22 °C (72 °F) is considered to be extremely humid."

Calculation (in degrees Celsius):

In this project I applied a simplified formula but with a pretty good approximation for personal uses:

Dew Point = Temperature - (100 - Humidity) / 5

  • Temperature Scale:

The program for this project uses the Celsius scale for temperature and this is the default for the DHT11 sensor.

If you prefer to see temperatures in degrees Fahrenheit, you should convert them as follows:

Fahrenheit = Celsius * 1.8 + 32

Code

Digital_Clock_LED_with_Alarm_and_PIR_sensor_V1.inoArduino
Arduino's code for Digital Clock with PIR
/*                       Digital Clock by LAGSILVA
     Digital Clock with PIR & LED Display - TM1637 - 4 Digits x 7 Segments
               Display Time, Temperature, Humidity & Dew Point
        Special Features: PIR sensor & Alarm with data recorded at RTC
                            V1.1 - 19.Mar.2018
                             Author: LAGSILVA
*/

#include <TM1637Display.h>            // Library of Display TM1637 (I2C)
#include <Bounce2.h>                  // Library to read Encoder key
#include <TimerOne.h>                 // Library of Timer1
#include <Time.h>                     // Time Library
#include <DS1307RTC.h>                // Library of Real Time Clock (RTC)
#include <Wire.h>                     // Library of Wire to support DS1307RTC (Real-Time Clock) - Pins to Arduino UNO: A4 (SDA), A5 (SCL)
#include <DHT.h>                      // Library of Temperature and Humidity sensor

#define DHTPIN 11         //Sensor DHT11 conected to the pin 11 on Arduino

// Definition of what DHT sensor type you are using
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE); // Define the name DHT for the sensor of Temperature and Humidity

#define DS1307_I2C_ADDRESS 0x68       // This is the I2C address (RTC)

int hora, minuto, hh, mm, temp, umid, tpo, dezHora, uniHora, horaAlarme, minutoAlarme;
byte statusPIR, statusAlarme, statusTempo, statusGatilho;

#define DIO 2                         // Arduino Conection on Pin #2 = DIO of Display Module TM1637
#define CLK 3                         // Arduino Conection on Pin #3 = CLK of Display Module TM1637

//Encoder variables
byte encoderPinSW = 4;                // Encoder variable - SW
byte encoderPinB = 5;                 // Encoder variable - DT
byte encoderPinA = 6;                 // Encoder variable - CLK

int PIR = 7;                          // Pin #7 connected to PIR (Presence Infra Red sensor)
int BUZ = 8;                          // Pin #8 connected to buzzer (Alarm)

int chk;                              // Variable to read the sensor DHT11
//dht11 DHT;                            // Define the name DHT for the sensor of Temperature and Humidity
//#define DHT11_PIN 11                  // Sensor DHT11 conected to the Pin #11 on Arduino

byte encoderPos = 0;
byte encoderPinALast = LOW;
byte n = LOW;
byte linSW = 0;
Bounce SW = Bounce();                 // Definition of Bounce object for the switch (SW) of Encoder

// Begin of display
TM1637Display display(CLK, DIO);

// Segments map of display
//
//      A
//     ---
//  F |   | B
//     -G-
//  E |   | C
//     ---
//      D
//


// Definition of special characters to be used with the display

const uint8_t Grau[] = {
  SEG_A | SEG_B | SEG_F | SEG_G ,                   // 
};
const uint8_t UR[] = {
  SEG_C | SEG_D | SEG_E | SEG_G ,                   // %
};
const uint8_t Celsius[] = {
  SEG_A | SEG_D | SEG_E | SEG_F ,                   // C
};
const uint8_t Fahrenheit[] = {
  SEG_A | SEG_E | SEG_F | SEG_G ,                   // F
};
const uint8_t letraA[] = {
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,    // A
};
const uint8_t letraL[] = {
  SEG_D | SEG_E | SEG_F ,                           // L
};
const uint8_t letraT[] = {
  SEG_D | SEG_E | SEG_F | SEG_G,                    // t
};
const uint8_t letraI[] = {
  SEG_E,                                            // i
};
const uint8_t letraS[] = {
  SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,            // S
};
const uint8_t letraO[] = {
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,    // O
};
const uint8_t letraE[] = {
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,            // E
};
const uint8_t letraN[] = {
  SEG_C | SEG_E | SEG_G,                            // n
};
const uint8_t letraF[] = {
  SEG_A | SEG_E | SEG_F | SEG_G ,                   // F
};

// Definition of numbers to be shown with colon in the display
uint8_t dataWithColon[] = {
  0b10111111, // 0
  0b10000110, // 1
  0b11011011, // 2
  0b11001111, // 3
  0b11100110, // 4
  0b11101101, // 5
  0b11111101, // 6
  0b10000111, // 7
  0b11111111, // 8
  0b11101111, // 9
  0b00000000, // 10
};


void setup() {

  dht.begin();

  setSyncProvider(RTC.get);                                 // Update the time with data of RTC (Real Time Clock)
  setSyncInterval(300);                                     // Set the number of seconds between re-sync

  display.setBrightness (0x0a);                             //(0x0f) is the max brightness

  pinMode(PIR, INPUT);                                      // Define pin of PIR as input
  pinMode(BUZ, OUTPUT);                                     // Define pin of Buzzer as output

  pinMode (encoderPinA, INPUT);
  pinMode (encoderPinB, INPUT);
  pinMode (encoderPinSW, INPUT_PULLUP);

  // After setting up the button, setup the Bounce instance :
  SW.attach(encoderPinSW);
  SW.interval(100);

  //TimerOne initialization
  Timer1.initialize(1000);                                  // Set Timer1 for 1000 microseconds
  Timer1.attachInterrupt(lerEncoder);                       // Timer1 reads the Encoder

  //setTime(16, 20, 00, 26, 03, 2016);                      // Set the time and calendar manually
  //RTC.set(now());                                         // Update the RTC with current time


  // Read data of Alarm recorded in RTC
  Wire.beginTransmission(DS1307_I2C_ADDRESS);               // Open I2C line in write mode
  Wire.write((byte)0x08);                                   // Set the register pointer to (0x08)
  Wire.endTransmission();                                   // End Write Transmission
  Wire.requestFrom(DS1307_I2C_ADDRESS, 3);                  // In this case read only 3 bytes
  horaAlarme = Wire.read();                                 // Read the hour of Alarm stored at RTC
  minutoAlarme = Wire.read();                               // Read the minute of Alarm stored at RTC
  statusAlarme = Wire.read();                               // Read the status of Alarm stored at RTC

  // Initial values of variables
  hh = 23;
  mm = 59;
  statusGatilho = LOW;
  statusTempo = LOW;

}


void buzzer() {                                             // Routine for Alarm/Buzzer

  display.showNumberDec(dezHora, true, 1, 0);
  display.setSegments(dataWithColon + uniHora, 1, 1);
  display.showNumberDec(minuto, true, 2, 2);

  tone(BUZ, 880, 300);
  delay(300);
  tone(BUZ, 523, 200);
  delay(200);

  display.setSegments(dataWithColon + 10, 1, 0);            // Clear digit #1
  display.setSegments(dataWithColon + 10, 1, 1);            // Clear digit #2
  display.setSegments(dataWithColon + 10, 1, 2);            // Clear digit #3
  display.setSegments(dataWithColon + 10, 1, 3);            // Clear digit #4
  delay(100);

}


void lerEncoder() {  //Encoder reading

  // Update the Bounce instance :
  SW.update();
  //Check the Encoder key status
  if (SW.fell()) {
    linSW++;
    if (linSW <= 6) {
      statusPIR = LOW;
      display.setSegments(letraS, 1, 0);                    // Show the symbol of word S
      display.setSegments(letraE, 1, 1);                    // Show the symbol of word E
      display.setSegments(letraT, 1, 2);                    // Show the symbol of word T
      display.setSegments(dataWithColon + 10, 1, 3);        // Clear digit #4
      delay(500);
    }
    else {
      linSW = 0;
      statusPIR = HIGH;
    }
  }

  switch (linSW) {


    case 1: //Set the Hours of Alarm

      n = digitalRead(encoderPinA);

      if ((encoderPinALast == LOW) && (n == HIGH)) {
        if (digitalRead(encoderPinB) == LOW) {
          encoderPos++;
          horaAlarme++;
        } else {
          encoderPos--;
          horaAlarme--;
        }
        encoderPinALast = n;
        horaAlarme = constrain(horaAlarme, 0, 23);
        display.showNumberDec(horaAlarme, true, 2, 0);
        display.setSegments(letraA, 1, 2);                    // Show the symbol of word A
        display.setSegments(letraL, 1, 3);                    // Show the symbol of word L
      }


    case 2: //Set the Minutes of Alarm

      n = digitalRead(encoderPinA);

      if ((encoderPinALast == LOW) && (n == HIGH)) {
        if (digitalRead(encoderPinB) == LOW) {
          encoderPos++;
          minutoAlarme++;
        } else {
          encoderPos--;
          minutoAlarme--;
        }
        encoderPinALast = n;
        minutoAlarme = constrain(minutoAlarme, 0, 59);
        display.setSegments(letraA, 1, 0);                    // Show the symbol of word A
        display.setSegments(letraL, 1, 1);                    // Show the symbol of word L
        display.showNumberDec(minutoAlarme, true, 2, 2);
      }


    case 3: //Set status of Alarm (On-Off)

      n = digitalRead(encoderPinA);

      if ((encoderPinALast == LOW) && (n == HIGH)) {
        if (digitalRead(encoderPinB) == LOW) {
          encoderPos++;
          statusAlarme = HIGH;
        } else {
          encoderPos--;
          statusAlarme = LOW;
        }
        encoderPinALast = n;
        if (statusAlarme == LOW) {
          display.setSegments(letraO, 1, 0);                // Show the symbol of word O
          display.setSegments(letraF, 1, 1);                // Show the symbol of word F
          display.setSegments(letraF, 1, 2);                // Show the symbol of word F
          display.setSegments(dataWithColon + 10, 1, 3);    // Clear digit #4
        }
        if (statusAlarme == HIGH) {
          //display.showNumberDec(1111, true, 4, 0);
          display.setSegments(letraO, 1, 0);                // Show the symbol of word O
          display.setSegments(letraN, 1, 1);                // Show the symbol of word N
          display.setSegments(dataWithColon + 10, 1, 2);    // Clear digit #3
          display.setSegments(dataWithColon + 10, 1, 3);    // Clear digit #4
        }
        statusGatilho = HIGH;
      }


    case 4: //Set the Hour of Time

      n = digitalRead(encoderPinA);

      if ((encoderPinALast == LOW) && (n == HIGH)) {
        if (digitalRead(encoderPinB) == LOW) {
          encoderPos++;
          hh++;
        } else {
          encoderPos--;
          hh--;
        }
        encoderPinALast = n;
        hh = constrain(hh, 0, 23);
        display.showNumberDec(hh, true, 2, 0);
        display.setSegments(letraT, 1, 2);                    // Show the symbol of word T
        display.setSegments(letraI, 1, 3);                    // Show the symbol of word I
      }


    case 5: //Set the Minutes of Time

      n = digitalRead(encoderPinA);

      if ((encoderPinALast == LOW) && (n == HIGH)) {
        if (digitalRead(encoderPinB) == LOW) {
          encoderPos++;
          mm++;
        } else {
          encoderPos--;
          mm--;
        }
        encoderPinALast = n;
        mm = constrain(mm, 0, 59);
        display.setSegments(letraT, 1, 0);
        display.setSegments(letraI, 1, 1);                    // Show the symbol of word T
        display.showNumberDec(mm, true, 2, 2);                // Show the symbol of word I
      }


    case 6: //Set Time Adjustment

      n = digitalRead(encoderPinA);

      if ((encoderPinALast == LOW) && (n == HIGH)) {
        if (digitalRead(encoderPinB) == LOW) {
          encoderPos++;
          statusTempo = HIGH;
        } else {
          encoderPos--;
          statusTempo = LOW;
        }
        encoderPinALast = n;
        if (statusTempo == LOW) {
          display.setSegments(letraO, 1, 0);                // Show the symbol of word O
          display.setSegments(letraF, 1, 1);                // Show the symbol of word F
          display.setSegments(letraF, 1, 2);                // Show the symbol of word F
          display.setSegments(dataWithColon + 10, 1, 3);    // Clear digit #4
        }
        if (statusTempo == HIGH) {
          //display.showNumberDec(1111, true, 4, 0);
          display.setSegments(letraO, 1, 0);                // Show the symbol of word O
          display.setSegments(letraN, 1, 1);                // Show the symbol of word N
          display.setSegments(dataWithColon + 10, 1, 2);    // Clear digit #3
          display.setSegments(dataWithColon + 10, 1, 3);    // Clear digit #4
        }
      }

      encoderPinALast = n;

  }
}


void loop() {

  //Clear all digits of display
  display.setSegments(dataWithColon + 10, 1, 0);            // Clear digit #1
  display.setSegments(dataWithColon + 10, 1, 1);            // Clear digit #2
  display.setSegments(dataWithColon + 10, 1, 2);            // Clear digit #3
  display.setSegments(dataWithColon + 10, 1, 3);            // Clear digit #4

  do {                                                      // Keep the display off and check the sensor PIR and the time of Alarm
    if (linSW == 0) {
      statusPIR = digitalRead(PIR);
    }
    hora = hour();
    minuto = minute();
    if (hora == horaAlarme && minuto == minutoAlarme && statusAlarme == HIGH) {
      buzzer();
    }
  } while (statusPIR == LOW);

  hora = hour();
  minuto = minute();
  if (hora == horaAlarme && minuto == minutoAlarme && statusAlarme == HIGH) {
    buzzer();
  }

  //Set Time (adjustment of Hours and Minutes)
  if (linSW == 0 && statusTempo == HIGH) {
    setTime(hh, mm, 00, day(), month(), year());
    RTC.set(now());
    setSyncProvider(RTC.get);
    statusTempo = LOW;
  }

  // Write data of Alarm into RTC
  if (linSW == 0 && statusGatilho == HIGH) {
    Wire.beginTransmission(DS1307_I2C_ADDRESS);               // Open I2C line in write mode
    Wire.write((byte)0x08);                                   // Set the register pointer to (0x08)
    Wire.write(horaAlarme);                                   // Record at RTC memory the Hour of Alarm
    Wire.write(minutoAlarme);                                 // Record at RTC memory the Minute of Alarm
    Wire.write(statusAlarme);                                 // Record at RTC memory the Status of Alarm
    Wire.endTransmission();                                   // End Write Transmission
    statusGatilho == LOW;
  }

  if (linSW == 0) {
    //Display Hour and Minutes
    dezHora = hora / 10;
    uniHora = hora % 10;
    display.showNumberDec(dezHora, true, 1, 0);
    display.setSegments(dataWithColon + uniHora, 1, 1);
    display.showNumberDec(minuto, true, 2, 2);
    delay(2000);
  }

  if (linSW == 0) {

    temp = dht.readTemperature(false);          // Read temperature in Celsius degrees (C)

    //Optional Temperature in Fahrenheit (F). Remove the comments ("//") of following statement to use it.
    //temp = dht.readTemperature(true); //Reading of Temperature in Fahrenheit degree (F)

    //Display Temperature (C or F)
    display.showNumberDec(temp, true, 2, 0);    // Show Temperature in 2 digits begenning at Display #0 (first from left to right)
    display.setSegments(Grau, 1, 2);            // Show the symbol of degree ()
    display.setSegments(Celsius, 1, 3);         // Celsius symbol
    //display.setSegments(Fahrenheit, 1, 3);    // Optional Fahrenheit symbol. Remove the comments ("//") of following statement to use it.
    delay(2000);
  }

  if (linSW == 0) {

    umid = dht.readHumidity();                   // Read Humidity (%)

    //Display Relative Humidity (%)
    display.showNumberDec(umid, true, 2, 0);
    display.setSegments(Grau, 1, 2);
    display.setSegments(UR, 1, 3);
    delay(2000);
  }

  if (linSW == 0) {

    tpo = temp - (100 - umid) / 5;                // Dew Point calculation (aproximated)

    //Optional calculation of Temperature in Fahrenheit degrees (F). Remove the comments ("//") of following statement before use it.
    //tpo = (tpo * 18) / 10 + 32;

    //Display Dew Point (C or F)
    display.showNumberDec(tpo, true, 2, 0);
    display.setSegments(UR, 1, 2);
    display.setSegments(UR, 1, 3);
    delay(2000);
  }

}

Custom parts and enclosures

User Guide for Display TM1637
User guide for display TM1637 (4 Digits X 7 Segments)

Schematics

Schematic in PDF

Comments

Similar projects you might like

Digital Clock with Arduino, RTC and Shift Register 74HC595

Project tutorial by LAGSILVA

  • 20,727 views
  • 16 comments
  • 46 respects

Amazing Binary Clock using LED Matrix Module

Project tutorial by LAGSILVA

  • 9,742 views
  • 12 comments
  • 55 respects

Tiny Calendar and Clock Featuring Moon Phase in a LED Matrix

Project showcase by LAGSILVA

  • 6,075 views
  • 6 comments
  • 33 respects

4-Stroke Digital Clock With Arduino

Project showcase by LAGSILVA

  • 11,722 views
  • 14 comments
  • 40 respects

Tri-Mode Digital Clock With ATtiny85 And RTC

Project showcase by LAGSILVA

  • 5,440 views
  • 0 comments
  • 19 respects

Digital And Binary Clock With Two LED Matrix And RTC

Project tutorial by LAGSILVA

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