Часы на Arduino Nano с LED-матрицей 4×64 — новая версия
Компоненты и материалы
| Arduino Nano R3 | ×1 |
| LED-матрица 4×8×8 (модуль MAX7219, 4 в 1) | ×1 |
| Фоторезистор (LDR) | ×1 |
| Макетная плата | ×1 |
| Модуль реального времени DS3231 | ×1 |
Программное обеспечение
| Arduino IDE |
О проекте



Для чтения часов с нескольких метров в комнате нужна яркая LED-матрица.
Купив 4-сектный дисплей дешево, я искал проекты на Hackster для Arduino Nano. Если нужно одновременно видеть часы, минуты и секунды — подходят мало проектов, так как стандартные шрифты 5×7 пикселей слишком велики. Вариант с библиотекой MD_Parola слишком громоздок для простых часов. Библиотека Max72xxPanel устарела и тянет за собой зависимости. В итоге проект основан на базовой библиотеке MD_MAX72XX, входящей в состав остальных.
Важные замечания:
- Библиотека DS3231: использую эту версию (Rinky-Dink Electronics).
- LED-матрица: моделей на рынке много. После загрузки кода дисплей может показывать «кракозябры». Решение: загрузите пример
MD_MAX72xx_HW_Mapper.inoиз библиотекиMD_MAX72xx_lib.hи определите свою модель. В моём коде задано#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW, но может потребоваться другая. - Малые секунды: в версии 2 шрифты 3×5 для секунд встроены в код — менять библиотеку не нужно.
- Предупреждения компиляции: из-за обновлений Arduino. Месяцы теперь в двумерном массиве
char, а не через указатель. Остальные предупреждения изDS3231.h— игнорируйте. - Мигание двоеточия: теперь всего 2 точки! Точные секунды отображаются мелким шрифтом 3×5 после «чч:мм». Точки мигают почти два раза в секунду — индикатор жизни.
- Режим отображения: время показывается 53 секунды каждой минуты, последние 7 секунд — дата и температура.
- День недели: можно включить, раскомментировав две строки в
loop(). Тогда лучше уменьшить интервал времени с 53 до 51 секунды. - 12-часовой формат: см. один из моих старых ответов в комментариях.
- Установка времени RTC: через Serial Monitor Arduino IDE: введите
DD/MM/YYYY hh:mm:ss(пробел обязателен) и нажмите Enter. Работает при подключенном USB и открытом Serial Monitor (верный COM и бодрейт). - Новый код занимает 13558 байт (44%) прошивки и 372 байта (18%) ОЗУ — чуть компактнее.
- Дата показывается как «дд МММ», температура комнаты в °C (по встроенному термистору RTC) — на отдельной странице. Яркость регулируется фоторезистором. Код работает и без датчика света.
Спасибо за интерес, проявляемый кнопкой «Respect»!
Программный код
- Старая версия — Arduino Nano Dot Matrix Clock
- Новая версия (v2) — Arduino Nano Dot Matrix Clock
Старая версия Arduino
Код устарел из-за изменений в библиотеках. Используйте версию 2. Все подключения описаны в коде. Для мелких шрифтов нужно изменить несколько строк в MD_MAX72xx_font.cpp, как указано в комментариях.
/* WARNING: Initial code is now obsolete. Use the new one (version 2)
* Arduino Nano DS3231 clock with LED Matrix 4x(8x8) SPI
* Arduino Nano 5V logic - 32kB prog. space
* Tools: Board: Arduino Nano; Processor: ATmega328P (Old Bootloader)!!
* LED Matrix 4x(8x8) SPI with connector on the right side (last module)
* CONNECTIONS:
* LCD 4x64 -> Arduino Nano (Hardware SPI):
* 5V -> 5V, GND -> GND, CLK_PIN -> 13 (SCK), DATA_PIN -> 11 (MOSI), CS_PIN -> 10 (SS)
* DS3231 RTC -> Arduino Nano: SDA -> A4, SCL -> A5
*/
#include <SPI.h>
#include "DS3231.h"
#include "MD_MAX72xx_lib.h"
DS3231 rtc(SDA, SCL);
const byte LDR_PIN = A2;
#define MAX_DEVICES 4
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW
#define USE_NEW_FONT 1
#define BUF_SIZE 20
#define CHAR_SPACING 1
char buf[BUF_SIZE], secs[4];
uint8_t dots;
MD_MAX72XX matrix = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
const byte WAIT = 100;
const byte SPACER = 1;
byte FONT_WIDTH;
bool timeset = false;
// ... (функции adjustClock, ledintensitySelect, printText, setup, getDate, getHour, showsec, loop)
Новая версия (v2) Arduino
Обновлена в соответствии с актуальными библиотеками.
/* Arduino Nano DS3231 clock with LED Matrix 4x(8x8) SPI
* Version 2 - updated 15/05/2021
* Arduino Nano 5V logic - 32kB prog. space
* Tools: Board: Arduino Nano; Processor: ATmega328P (Old Bootloader)!!
* CONNECTIONS: same as above
*/
#include <SPI.h>
#include "DS3231.h"
#include "MD_MAX72xx_lib.h"
DS3231 rtc(SDA, SCL);
const byte LDR_PIN = A2;
#define MAX_DEVICES 4
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
// ВЫБЕРИТЕ СВОЮ МОДЕЛЬ МАТРИЦЫ:
//#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define USE_NEW_FONT 1
#define BUF_SIZE 20
#define CHAR_SPACING 1
char buf[BUF_SIZE], secs[4];
uint8_t hh, mm, ss, dots;
// Мелкий шрифт 3x5 для секунд
uint8_t Font3x5[10][3] = {
{248, 136, 248}, // 0
{144, 248, 128}, // 1
{200, 168, 184}, // 2
{136, 168, 248}, // 3
{112, 72, 224}, // 4
{184, 168, 232}, // 5
{248, 168, 232}, // 6
{8, 232, 24}, // 7
{248, 168, 248}, // 8
{184, 168, 248} // 9
};
char months[12][4] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
char* wday;
MD_MAX72XX matrix = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
const byte WAIT = 100;
const byte SPACER = 1;
byte FONT_WIDTH;
bool timeset = false;
void adjustClock(String data) {
byte _day = data.substring(0,2).toInt();
byte _month = data.substring(3,5).toInt();
int _year = data.substring(6,10).toInt();
byte _hour = data.substring(11,13).toInt();
byte _min = data.substring(14,16).toInt();
byte _sec = data.substring(17,19).toInt();
rtc.setTime(_hour, _min, _sec);
rtc.setDate(_day, _month, _year);
Serial.println(F(">> Datetime successfully set!"));
timeset = true;
}
byte ledintensitySelect(int light) {
byte _value = 0;
if (light >= 0 && light <= 127) _value = 12;
else if (light >= 128 && light <= 319) _value = 3;
else if (light >= 320 && light <= 512) _value = 0;
return _value;
}
void printText(uint8_t modStart, uint8_t modEnd, char *pMsg) {
uint8_t state = 0, curLen;
uint16_t showLen;
uint8_t cBuf[FONT_WIDTH];
int16_t col = ((modEnd + 1) * COL_SIZE) - 1;
matrix.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
do {
switch(state) {
case 0:
if (*pMsg == '\0') { showLen = col - (modEnd * COL_SIZE); state = 2; break; }
showLen = matrix.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
curLen = 0; state++;
case 1:
matrix.setColumn(col--, cBuf[curLen++]);
if (curLen == showLen) { showLen = CHAR_SPACING; state = 2; }
break;
case 2:
curLen = 0; state++;
case 3:
matrix.setColumn(col--, 0);
curLen++;
if (curLen == showLen) state = 0;
break;
default: col = -1;
}
} while (col >= (modStart * COL_SIZE));
matrix.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}
void setup() {
pinMode(LDR_PIN, INPUT_PULLUP);
Serial.begin(9600);
Serial.println(F(">> Arduino 32x8 LED Dot Matrix Clock!"));
Serial.println(F(">> Use format to set clock's date and hour!"));
rtc.begin();
matrix.begin();
matrix.clear();
FONT_WIDTH = 5 + SPACER;
matrix.control(MD_MAX72XX::INTENSITY, 2);
rtc.setDOW(); // нужно для нового RTC
}
void getDate() {
String dts = rtc.getDateStr(); // dd/mm/yyyy
String dds = dts.substring(0,2);
String mms = dts.substring(3,5);
int mm = mms.toInt();
dds.concat(" "); dds.concat(String(months[mm-1])); // "dd Mmm"
dds.toCharArray(buf, sizeof(buf));
wday = rtc.getDOWStr(2);
}
void getHour() {
String dts = rtc.getTimeStr(); // hh:mm:ss
String hhs = dts.substring(0,2);
String mms = dts.substring(3,5);
hh = hhs.toInt(); mm = mms.toInt();
ss = dts.substring(6,8).toInt();
if (hh >= 0 && hh < 10) dots = 7;
else if (hh > 9 && hh < 20) dots = 11;
else if (hh > 19 && hh < 25) dots = 13;
if (hh % 10 == 1) dots -= 2;
String outmsg = String(hh);
outmsg.concat(char(124)); // вертикальная черта вместо двоеточия на 2 колонки
outmsg.concat(dts.substring(3,5));
outmsg.toCharArray(buf, BUF_SIZE);
}
// Новая функция показа секунд встроенным мелким шрифтом
void showsec(uint8_t secs) {
uint8_t secs1 = secs % 10;
uint8_t secs2 = secs / 10;
for (uint8_t k = 0; k < 3; k++) {
matrix.setColumn(MAX_DEVICES*8 - 26 - k, Font3x5[secs2][k]);
matrix.setColumn(MAX_DEVICES*8 - 30 - k, Font3x5[secs1][k]);
}
}
void loop() {
byte ledIntensity = ledintensitySelect(analogRead(LDR_PIN));
matrix.control(MD_MAX72XX::INTENSITY, ledIntensity);
getHour();
printText(0, MAX_DEVICES-1, buf);
matrix.setColumn(MAX_DEVICES*8 - dots, 0);
unsigned long inst = millis();
while (ss < 53) { // первые 53 сек минуты — время
while (millis() - inst > 1000) {
inst = millis(); ss++;
showsec(ss);
for (uint8_t i = 0; i < 2; i++) {
matrix.setColumn(MAX_DEVICES*8 - dots, 36); // мигающие две точки
delay(240);
matrix.setColumn(MAX_DEVICES*8 - dots, 0);
delay(240);
}
}
}
// Прокрутка времени вверх
for (uint8_t i = 0; i < 8; i++) {
matrix.transform(MD_MAX72XX::TSU); delay(3*WAIT);
}
// Дата
getDate(); printText(0, MAX_DEVICES-1, buf); delay(20*WAIT);
// День недели (раскомментировать при необходимости)
// printText(0, MAX_DEVICES-1, wday); delay(20*WAIT);
// Температура
int temp = rtc.getTemp(); temp = temp - 1; // коррекция -1°C
String outmsg = String(temp); outmsg.concat(" C");
outmsg.toCharArray(buf, BUF_SIZE);
printText(0, MAX_DEVICES-1, buf); delay(20*WAIT);
// Установка времени через Serial Monitor
if (Serial.available() > 0 && timeset == false) {
adjustClock(Serial.readString());
}
}
Схемы
Схема почти стандартная для всех проектов на MAX7219. Фоторезистор — моя добавка. Как указано в коде: #define CS_PIN(Matrix) <-> 10(Nano). Оригинал вдохновлен проектом Leonardo Sposina: GitHub.
Производственный процесс
- Часы реального времени на Arduino с расчётом времени намаза
- Монитор температуры и реальные часы на Arduino Due с TFT-дисплеем 3.2"
- Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
- Интерактивный HMI-проект на Nextion с Arduino Mega и датчиками
- Интерактивный LED-дисплей в двери с PIR-датчиком — новогоднее приветствие на Arduino
- Управление двумя шаговыми двигателями через джойстик на Arduino Nano — простой урок (Visuino)
- Arduino Flip Clock на матрице 8×8 LED — DIY проект реального времени
- Мастерство 8×8 LED-матрицы с Arduino Uno: Пошаговое руководство
- Ручной дозиметр (Гейгер-счетчик) на Arduino Nano: сборка в 3D-корпусе
- Умный зарядный мультиплексор для 6 батареек на Arduino Uno с LCD и ультразвуковым управлением