Загрузка данных
#include <LedControl.h> // Библиотека для матрицы MAX7219
// Настройки пинов для матрицы MAX7219
const uint8_t MATRIX_DIN = 11;
const uint8_t MATRIX_CLK = 13;
const uint8_t MATRIX_CS = 10;
LedControl matrix(MATRIX_DIN, MATRIX_CLK, MATRIX_CS, 1);
// Порядок пинов из вашего файла cirkitFile.json (D2=A, D3=B, D4=C...)
const uint8_t segmentPins[8] = {2, 3, 4, 5, 6, 7, 8, 9};
// Пины выбора разрядов (DIG1, DIG2, DIG3, DIG4)
const uint8_t digitPins[4] = {A0, A1, A2, A3};
// Маски сегментов для отображения цифр 0-9
const uint8_t digitMasks[10] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F
};
uint32_t startedAtMs = 0;
uint32_t lastMatrixMs = 0;
uint32_t lastScanUs = 0;
uint8_t scanDigit = 0;
uint8_t runnerFrame = 0;
// Функция гашения всех разрядов (ДЛЯ ОБЩЕГО АНОДА подаем LOW)
void blankDisplay() {
for (uint8_t i = 0; i < 4; ++i) {
digitalWrite(digitPins[i], LOW);
}
}
// Функция обновления 7-сегментного дисплея
void refreshTimer(uint32_t nowUs, uint32_t elapsedSeconds) {
// Переключаем разряд строго раз в 2.5 миллисекунды
if ((uint32_t)(nowUs - lastScanUs) < 2500U) return;
lastScanUs = nowUs;
// 1. Гасим предыдущий разряд перед сменой данных
blankDisplay();
// Вычисление минут и секунд (формат MM:SS)
const uint16_t secondsInCycle = 100U * 60U;
const uint16_t timeInCycle = elapsedSeconds % secondsInCycle;
const uint8_t digits[4] = {
(uint8_t)((timeInCycle / 60U) / 10U), // Десятки минут
(uint8_t)((timeInCycle / 60U) % 10U), // Единицы минут
(uint8_t)((timeInCycle % 60U) / 10U), // Десятки секунд
(uint8_t)(timeInCycle % 10U) // Единицы секунд
};
// 2. Переходим к следующему разряду индикатора
scanDigit = (scanDigit + 1U) & 0x03U;
// 3. Получаем маску для текущей цифры
uint8_t mask = digitMasks[digits[scanDigit]];
// Добавляем разделительную точку на второй разряд
if (scanDigit == 1) mask |= 0x80;
// 4. Зажигаем нужные сегменты (ДЛЯ ОБЩЕГО АНОДА инвертируем: LOW — горит, HIGH — не горит)
for (uint8_t segment = 0; segment < 8; ++segment) {
digitalWrite(segmentPins[segment], (mask & (1U << segment)) ? LOW : HIGH);
}
// 5. Включаем текущий разряд (ДЛЯ ОБЩЕГО АНОДА подаем HIGH)
digitalWrite(digitPins[scanDigit], HIGH);
}
// Функция отрисовки человечка на матрице 8х8
void drawRunner(uint8_t frame) {
matrix.clearDisplay(0);
// Бегущая дорожка снизу
for (uint8_t col = 0; col < 8; ++col) {
if (((col + frame) % 3U) == 0U) matrix.setLed(0, 7, col, true);
}
// Рисуем тело бегуна
matrix.setLed(0, 2, 3, true); // Голова
matrix.setLed(0, 3, 3, true); // Торс
matrix.setLed(0, 4, 3, true); // Бедра
// Анимация рук и ног
if (frame & 1U) {
matrix.setLed(0, 3, 2, true);
matrix.setLed(0, 4, 4, true);
matrix.setLed(0, 5, 4, true);
matrix.setLed(0, 6, 5, true);
matrix.setLed(0, 5, 2, true);
} else {
matrix.setLed(0, 3, 4, true);
matrix.setLed(0, 4, 2, true);
matrix.setLed(0, 5, 2, true);
matrix.setLed(0, 6, 1, true);
matrix.setLed(0, 5, 4, true);
}
}
void setup() {
// Настраиваем пины разрядов на выход
for (uint8_t i = 0; i < 4; ++i) pinMode(digitPins[i], OUTPUT);
// Настраиваем пины сегментов на выход
for (uint8_t i = 0; i < 8; ++i) {
pinMode(segmentPins[i], OUTPUT);
digitalWrite(segmentPins[i], HIGH);
}
blankDisplay();
// Инициализация матрицы MAX7219
matrix.shutdown(0, false);
matrix.setIntensity(0, 4);
matrix.clearDisplay(0);
drawRunner(0);
startedAtMs = millis();
lastMatrixMs = startedAtMs;
lastScanUs = micros();
}
void loop() {
const uint32_t nowMs = millis();
const uint32_t elapsedSeconds = (nowMs - startedAtMs) / 1000UL;
// Обновляем дисплей
refreshTimer(micros(), elapsedSeconds);
// Обновляем анимацию человечка каждые 180 мс
if ((uint32_t)(nowMs - lastMatrixMs) >= 180UL) {
lastMatrixMs = nowMs;
runnerFrame = (runnerFrame + 1U) & 0x03U;
drawRunner(runnerFrame);
}
}