Загрузка данных


#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);
  }
}