Created
February 28, 2025 09:35
-
-
Save aambrozkiewicz/06b0a0d89d7f0036ccc35870daf42600 to your computer and use it in GitHub Desktop.
Arduino MAX7219 display matrix with RTC showing current time/date and temperature using DS3231
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <MD_MAX72xx.h> | |
#include <RTClib.h> | |
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW // Specify your hardware type | |
#define MAX_DEVICES 4 // Number of MAX7219 modules | |
#define CLK_PIN 13 // Clock pin | |
#define DATA_PIN 11 // Data pin | |
#define CS_PIN 10 // Chip select pin | |
RTC_DS3231 rtc; | |
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); | |
const int ldrPin = A3; | |
unsigned long lastMillis; | |
unsigned int lastIntensity = 0; | |
unsigned int intensity = 0; | |
DateTime now; | |
char time[6], lastTime[6], date[7]; | |
enum state_t { | |
INIT, | |
DISPLAY_TIME, | |
ANIMATE, | |
DISPLAY_TEMP, | |
DISPLAY_DATE, | |
NOOP, | |
}; | |
state_t state = NOOP; | |
state_t animationNextStep = NOOP; | |
unsigned long timeMillis, tempMillis, dateMillis; | |
const char *daysOfTheWeek[] = { "nd", "pn", "wt", "sr", "cz", "pt", "so" }; | |
const uint8_t symbol[2] = { | |
0b01101100, | |
0b01101100, | |
}; | |
const uint8_t degreeSymbol[5] = { | |
0b00000110, // ** (flipped) | |
0b00001001, // * * (flipped) | |
0b00001001, // * * (flipped) | |
0b00000110, // ** (flipped) | |
0b00000000 // (empty row for spacing) | |
}; | |
void setup() { | |
Serial.begin(9600); | |
if (!rtc.begin()) { | |
Serial.println("Couldn't find RTC!"); | |
while (1) | |
; | |
} | |
if (rtc.lostPower()) { | |
Serial.println("RTC lost power, setting time..."); | |
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Set to compile time | |
} | |
mx.begin(); | |
mx.control(MD_MAX72XX::INTENSITY, 0); | |
setState(INIT); | |
} | |
void loop() { | |
if (!lastMillis || millis() - lastMillis >= 1000) { | |
int ldrValue = analogRead(ldrPin); | |
for (intensity = 0; intensity <= 5; intensity++) { | |
if (ldrValue > 550 - (intensity * 110)) { | |
break; | |
} | |
} | |
if (lastIntensity != intensity) { | |
mx.control(MD_MAX72XX::INTENSITY, intensity); | |
lastIntensity = intensity; | |
} | |
now = rtc.now(); | |
sprintf(time, "%02d:%02d", now.hour(), now.minute()); | |
sprintf(date, "%s. %d", daysOfTheWeek[now.dayOfTheWeek()], now.day()); | |
lastMillis = millis(); | |
} | |
switch (state) { | |
case INIT: | |
setState(DISPLAY_TEMP); | |
break; | |
case DISPLAY_TIME: | |
if (strcmp(lastTime, time)) { | |
mx.clear(); | |
displayText(time); | |
strcpy(lastTime, time); | |
} | |
if (millis() - timeMillis >= 6000) { | |
animationNextStep = DISPLAY_TEMP; | |
setState(ANIMATE); | |
} | |
break; | |
case ANIMATE: | |
if (terminalLine()) { | |
setState(animationNextStep); | |
} | |
break; | |
case DISPLAY_TEMP: | |
if (millis() - tempMillis >= 6000) { | |
animationNextStep = DISPLAY_DATE; | |
setState(ANIMATE); | |
} | |
break; | |
case DISPLAY_DATE: | |
if (millis() - dateMillis >= 6000) { | |
animationNextStep = DISPLAY_TIME; | |
setState(ANIMATE); | |
} | |
} | |
// for (int row = 0; row < 8; row++) { | |
// for (int col = 0; col < 2; col++) { | |
// mx.setColumn(col, symbol[col] >> row | symbol[col] << (8 - row)); | |
// } | |
// delay(500); | |
// } | |
} | |
void setState(state_t nextState) { | |
state = nextState; | |
switch (state) { | |
case DISPLAY_TIME: | |
mx.clear(); | |
displayText(time); | |
timeMillis = millis(); | |
break; | |
case DISPLAY_TEMP: | |
mx.clear(); | |
displayTemp(rtc.getTemperature()); | |
tempMillis = millis(); | |
break; | |
case DISPLAY_DATE: | |
mx.clear(); | |
displayText(date); | |
dateMillis = millis(); | |
break; | |
} | |
} | |
bool terminalLine() { | |
static int8_t lastCol = 31; | |
static unsigned long lastMillis; | |
if (millis() - lastMillis < 100) { | |
return false; | |
} | |
for (uint8_t row = 0; row <= 7; row++) { | |
mx.setPoint(row, lastCol + 1, false); | |
mx.setPoint(row, lastCol, true); | |
} | |
lastMillis = millis(); | |
lastCol--; | |
if (lastCol <= -2) { | |
lastCol = 31; | |
return true; | |
} | |
return false; | |
} | |
void displayTemp(float temp) { | |
String str_temp = String(temp, 1); | |
displayText(str_temp.c_str()); | |
for (uint8_t col = 0; col <= 4; col++) { | |
mx.setColumn(col, degreeSymbol[col]); | |
} | |
} | |
uint8_t getCharWidth(char c) { | |
char buf[8]; | |
return mx.getChar(c, sizeof(buf) / sizeof(buf[0]), buf); | |
} | |
// Returns number of column at which it left off | |
uint8_t displayText(const char *s) { | |
const char *pp = s; | |
uint8_t totalWidth = 0; | |
uint8_t len = 0; | |
while (*pp != '\0') { | |
totalWidth += getCharWidth(*pp); | |
pp++; | |
len++; | |
} | |
totalWidth += len - 2; // spacing? | |
int startingCol = (31 - totalWidth) / 2; | |
uint8_t nextCol = startingCol; | |
for (uint8_t i = 0; i < len; i++) { | |
nextCol += mx.setChar(31 - nextCol - i, *(s + i)); | |
} | |
return nextCol; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment