Thank you, @marco_c !
I have made a clock project that uses the MD_Parola library to show time and a menu. And i made a falling blcoks game for the same 8x32 max7219 module and rotary encoder. I want to merge them to make a clock that has a built in game accesable from the menu.
Clock:
////////////////////ARDUINO UNO R4////////////////////
////////////////////LED MATRIX CLOCK////////////////////
////////////////////LIBRARIES////////////////////
#include "RTClib.h"
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <CtrlBtn.h>
#include <CtrlEnc.h>
#include <BlockNot.h>
////////////////////VARIABLES////////////////////
static char displayChar[9] = {0}; //stores the text for the display to show
char status = 'N';
// status variable — indicates the clock's current mode.
//
// Legend:
// 'N' - Normal display (time view)
// 'h' - Enter hour-edit menu
// 'm' - Enter minute-edit menu
// 'H' - Hour edit screen
// 'M' - Minute edit screen
// 's' - Set/confirm time
// 'e' - Exit menu / return to normal
byte oldMin; //holds the last minute so screen updates when minute changes
int8_t setMinuteVar = 0; //holds the value when using the encoder to change the minute
int8_t setHourVar = 0; //holds the value when using the encoder to change the Hour
////////////////////PAROLA SETUP////////////////////
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 8
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
////////////////////RTC SETUP////////////////////
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
////////////////////BLOCKNOT SETUP////////////////////
BlockNot rtcRefreshTimer(1000);//check if time has changed once a second
BlockNot menuTimer(5000);//check if time has changed once a second
////////////////////CTRL SETUP AND MENU HANDLERS////////////////////
//Switch...Case is used to handle the status of the variables
// Define an onTurnleft handler.
void onTurnLeft() {
menuTimer.start(WITH_RESET);//resets the timer that automatically exits the menu
switch (status) {
case 'm':
status = 'h';
P.displayClear();
P.print("Hours");
break;
case 'H':
setHourVar--;
if(setHourVar <= -1){setHourVar = 23;}
snprintf(displayChar, sizeof(displayChar), "%02d", setHourVar);
P.displayClear();
P.print(displayChar);
break;
case 'M':
setMinuteVar--;
if(setMinuteVar <= -1){setMinuteVar = 59;}
snprintf(displayChar, sizeof(displayChar), "%02d", setMinuteVar);
P.displayClear();
P.print(displayChar);
break;
case 's':
status = 'm';
P.displayClear();
P.print("Minutes");
break;
case 'e':
status = 's';
P.displayClear();
P.print("Set");
break;
default:
break;
}
}
// Define an onTurnRight handler.
void onTurnRight() {
menuTimer.start(WITH_RESET);
switch (status) {
case 'h':
status = 'm';
P.displayClear();
P.print("Minutes");
break;
case 'm':
status = 's';
P.displayClear();
P.print("Set");
break;
case 'H':
setHourVar++;
if(setHourVar >= 24){setHourVar = 0;}
snprintf(displayChar, sizeof(displayChar), "%02d", setHourVar);
P.displayClear();
P.print(displayChar);
break;
case 'M':
setMinuteVar++;
if(setMinuteVar >= 60){setMinuteVar = 0;}
snprintf(displayChar, sizeof(displayChar), "%02d", setMinuteVar);
P.displayClear();
P.print(displayChar);
break;
case 's':
status = 'e';
P.displayClear();
P.print("Exit");
break;
default:
break;
}
}
// Define an onPress handler.
void onPress() {
menuTimer.start(WITH_RESET);
DateTime now = rtc.now();
switch (status) {
case 'N':
setHourVar = now.hour();
setMinuteVar = now.minute();
status = 'h';
P.displayClear();
P.print("Hours");
break;
case 'h':
status = 'H';
snprintf(displayChar, sizeof(displayChar), "%02d", setHourVar);
P.displayClear();
P.print(displayChar);
break;
case 'm':
status = 'M';
snprintf(displayChar, sizeof(displayChar), "%02d", setMinuteVar);
P.displayClear();
P.print(displayChar);
break;
case 'H':
status = 'h';
P.displayClear();
P.print("Hours");
break;
case 'M':
status = 'm';
P.displayClear();
P.print("Minutes");
break;
case 's':
status = 'N';
setTime(setHourVar, setMinuteVar);
showTime();
break;
case 'e':
status = 'N';
showTime();
break;
default:
break;
}
}
CtrlBtn button(2, 50, onPress);
CtrlEnc encoder(4, 3, onTurnLeft, onTurnRight);
////////////////////TIME SETTING FUNCTIONS////////////////////
void setTime(int8_t newHour, int8_t newMinute) {//take two variables and sets the time of the rtc to them
DateTime before = rtc.now();
DateTime updated(before.year(), before.month(), before.day(), newHour, newMinute, 0);
rtc.adjust(updated);
}
void showTime() {//updates the display and shows the current time.
DateTime now = rtc.now();
oldMin = now.minute();
if( status == 'N'){
snprintf(displayChar, sizeof(displayChar), "%02d:%02d", now.hour(), now.minute());
P.displayClear();
P.print(displayChar);
}
}
////////////////////SETUP CODE////////////////////
void setup () {
P.begin();
P.setIntensity(0);
if (! rtc.begin()) {
while (1) delay(10);
}
if (! rtc.isrunning()) {
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
DateTime now = rtc.now();
oldMin = now.minute();
P.setTextAlignment(PA_CENTER);
P.print("Hello!");//Turns the screen on and says hello
delay(4000);
showTime();
menuTimer.stop();
rtcRefreshTimer.start(WITH_RESET);
}
void loop () {
if (menuTimer.triggered()) {//This exits the menu automatically
switch (status) {
case 'h':
status = 'N';
showTime();
menuTimer.stop();
break;
case 'm':
status = 'N';
showTime();
menuTimer.stop();
break;
case 'H':
status = 'h';
P.displayClear();
P.print("Hours");
break;
case 'M':
status = 'm';
P.displayClear();
P.print("Minutes");
break;
case 's':
status = 'N';
showTime();
menuTimer.stop();
break;
case 'e':
status = 'N';
showTime();
menuTimer.stop();
break;
default:
break;
}
}
if(rtcRefreshTimer.triggered()){//checks if time has changed
DateTime now = rtc.now();
if (oldMin != now.minute()) {
showTime();
}
}
encoder.process();
button.process();
}
Game:
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <CtrlEnc.h>
#include <BlockNot.h>
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 8 // Your chip select pin
MD_MAX72XX P = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
BlockNot blockTimer(200);
uint8_t blocks[32] = {255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, };
int8_t player = 0;
void onTurnRight() {
if (player - 1 != blocks[0]) {
if(((player == 0) && (blocks[0] == 7)) == 0){
player--;
if(player < 0){
player = 7;
}
}
}
updateScreen();
}
void onTurnLeft() {
if (player + 1 != blocks[0]) {
if(((player == 7) && (blocks[0] == 0)) == 0){
player++;
if(player > 7){
player = 0;
}
}
}
updateScreen();
}
CtrlEnc encoder(4, 3, onTurnLeft, onTurnRight);
void setup() {
Serial.begin(115200);
P.begin();
P.control(MD_MAX72XX::INTENSITY, 0); // Set brightness level (0–15)
blocks[31] = rand() % 8;
P.clear();
updateScreen();
}
void loop() {
encoder.process();
if(blockTimer.TRIGGERED){
moveBlocks();
}
}
void moveBlocks() {
for (uint8_t i = 1; i <= 31; i++) {
if (blocks[i] != 255) {
blocks[i - 1] = blocks[i];
}
}
blocks[31] = rand() % 8;
if (blocks[0] == player){
delay(2000);
for (uint8_t i = 0; i <= 31; i++) {
blocks[i] = 255;
}
}
updateScreen();
}
void updateScreen() {
P.clear();
P.setPoint(player, 0, true);
for(uint8_t i = 0; i <= 31; i++){
if(blocks[i] != 255){
P.setPoint(blocks[i], i, true);
}
}
}