This shows you the differences between two versions of the page.
pm:prj2023:tmiu:digitalclock [2023/05/28 03:45] sajjad.al [Software Design] |
pm:prj2023:tmiu:digitalclock [2023/05/30 16:58] (current) sajjad.al [Introduction] |
||
---|---|---|---|
Line 7: | Line 7: | ||
| | ||
- | • The goal and purpose of this project is to build and design a simple Digital Clock with Alarm and LED Matrix Display, to displays the current time on LED display and it also can be set to sound an Alarm on a specific time. The clock uses an LED matrix to display the time, and a buzzer to sound the alarm. | + | • The goal and purpose of this project is to build and design a simple Digital Clock with Alarm and LED Matrix Display, to displays the current time and date on LED display and it also can be set to sound an Alarm on a specific time. The clock uses an LED matrix to display the time, and a buzzer to sound the alarm. |
- | • The idea of this project comes from an actual Digital clock but I added the Alarm function. | ||
Line 23: | Line 23: | ||
- | {{:pm:prj2023:tmiu:pic.jpg?200|}}===== Hardware Design ===== | + | |
+ | {{:pm:prj2023:tmiu:1.jpg?200|}}===== Hardware Design ===== | ||
Line 29: | Line 30: | ||
The following components are required for this project: | The following components are required for this project: | ||
- | • RTC module with I2C interface | + | • Tiny RTC module with I2C interface |
• LED matrix (8x8 or higher) | • LED matrix (8x8 or higher) | ||
- | • Push buttons for setting the timer | + | • 3 Push buttons |
• Buzzer for alarm sound | • Buzzer for alarm sound | ||
Line 40: | Line 41: | ||
• Breadboard | • Breadboard | ||
+ | |||
+ | * 3 Resistors | ||
• Wires | • Wires | ||
Line 54: | Line 57: | ||
The following software requirements are necessary for this project: | The following software requirements are necessary for this project: | ||
- | • RTC library (e.g., DS1307) | + | • Libraries ( MD_Parola.h, RTClib.h, toneAC.h ) |
- | • GPIO library for controlling LED matrix | ||
- | • Timer function to update the time and trigger the alarm | ||
- | • Button input and buzzer output code | ||
+ | #include <MD_Parola.h> | ||
- | #include <Wire.h> | + | #include "RTClib.h" |
- | #include <RTClib.h> | + | #include <toneAC.h> |
- | #include <LedControl.h> | + | |
+ | RTC_DS1307 RTC; | ||
+ | DateTime now; | ||
+ | |||
+ | #define HARDWARE_TYPE MD_MAX72XX::FC16_HW | ||
- | const int buttonPin = 2; | + | #define MAX_DEVICES 4 |
- | const int buzzerPin = 9; | + | #define CLK_PIN 13 |
- | const int dinPin = 12; // Data input pin | + | #define DATA_PIN 11 |
- | const int clkPin = 11; | + | #define CS_PIN 10 |
+ | |||
+ | int i = 9; | ||
- | const int csPin = 10; | + | int Animation; |
- | LedControl ledMatrix = LedControl(dinPin, clkPin, csPin, 0); // Use type 0 for MAX7219 | + | String RandAn; |
+ | |||
+ | MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); | ||
- | const int rtcSdaPin = A4; // RTC SDA pin | + | // Brightness variables |
- | const int rtcSclPin = A5; // RTC SCL pin | + | int brightness = 5; // Initial brightness level |
- | RTC_DS1307 rtc; | + | const int brightnessStep = 1; // Step to increase/decrease brightness |
- | int alarmHourSet = 0; | + | const int brightnessMin = 0; // Minimum brightness level |
- | int alarmMinuteSet = 0; | + | const int brightnessMax = 15; // Maximum brightness level |
- | byte digitPatterns[10][8] = { | + | // Button pin numbers |
- | {B0111110, B1000001, B1000001, B1000001, B1000001, B1000001, B1000001, B0111110}, // Digit 0 | + | const int brightnessUpPin = 2; |
- | {B0000000, B0000001, B0000001, B0000000, B0000000, B0000000, B0000001, B0000001}, // Digit 1 | + | const int brightnessDownPin = 3; |
- | {B0111011, B1000100, B0000100, B0000100, B0000100, B0000100, B1000100, B1111111}, // Digit 2 | + | const int alarmButtonPin = 4; // Alarm button pin |
- | {B0111110, B0000001, B0000001, B0111110, B1000000, B1000000, B1000000, B0111110}, // Digit 3 | + | const int alarmBuzzerPin = 9; // Alarm buzzer pin |
- | {B1000001, B1000001, B1000001, B1111111, B0000001, B0000001, B0000001, B0000001}, // Digit 4 | + | bool isAlarmEnabled = false; |
- | {B1111111, B1000000, B1000000, B1111110, B0000001, B0000001, B1000001, B0111110}, // Digit 5 | + | bool isAlarmOn = false; |
+ | |||
+ | char daysOfTheWeek[7][12] = {"sun", "mon", "tues", "wedn", "thur", "fri", "sat"}; | ||
- | {B0011110, B0100001, B1000000, B1111110, B1000001, B1000001, B1000001, B0111110}, // Digit 6 | + | char monthOfTheYear[12][12] = {"Jan", "Feb", "Mar", "April", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}; |
- | + | ||
- | {B1111111, B0000001, B0000001, B0000001, B0000001, B0000001, B0000001, B0000001}, // Digit 7 | + | struct sCatalog |
- | + | ||
- | {B0111110, B1000001, B1000001, B0111110, B1000001, B1000001, B1000001, B0111110}, // Digit 8 | + | |
- | {B0111110, B1000001, B1000001, B1000001, B1000001, B0111110, B0000001, B0000001} // Digit 9 | + | { |
+ | textEffect_t effect; | ||
+ | | ||
+ | const char * psz; | ||
+ | | ||
+ | uint16_t speed; | ||
+ | | ||
+ | uint16_t pause; | ||
}; | }; | ||
+ | |||
+ | sCatalog catalog[] = | ||
- | void setup() { | + | { |
- | Serial.begin(9600); | + | { PA_PRINT,"",80,3000 }, |
+ | |||
+ | { PA_SCROLL_UP,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_DOWN,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_LEFT,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_RIGHT,"",80,3000 }, | ||
+ | |||
+ | { PA_SPRITE,"",80,3000 }, | ||
+ | |||
+ | { PA_SLICE,"",15,3000 }, | ||
+ | |||
+ | { PA_MESH,"",150,3000 }, | ||
+ | |||
+ | { PA_FADE,"",250,3000 }, | ||
+ | |||
+ | { PA_DISSOLVE,"",500,3000 }, | ||
+ | |||
+ | { PA_BLINDS,"",120,3000 }, | ||
+ | |||
+ | { PA_RANDOM,"",50,3000 }, | ||
+ | |||
+ | { PA_WIPE,"",80,3000 }, | ||
+ | |||
+ | { PA_WIPE_CURSOR,"",80,3000 }, | ||
+ | |||
+ | { PA_SCAN_HORIZ,"",80,3000 }, | ||
+ | |||
+ | { PA_SCAN_HORIZX,"",80,3000 }, | ||
+ | |||
+ | { PA_SCAN_VERT,"",80,3000 }, | ||
+ | |||
+ | { PA_SCAN_VERTX,"",80,3000 }, | ||
+ | |||
+ | { PA_OPENING,"",80,3000 }, | ||
+ | |||
+ | { PA_OPENING_CURSOR,"",80,3000 }, | ||
+ | |||
+ | { PA_CLOSING,"",80,3000 }, | ||
+ | |||
+ | { PA_CLOSING_CURSOR,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_UP_LEFT,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_UP_RIGHT,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_DOWN_LEFT,"",80,3000 }, | ||
+ | |||
+ | { PA_SCROLL_DOWN_RIGHT,"",80,3000 }, | ||
+ | |||
+ | { PA_GROW_UP,"",80,3000 }, | ||
+ | |||
+ | { PA_GROW_DOWN,"",80,3000 }, | ||
+ | |||
+ | }; | ||
+ | |||
+ | |||
+ | // Sprite Definitions | ||
+ | const uint8_t F_PMAN1 = 6; | ||
+ | const uint8_t W_PMAN1 = 8; | ||
+ | static const uint8_t PROGMEM pacman1[F_PMAN1 * W_PMAN1] = // gobbling pacman animation | ||
+ | { | ||
+ | 0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c, | ||
+ | 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, | ||
+ | 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, | ||
+ | 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, | ||
+ | 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, | ||
+ | 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, | ||
+ | }; | ||
+ | |||
+ | const uint8_t F_PMAN2 = 6; | ||
+ | const uint8_t W_PMAN2 = 18; | ||
+ | static const uint8_t PROGMEM pacman2[F_PMAN2 * W_PMAN2] = // ghost pursued by a pacman | ||
+ | { | ||
+ | 0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe, | ||
+ | 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe, | ||
+ | 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe, | ||
+ | 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, | ||
+ | 0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, | ||
+ | 0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, | ||
+ | }; | ||
+ | |||
+ | void setup() | ||
+ | { | ||
+ | //Serial.begin(9600); | ||
+ | P.begin(); | ||
+ | P.setInvert(false); | ||
+ | P.setIntensity(0); | ||
Wire.begin(); | Wire.begin(); | ||
+ | RTC.begin(); | ||
- | pinMode(rtcSdaPin, INPUT_PULLUP); | + | //if (! RTC.isrunning()) |
- | pinMode(rtcSclPin, INPUT_PULLUP); | + | //{ |
- | rtc.begin(); | + | //Serial.println("RTC is NOT running!"); |
+ | RTC.adjust(DateTime(2023, 5, 30, 15, 15, 0)); | ||
+ | //} | ||
+ | #if ENA_SPRITE | ||
+ | P.setSpriteData(pacman1, W_PMAN1, F_PMAN1, pacman2, W_PMAN2, F_PMAN2); | ||
+ | #endif | ||
+ | P.displayText("Digital clock ARDUINO - BY- ALNASER SAJJAD" , PA_CENTER, 50, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT); | ||
+ | while (!P.displayAnimate()); | ||
- | pinMode(buttonPin, INPUT_PULLUP); | + | pinMode(brightnessUpPin, INPUT_PULLUP); |
- | pinMode(buzzerPin, OUTPUT); | + | pinMode(brightnessDownPin, INPUT_PULLUP); |
- | + | pinMode(alarmButtonPin, INPUT_PULLUP); | |
- | ledMatrix.shutdown(0, false); // Wake up the MAX7219 module | + | pinMode(alarmBuzzerPin, OUTPUT); |
- | ledMatrix.setIntensity(0, 1); // Set the LED matrix brightness (0-15) | + | |
- | ledMatrix.clearDisplay(0); // Clear the display | + | |
- | + | ||
- | // Set the initial alarm time | + | |
- | setAlarmTime(); | + | |
} | } | ||
+ | |||
+ | const char *ZiuaCurenta = " "; | ||
+ | |||
+ | String Hour; | ||
+ | String TIMP=" "; | ||
+ | String ORA=" "; | ||
+ | String MINUT=" "; | ||
+ | String SECUNDA=" "; | ||
+ | String DATA=""; | ||
+ | |||
+ | String Day; | ||
+ | String Month; | ||
+ | String Year; | ||
+ | String HumSTR; | ||
+ | String CelSTR; | ||
+ | String FarSTR; | ||
+ | |||
+ | void loop() | ||
+ | { | ||
+ | |||
+ | String DayOfWeek = daysOfTheWeek[now.dayOfTheWeek()]; | ||
+ | String MonthOfYear = monthOfTheYear[now.month() - 1]; | ||
+ | const char *DayOfWeekC = DayOfWeek.c_str(); | ||
+ | const char *MonthOfYearC = MonthOfYear.c_str(); | ||
+ | |||
+ | ORA = (now.hour()); | ||
+ | if (ORA.length() < 2) | ||
+ | { | ||
+ | ORA = "0"+ ORA; | ||
+ | } | ||
+ | |||
+ | MINUT = (now.minute()); | ||
+ | if (MINUT.length() < 2) | ||
+ | { | ||
+ | MINUT = "0"+ MINUT; | ||
+ | } | ||
+ | |||
+ | TIMP = ORA + ":" + MINUT; | ||
+ | |||
+ | const char *Timp = TIMP.c_str(); | ||
+ | |||
+ | Day = now.day(); | ||
+ | Month = now.month(); | ||
+ | Year = now.year(); | ||
+ | |||
+ | const char *Ziua = Day.c_str(); | ||
+ | const char *Luna = Month.c_str(); | ||
+ | const char *Anul = Year.c_str(); | ||
+ | |||
+ | String Date = Day + "/" + Month + "/" + Year; | ||
+ | const char *Data = Date.c_str(); | ||
+ | |||
+ | | ||
+ | if (i == 1) | ||
+ | { | ||
+ | Animation = random(1, 29); | ||
+ | P.displayText(DayOfWeekC, PA_CENTER, catalog[Animation].speed, catalog[Animation].pause, catalog[Animation].effect, catalog[Animation].effect); | ||
+ | while (!P.displayAnimate()); | ||
+ | } | ||
+ | if (i == 2) | ||
+ | { | ||
+ | Animation = random(1, 29); | ||
+ | P.displayText(Ziua, PA_CENTER, catalog[Animation].speed, catalog[Animation].pause, catalog[Animation].effect, catalog[Animation].effect); | ||
+ | while (!P.displayAnimate()); | ||
+ | } | ||
+ | if (i == 3) | ||
+ | { | ||
+ | Animation = random(1, 29); | ||
+ | P.displayText(MonthOfYearC, PA_CENTER, catalog[Animation].speed, catalog[Animation].pause, catalog[Animation].effect, catalog[Animation].effect); | ||
+ | while (!P.displayAnimate()); | ||
+ | } | ||
+ | if (i == 4) | ||
+ | { | ||
+ | Animation = random(1, 29); | ||
+ | P.displayText(Anul, PA_CENTER, catalog[Animation].speed, catalog[Animation].pause, catalog[Animation].effect, catalog[Animation].effect); | ||
+ | while (!P.displayAnimate()); | ||
+ | } | ||
+ | |||
+ | if (i == 5) | ||
+ | { | ||
+ | Animation = random(1, 29); | ||
+ | P.displayText(Timp, PA_CENTER, catalog[Animation].speed, catalog[Animation].pause, catalog[Animation].effect, catalog[Animation].effect); | ||
+ | while (!P.displayAnimate()); | ||
+ | } | ||
+ | |||
+ | //Serial.println(Animation); | ||
+ | i= i+1; | ||
+ | if (i > 5) | ||
+ | { | ||
+ | i=1; | ||
+ | }; | ||
+ | |||
+ | // Button handling | ||
+ | if (digitalRead(brightnessUpPin) == LOW) { | ||
+ | increaseBrightness(); | ||
+ | delay(200); // Add a small delay to avoid button bouncing | ||
+ | } | ||
- | void loop() { | + | if (digitalRead(brightnessDownPin) == LOW) { |
- | checkButton(); | + | decreaseBrightness(); |
- | displayTime(); | + | delay(200); // Add a small delay to avoid button bouncing |
+ | } | ||
+ | if (digitalRead(alarmButtonPin) == LOW) { | ||
+ | delay(200); // Add a small delay to avoid button bouncing | ||
+ | } | ||
+ | // Check for alarm condition | ||
+ | if (isAlarmEnabled && isAlarmTime()) { | ||
+ | activateAlarm(); | ||
+ | } | ||
} | } | ||
- | + | void increaseBrightness() { | |
- | void setAlarmTime() { | + | brightness += brightnessStep; |
- | Serial.println("Enter alarm time (hh:mm):"); | + | if (brightness > brightnessMax) { |
- | while (!Serial.available()) { | + | brightness = brightnessMax; |
- | // Wait for input from the serial monitor | + | |
} | } | ||
- | delay(100); | + | P.setIntensity(brightness); |
+ | } | ||
- | String input = Serial.readString(); | + | void decreaseBrightness() { |
- | int separatorIndex = input.indexOf(':'); | + | brightness -= brightnessStep; |
+ | if (brightness < brightnessMin) { | ||
+ | brightness = brightnessMin; | ||
+ | } | ||
+ | P.setIntensity(brightness); | ||
+ | } | ||
- | if (separatorIndex > 0) { | + | bool isAlarmTime() { |
- | String hourString = input.substring(0, separatorIndex); | + | // Get the current time |
- | String minuteString = input.substring(separatorIndex + 1); | + | now = RTC.now(); |
- | alarmHourSet = hourString.toInt(); | + | // Define the alarm time (hours and minutes) |
- | alarmMinuteSet = minuteString.toInt(); | + | int alarmHour = 8; |
+ | int alarmMinute = 30; | ||
- | Serial.print("Alarm time set: "); | + | // Compare the current time with the alarm time |
- | Serial.println(input); | + | if (now.hour() == alarmHour && now.minute() == alarmMinute) { |
+ | return true; // It's alarm time | ||
} else { | } else { | ||
- | Serial.println("Invalid input format. Please try again."); | + | return false; // It's not alarm time |
- | setAlarmTime(); | + | |
} | } | ||
} | } | ||
- | void checkButton() { | ||
- | static bool buttonPressed = false; | ||
- | if (digitalRead(buttonPin) == LOW && !buttonPressed) { | + | void activateAlarm() { |
- | // Button is pressed for the first time, activate the buzzer | + | digitalWrite(alarmBuzzerPin, HIGH); // Turn on the buzzer |
- | toggleAlarm(); | + | delay(1000); // Adjust the delay as needed |
- | buttonPressed = true; | + | digitalWrite(alarmBuzzerPin, LOW); // Turn off the buzzer |
- | } else if (digitalRead(buttonPin) == HIGH && buttonPressed) { | + | |
- | // Button is released, reset the button pressed flag | + | |
- | buttonPressed = false; | + | |
- | } | + | |
} | } | ||
- | void toggleAlarm() { | + | // Function to deactivate the alarm |
- | static bool alarmOn = false; | + | void deactivateAlarm() { |
- | alarmOn = !alarmOn; | + | digitalWrite(alarmBuzzerPin, LOW); // Turn off the buzzer |
- | + | ||
- | if (alarmOn) { | + | |
- | digitalWrite(buzzerPin, HIGH); | + | |
- | } else { | + | |
- | digitalWrite(buzzerPin, LOW); | + | |
- | } | + | |
} | } | ||
- | void displayTime() { | ||
- | DateTime now = rtc.now(); | ||
- | int currentHour = now.hour(); | ||
- | int currentMinute = now.minute(); | ||
- | int hourTens = currentHour / 10; | + | ===== Results Obtained ===== |
- | int hourOnes = currentHour % 10; | + | |
- | int minuteTens = currentMinute / 10; | + | |
- | int minuteOnes = currentMinute % 10; | + | |
- | // Display the hour tens digit | + | After i built the Hardware components and wrote the Software (CODE): |
- | for (int i = 0; i < 8; i++) { | + | |
- | byte pattern = digitPatterns[hourTens][i]; | + | |
- | ledMatrix.setRow(0, i, pattern); | + | |
- | } | + | |
- | // Display the hour ones digit | + | * The digital clock should display the current time in hours and minutes using the LED matrix. |
- | for (int i = 0; i < 8; i++) { | + | |
- | byte pattern = digitPatterns[hourOnes][i]; | + | |
- | ledMatrix.setRow(0, i + 8, pattern); | + | |
- | } | + | |
- | // Display the minute tens digit | + | * The clock should retrieve the time from the Tiny RTC module using the I2C interface. |
- | for (int i = 0; i < 8; i++) { | + | |
- | byte pattern = digitPatterns[minuteTens][i]; | + | |
- | ledMatrix.setRow(0, i + 16, pattern); | + | |
- | } | + | |
- | // Display the minute ones digit | + | * The clock should display the current day of the week, date, month, and year on the LED matrix. |
- | for (int i = 0; i < 8; i++) { | + | |
- | byte pattern = digitPatterns[minuteOnes][i]; | + | |
- | ledMatrix.setRow(0, i + 24, pattern); | + | |
- | } | + | |
- | } | + | |
- | + | * The clock should support different text effects and animations for displaying the time and date. | |
- | ===== Results Obtained ===== | + | * The clock should have three push buttons for controlling the brightness of the LED matrix and activating/deactivating the alarm. |
- | + | * The clock should activate an alarm sound using the buzzer at a predefined alarm time (8:30 AM). | |
- | + | ||
- | What were the results obtained after the realization of your project. | + | |
Line 240: | Line 423: | ||
===== Conclusions ===== | ===== Conclusions ===== | ||
+ | |||
+ | the project demonstrates the ability to create a digital clock using an Arduino Uno, LED matrix, Tiny RTC module, push buttons, and a buzzer. The project combines both hardware and software components to deliver a functional and interactive digital clock. | ||
===== Download ===== | ===== Download ===== | ||
Line 261: | Line 446: | ||
- | + | **Software Resources** | |
- | List of documents, datasheets, Internet resources used, possibly grouped by **Software Resources** and **Hardware Resources**. | + | |
+ | https://mytectutor.com/ds1307-real-time-clock-with-arduino-including-digital-clock-using-max7219-led-matrix/ | ||
+ | |||
+ | |||
+ | https://pastebin.com/EkX8aJvc | ||
+ | |||
+ | |||
+ | https://lastminuteengineers.com/ds1307-rtc-arduino-tutorial/ | ||