Часы - бегущая строка на MAX7219

Часы

В предверии Нового года решил сделать что-нибудь «электронно-микроконтроллерное» под елку. Порылся в своих закромах… На глаза попался матричный светодиодный модуль на MAX7219 и модуль часов реального времени на микросхеме DS3231. Так родилась идея сделать простенькие часы с бегущей строкой, которые бы отсчитывали оставшиеся деньки до «боя курантов»:)

часы бегущая строка

В итоге получился такой скетч:

#include <DS3232RTC.h>      
#include <EEPROM.h>

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

//============== глобальные переменные ===========================================================
String LastD;
String StrHour;
String StrMinute;
String StrTime;

int LastDays=0;
int LastDHB=0;

int pinCS = 9;
int numberOfHorizontalDisplays = 4; // теперь у нас по-горизонтали 4 матрицы
int numberOfVerticalDisplays = 1;   // а по-вертикали, по-прежнему, одна
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);
int wait = 45;                      // время между крайними перемещениями букв
int spacer = 1;                     // расстояние между буквами
int width = 5 + spacer;             // размер шрифта

void setup()
{
  //============ инициализация модуля часов реального времени ====================================
    Serial.begin(9600);             //настраиваем COM-порт для отладки
    setSyncProvider(RTC.get);       //устанавливаем режим считывания текущего времени с модуля RTC
    if(timeStatus() != timeSet)     //проверяем статус работы модуля RTC
        Serial.println("Unable to sync with the RTC");
    else
        Serial.println("RTC has set the system time");
   //============ окончание инициализация модуля часов реального времени =========================
   //============ инициализация MAX7219 ==========================================================
    matrix.setIntensity(3);         //яркость
    matrix.setRotation( 0, 1 );     //в моём случае потребовалось "развернуть" каждую матрицу
    matrix.setRotation( 1, 1 );
    matrix.setRotation( 2, 1 );
    matrix.setRotation( 3, 1 );
    //=========== окончание инициализация MAX7219  ===============================================
}

void loop()
{
    
    LastDaysNY();           //формирование строки с остатком дней до Нового года
    TickerLEDs (LastD);     //отображение бегущей строки с остатком дней до Нового года
    printsClockOnLED();     //формирование строки текущего времени
    StringLEDs (StrTime);   //отображение статичной строки текущего времени на LED матрице
    delay (1200);           //задержка для отображения времени
}

//============== ФУНКЦИИ =========================================================================

//функция вывода текущего времени и даты в COM-порт
void digitalClockDisplay()
{
    Serial.print(hour());
    printDigits(minute());
    printDigits(second());
    Serial.print(' ');
    Serial.print(day());
    Serial.print(' ');
    Serial.print(month());
    Serial.print(' ');
    Serial.print(year());
    Serial.println();  
    Serial.println(StrTime);
}

//функция добавления "0" перед однозначными числами
void printDigits(int digits)
{
    Serial.print(':');
    if(digits < 10)
        Serial.print('0');
    Serial.print(digits);
}

//функция отображения бегущей строки на LED матрице
void TickerLEDs (String tape) {
    for ( int i = 0 ; i < width * tape.length() + matrix.width() - 1 - spacer; i++ ) {
        matrix.fillScreen(LOW);

        int letter = i / width;
        int x = (matrix.width() - 1) - i % width;
        int y = (matrix.height() - 8) / 2; // center the text vertically

        while ( x + width - spacer >= 0 && letter >= 0 ) {
            if ( letter < tape.length() ) {
                matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
            }
            letter--;
            x -= width;
        }

        matrix.write();
        delay(wait);
    }
}

//функция отображения статичной строки на LED матрице
void StringLEDs (String tape) {
    matrix.fillScreen(LOW);
    int letter = width;
    int x = matrix.width()+6;
    int y = (matrix.height() - 8) / 2; // center the text vertically

    while ( x + width - spacer >= 0 && letter >= 0 ) {
        if ( letter < tape.length() ) {
            matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
        }
        letter--;
        x -= width;
    }
    matrix.write();
}

//функция перевода времени в строчный формат
void printsClockOnLED() {
    if (hour()<10) {
        StrHour = String(0) + String(hour());
    } else {
        StrHour = String(hour());
    }
    if (minute()<10) {
        StrMinute = String(0) + String(minute());
    } else {
        StrMinute = String(minute());
    }
    StrTime = StrHour + String(":") + StrMinute;
}

//функция отчёта обратного отсчёта до Нового года
void LastDaysNY(){
    LastDays = 31 - day();
    LastD = String(LastDays) + String(utf8rus(" дней до Нового года!"))+(char)0x06;
}

//функция перекодирования кириллицы из UTF-8 в формат Windows-1251
String utf8rus(String source)
{
  int i,k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };

  k = source.length(); i = 0;

  while (i < k) {
    n = source[i]; i++;

    if (n >= 0xBF){
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (n == 0x91) { n = 0xB7; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
          break;
        }
      }
    }
    m[0] = n; target = target + String(m);
  }
return target;
}

Подробно расписывать работу часов не вижу смысла, ибо достаточно разжёванного материала в Интернете. К тому же, мой скетч пестрит комментариями. Данные часы прекрасно могут подойти для своего рода информатора на рабочем месте. Можно прикрутить всё тот же модуль Wi-Fi на ESP8266 и посылать на него напоминалки со смартфона😉

Хочется поздравить Всех с наступающим 2020 годом, пожелать здоровья и творческих успехов!

Архив для скачивания скетча и использованных мною библиотек: