ARDUINO Помощь в реализации алгоритма светофор

Askar

✩✩✩✩✩✩✩
17 Фев 2021
20
0
Всем примет
Не так давно начал плотно изучать ардуино, сейчас переключился на адресные матрицы ws2812b 8x8. Смог разобраться и вывести работу светофора (Красный, желтый, зелёный) по времени и понял как отдельно выводить время. Но уже 2ю неделю не могу понять где ошибка и как сделать что бы на светофоре выводилось время и цвета светофора.
Все матрицы подключены последовательно, на один пин. Части кода взяты из разных проектов (Алекс Гайвер, vvip-68)

Пытаюсь реализовать следующий алгоритм:
Матрицы расположены сверху вниз
На 1й матрице горит красный
На второй идет отсчет времени красным цветом
На второй матрице отсчет доходит до 3, вторая матрица загорается желтый, отсчет на ней перестает идти, но функция считает. Когда в функции счет доходит до 0, первая и вторая матрицы гаснут, загорается 3я матрица зеленым светом и на 2й снова идет отсчет времени. Когда на 2й матрице отсчет времени доходит до 5, начинает мигать зелёный свет на третей матрице, дошел отсчет до 0 на 3 секунды загорается желтый свет, потом красный и так по кругу.
Если горит красный, то отсчет идет красным цветом, если зелёный то отсчет идет зелёным. При желтом цвете счет времени идет только в контроллере, на матрице не отображается.

В приведённом ниже коде, по отдельности работают только отсчет времени и автоматический алгоритм светофора, заливка цвета без счета.
Так же там таймер считает с 96 до 0 и свет отсчета синий, это делал на время тестов, пока пытался все объединить в одно. Ещё в результате недостатка знаний со временем алгоритм зависает и цвета переключаются с задержкой. Например желтый, включается зелёный, и спустя несколько секунд гаснет желтый.

1:
#define TIME_RED 7              // секунды работы
#define TIME_YELLOW 3
#define TIME_GREEN 15         

#define COLOR_RED CRGB::Red       // быстрые цвета
#define COLOR_YELLOW CRGB::Yellow
#define COLOR_GREEN CRGB::Green

// Переменные для таймера
int8_t newSecs = 96;
uint32_t newColor;
uint32_t timeCounter = 0;

uint32_t RED_DURATION = TIME_RED * 1000;       // перевод в секунды для millis
uint32_t YELLOW_DURATION = TIME_YELLOW * 1000;
uint32_t GREEN_DURATION = TIME_GREEN * 1000;

#define BRIGHTNESS      7       // Яркость матрицы по-умолчанию 0..255
//////////////////////////////////////////////////
#define COLOR_ORDER    GRB      // Порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB

#define WIDTH 8                // ширина одного сегмента матрицы                                   
#define HEIGHT 8               // высота одного сегмента матрицы                                     
#define MATRIX_TYPE 0           // тип соединения диодов в сегменте матрицы: 0 - зигзаг, 1 - параллельная
#define CONNECTION_ANGLE 3      // угол подключения диодов в сегменте: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
#define STRIP_DIRECTION 1       // направление ленты из угла сегмента: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз                                 
#define META_MATRIX_WIDTH 1    // количество сегментов в ширину сборной матрицы                                                                 
#define META_MATRIX_HEIGHT 3    // количество сегментов в высоту сборной матрицы                                                                 
#define META_MATRIX_TYPE 0      // тип сборной матрицы: 0 - зигзаг, 1 - параллельная                                                             
#define META_MATRIX_ANGLE 3     // угол 1-го сегмента сборной матрицы: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний

#define META_MATRIX_DIRECTION 3 // направление следующих сегментов сборной матрицы из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз         

#define LED_PIN  13              // пин ленты
// =======================================================

// ************** ИСПОЛЬЗУЕМЫЕ БИБЛИОТЕКИ ****************
#include <FastLED.h>             // Установите в менеджере библиотек стандартную библиотеку FastLED
// =======================================================

// ************************* УПРАВЛЕНИЕ МАТРИЦЕЙ *******************************
uint16_t   CURRENT_LIMIT = 500;                // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит

uint8_t    sWIDTH = WIDTH;                       // ширина одного сегмента матрицы 1..127
uint8_t    sHEIGHT = HEIGHT;                     // высота одного сегмента матрицы 1..127
uint8_t    sMATRIX_TYPE = MATRIX_TYPE;           // тип соединения диодов в сегменте матрицы: 0 - зигзаг, 1 - параллельная, 2 - карта индексов
uint8_t    sCONNECTION_ANGLE = CONNECTION_ANGLE; // угол подключения диодов в сегменте: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
uint8_t    sSTRIP_DIRECTION = STRIP_DIRECTION;   // направление ленты из угла сегмента: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз

uint8_t    mWIDTH = META_MATRIX_WIDTH;           // количество сегментов в ширину 1..9
uint8_t    mHEIGHT = META_MATRIX_HEIGHT;         // количество сегментов в высоту 1..9
uint8_t    mTYPE = META_MATRIX_TYPE;             // соединение сегментов мета-матрицы: 0 - зигзаг, 1 - параллельная
uint8_t    mANGLE = META_MATRIX_ANGLE;           // угол 1-го сегмента мета-матрицы: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
uint8_t    mDIRECTION = META_MATRIX_DIRECTION;   // направление следующих сегментов мета-матрицы из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз

uint8_t    pWIDTH = sWIDTH * mWIDTH;            // Равна ширене одного сегмента * на количество сегментов в ширину 8*1=8
uint8_t    pHEIGHT = sHEIGHT * mHEIGHT;         // Равна высоте одного сегмента * на количество сегментов в высоту 8*3=24

uint32_t   NUM_LEDS = pWIDTH * pHEIGHT;
uint8_t    maxDim   = max(pWIDTH, pHEIGHT);
uint8_t    minDim   = min(pWIDTH, pHEIGHT);

CRGB       *leds;                               // обращение к светодиодам матрицы через этот массив

// ------------------- ВРЕМЕННЫЕ ПЕРЕМЕННЫЕ ----------------------
uint8_t  globalBrightness = BRIGHTNESS;     // текущая яркость (общая)

// ---------------------------------------------------------------

void setup()
{
  Serial.begin(9600);

  pWIDTH = sWIDTH * mWIDTH;
  pHEIGHT = sHEIGHT * mHEIGHT;

  NUM_LEDS = pWIDTH * pHEIGHT;
  maxDim   = max(pWIDTH, pHEIGHT);
  minDim   = min(pWIDTH, pHEIGHT);

  // Настройки ленты
  leds =  new CRGB[NUM_LEDS];

  FastLED.addLeds<WS2812, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );

  FastLED.setBrightness(globalBrightness);
  if (CURRENT_LIMIT > 0) {
    FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT);
  }
  FastLED.clear();
  FastLED.show();
 
  newColor = CRGB::Yellow;
}

void loop()
{ 
  handleTime();
}
custom:
enum LightState {RED, YELLOW, GREEN};
LightState currentLight = RED;

uint32_t redTime = 0;
uint32_t yellowTime = 0;
uint32_t greenTime = 0;
boolean Flag = true;

void light() {
  //FastLED.clear();
  switch (currentLight)
  {
    case RED:
      if (millis() - redTime >= RED_DURATION)
      {
        currentLight = YELLOW;
        redTime = millis();

      }
      break;

    case YELLOW:
      if (millis() - redTime >= YELLOW_DURATION)
      {
        if (Flag)
        {
          currentLight = GREEN;
        }
        else
        {
          currentLight = RED;
        }
        Flag = !Flag;
        redTime = millis();
      }
      break;

    case GREEN:
      if (millis() - redTime >= GREEN_DURATION)
      {
        currentLight = YELLOW;
        redTime = millis();
      }
      break;
  }

  switch (currentLight) {

    case RED:
      newColor = COLOR_RED;
      
      fillGreenBlack();
      fillRed();
      break;

    case YELLOW:
      if (Flag) {
        fillRedBlack();
      }
      else {
        fillGreenBlack();
      }
      fillYellow();
      break;

    case GREEN:
      newColor = COLOR_GREEN;
      fillGreen();
      break;
  }
  //FastLED.clear();
}
effects:
// Отсчет времени
void handleTime()
{
  light();
  if (millis() - timeCounter >= 1000L && newSecs > 0) {
    timeCounter = millis();
    //FastLED.clear();
    --newSecs;
    if (currentLight != 1)
    {
      showClear();
      displayScore(newSecs, newColor);
    }
    Serial.println(newSecs);
    if (newSecs == 0) newSecs = 96;
  }
  FastLED.show();
}

// вывод цифр
void displayScore(byte score, CRGB color) {
  if (score > 9)
  {
    drawDigit3x5(score / 10, 1, 10, color);
    drawDigit3x5(score % 10, 5, 10, color);
  }
  else
  {
    drawDigit3x5(score % 10, 3, 10, color);
  }
  FastLED.show();
}

void showClear() {
  for (int i = 64; i < 128; i++) {
    leds[i] = CRGB::Black;
  }
  //FastLED.show();
}

void fillRed() {
  for (int i = 0; i < 64; i++) {
    leds[i] = CRGB::Red;
  }
  FastLED.show();
}

void fillRedBlack() {
  for (int i = 0; i < 64; i++) {
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}

void fillYellow() {
  for (int i = 64; i < 128; i++) {
    leds[i] = CRGB::Yellow;
  }
  FastLED.show();
}

void fillYellowBlack() {
  for (int i = 64; i < 128; i++) {
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}

void fillGreen() {
  for (int i = 128; i < 192; i++) {
    leds[i] = CRGB::Green;
  }
  FastLED.show();
}

void fillGreenBlack() {
  for (int i = 128; i < 192; i++) {
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}


boolean pulseFlag = true;
uint32_t pulseTime;

void fillYellowPulse()
{
  if (millis() - pulseTime >= 1000)
  {
    if (pulseFlag) {
      fillYellow();
    } else {
      fillYellowBlack();
    }
    pulseTime = millis();
    pulseFlag = !pulseFlag;
  }
}

void fillGreenPulse()
{
  if (millis() - pulseTime >= 1000)
  {
    if (pulseFlag) {
      fillGreen();
    }
    else {
      fillGreenBlack();
    }
    pulseTime = millis();
    pulseFlag = !pulseFlag;
  }
}
utility:
// служебные функции

// шрифт 3х5 квадратный
const uint8_t font3x5[][3] PROGMEM = {
  {0b11111, 0b10001, 0b11111},    // 0
  {0b00000, 0b11111, 0b00000},    // 1
  {0b10111, 0b10101, 0b11101},    // 2
  {0b10101, 0b10101, 0b11111},    // 3
  {0b11100, 0b00100, 0b11111},    // 4
  {0b11101, 0b10101, 0b10111},    // 5
  {0b11111, 0b10101, 0b10111},    // 6
  {0b10000, 0b10000, 0b11111},    // 7
  {0b11111, 0b10101, 0b11111},    // 8
  {0b11101, 0b10101, 0b11111},    // 9
};

// нарисовать цифру шрифт 3х5 квадратный
void drawDigit3x5(uint8_t digit, int8_t X, int8_t Y, CRGB color) {
  if (digit > 9) return;
  for (uint8_t x = 0; x < 3; x++) {
    uint8_t thisByte = pgm_read_byte(&(font3x5[digit][x]));
    for (uint8_t y = 0; y < 5; y++) {
      if (y + Y > pHEIGHT) continue;
      if (thisByte & (1 << y)) drawPixelXY(x + X, y + Y, color);
    }
  }
}

void fillAll(uint32_t color) {
  fill_solid(leds, NUM_LEDS, color);
}

// залить все
void fillAll(CRGB color) {
  fill_solid(leds, NUM_LEDS, color);
}

// функция получения цвета пикселя по его номеру
uint32_t getPixColor(int16_t thisPixel) {
  if (thisPixel < 0 || thisPixel > NUM_LEDS - 1) return 0;
  return (((uint32_t)leds[thisPixel].r << 16) | ((uint32_t)leds[thisPixel].g << 8 ) | (uint32_t)leds[thisPixel].b);
}

// функция получения цвета пикселя в матрице по его координатам
uint32_t getPixColorXY(int8_t x, int8_t y) {
  return getPixColor(getPixelNumber(x, y));
}

// функция отрисовки точки по координатам X Y
void drawPixelXY(int8_t x, int8_t y, CRGB color) {
  if (x < 0 || x > pWIDTH - 1 || y < 0 || y > pHEIGHT - 1) return;
  int16_t thisPixel = getPixelNumber(x, y);
  if (thisPixel >= 0) leds[thisPixel] = color;
}

void drawPixelXYF(float x, float y, CRGB color) {
  // extract the fractional parts and derive their inverses
  uint8_t xx = (x - (int)x) * 255, yy = (y - (int)y) * 255, ix = 255 - xx, iy = 255 - yy;

  // calculate the intensities for each affected pixel
#define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8))

  uint8_t wu[4] = {WU_WEIGHT(ix, iy), WU_WEIGHT(xx, iy),
                   WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)
                  };

  // multiply the intensities by the colour, and saturating-add them to the pixels
  for (uint8_t i = 0; i < 4; i++) {
    int16_t xn = x + (i & 1), yn = y + ((i >> 1) & 1);
    CRGB clr = getPixColorXY(xn, yn);
    clr.r = qadd8(clr.r, (color.r * wu[i]) >> 8);
    clr.g = qadd8(clr.g, (color.g * wu[i]) >> 8);
    clr.b = qadd8(clr.b, (color.b * wu[i]) >> 8);
    drawPixelXY(xn, yn, clr);
  }
}

// получить номер пикселя в ленте по координатам
int16_t getPixelNumber(int8_t x, int8_t y) {

  if (x < 0 || x >= pWIDTH || y < 0 || y >= pHEIGHT) return -1;

  uint8_t xx, yy, ww, sx, sy, mx, my, mw, snum, num;

  if (sMATRIX_TYPE == 0 || sMATRIX_TYPE == 1) {

    // --------------------------------------------------
    // Матрица состоит из одного сегмента, адресация по углу подключения, типу, направлению
    // --------------------------------------------------

    if (mWIDTH == 1 && mHEIGHT == 1) {
      xx = THIS_X(x, y);
      yy = THIS_Y(x, y);
      ww = THIS_W();

      return (yy % 2 == 0 || sMATRIX_TYPE == 1)
             ? yy * ww + xx // если чётная строка
             : yy * ww + ww - xx - 1; // если нечётная строка
    }

    // --------------------------------------------------
    // Матрица - сборная, состоит из нескольких сегментов, адресация по углу подключения, типу, направлению
    // --------------------------------------------------

    sx = x / sWIDTH;    // номер сегмента по ширине
    sy = y / sHEIGHT;   // номер сегмента по высоте
    x = x % sWIDTH;     // позиция x относительно сегмента
    y = y % sHEIGHT;    // позиция y относительно сегмента

    // Номер сегмента в последовательности сборной матрицы
    mx = THIS_SX(sx, sy);
    my = THIS_SY(sx, sy);
    mw = THIS_SW();

    snum = (my % 2 == 0 || mTYPE == 1)
           ? my * mw + mx           // если чётная строка мета-матрицы
           : my * mw + mw - mx - 1; // если нечётная строка мета-матрицы

    // Номер дода в сегменте
    xx = THIS_X(x, y);
    yy = THIS_Y(x, y);
    ww = THIS_W();

    num = (yy % 2 == 0 || sMATRIX_TYPE == 1)
          ? yy * ww + xx           // если чётная строка
          : yy * ww + ww - xx - 1; // если нечётная строка

    return snum * sWIDTH * sHEIGHT + num;
  }

  return -1;
}

uint8_t THIS_X(uint8_t x, uint8_t y) {
  /*
      CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
      STRIP_DIRECTION;  // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
  */
  if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 0) return x;
  if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 1) return y;
  if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 0) return x;
  if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 3) return sHEIGHT - y - 1;
  if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 2) return sWIDTH - x - 1;
  if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 3) return sHEIGHT - y - 1;
  if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 2) return sWIDTH - x - 1;
  if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 1) return y;
  return x;
}

uint8_t THIS_Y(uint8_t x, uint8_t y) {
  /*
      CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
      STRIP_DIRECTION;  // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
  */
  if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 0) return y;
  if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 1) return x;
  if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 0) return sHEIGHT - y - 1;
  if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 3) return x;
  if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 2) return sHEIGHT - y - 1;
  if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 3) return sWIDTH - x - 1;
  if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 2) return y;
  if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 1) return sWIDTH - x - 1;
  return y;
}

uint8_t THIS_W() {
  /*
      CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
      STRIP_DIRECTION;  // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
  */
  if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 0) return sWIDTH;
  if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 1) return sHEIGHT;
  if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 0) return sWIDTH;
  if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 3) return sHEIGHT;
  if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 2) return sWIDTH;
  if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 3) return sHEIGHT;
  if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 2) return sWIDTH;
  if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 1) return sHEIGHT;
  return sWIDTH;
}

uint8_t THIS_SX(uint8_t x, uint8_t y) {
  /*
      CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
      STRIP_DIRECTION;  // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
  */
  if (mANGLE == 0 && mDIRECTION == 0) return x;
  if (mANGLE == 0 && mDIRECTION == 1) return y;
  if (mANGLE == 1 && mDIRECTION == 0) return x;
  if (mANGLE == 1 && mDIRECTION == 3) return mHEIGHT - y - 1;
  if (mANGLE == 2 && mDIRECTION == 2) return mWIDTH - x - 1;
  if (mANGLE == 2 && mDIRECTION == 3) return mHEIGHT - y - 1;
  if (mANGLE == 3 && mDIRECTION == 2) return mWIDTH - x - 1;
  if (mANGLE == 3 && mDIRECTION == 1) return y;
  return x;
}

uint8_t THIS_SY(uint8_t x, uint8_t y) {
  /*
      CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
      STRIP_DIRECTION;  // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
  */
  if (mANGLE == 0 && mDIRECTION == 0) return y;
  if (mANGLE == 0 && mDIRECTION == 1) return x;
  if (mANGLE == 1 && mDIRECTION == 0) return mHEIGHT - y - 1;
  if (mANGLE == 1 && mDIRECTION == 3) return x;
  if (mANGLE == 2 && mDIRECTION == 2) return mHEIGHT - y - 1;
  if (mANGLE == 2 && mDIRECTION == 3) return mWIDTH - x - 1;
  if (mANGLE == 3 && mDIRECTION == 2) return y;
  if (mANGLE == 3 && mDIRECTION == 1) return mWIDTH - x - 1;
  return y;
}

uint8_t THIS_SW() {
  /*
      CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
      STRIP_DIRECTION;  // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
  */
  if (mANGLE == 0 && mDIRECTION == 0) return mWIDTH;
  if (mANGLE == 0 && mDIRECTION == 1) return mHEIGHT;
  if (mANGLE == 1 && mDIRECTION == 0) return mWIDTH;
  if (mANGLE == 1 && mDIRECTION == 3) return mHEIGHT;
  if (mANGLE == 2 && mDIRECTION == 2) return mWIDTH;
  if (mANGLE == 2 && mDIRECTION == 3) return mHEIGHT;
  if (mANGLE == 3 && mDIRECTION == 2) return mWIDTH;
  if (mANGLE == 3 && mDIRECTION == 1) return mHEIGHT;
  return mWIDTH;
}
Буду признателен за объяснения где ошибки и как их исправить
 

BOT_Zilla

✩✩✩✩✩✩✩
1 Апр 2022
13
8
Насчет алгоритма. Предлагаю состояние светофора хранить в памяти вроде как на магнитной ленте. Создать массив с данными, которые на каждом цикле работы светофора хранят состояние каждого цвета (вкл/выкл), длительность его свечения, флаги моргания и отображения таймера и т. д. Считывая данные через заданные в этом же массиве промежутки времени, можно избавиться от путаницы с millis
C++:
// Структура для хранения состояния светофора
struct TrafficLightState {
  char red;    // 'R' - красный, 'O' - выключен
  char yellow; // 'Y' - желтый, 'O' - выключен
  char green;  // 'G' - зеленый, 'O' - выключен
  int duration; // Продолжительность текущего состояния в секундах
};// типы данных можно поменять на те, как определены были выше в enum, также добавить
//еще данные (флаги, таймеры)

// Максимальная длина "ленты"
const int maxStates = 4;

// Массив для хранения состояний
TrafficLightState states[maxStates] = {
  {'R', 'O', 'O', 5},  // Красный 5 сек
  {'R', 'Y', 'O', 2},  // Красный+Желтый 2 сек
  {'O', 'O', 'G', 5},  // Зеленый 5 сек
  {'O', 'Y', 'O', 2}  // Желтый 2 сек
  // сюда пишем работу светофора на каждом шаге
};

// читаем "ленту". Для примера просто дрыгаем ногами
    digitalWrite(2, currentState.red == 'R' ? HIGH : LOW);
    digitalWrite(3, currentState.yellow == 'Y' ? HIGH : LOW);
    digitalWrite(4, currentState.green == 'G' ? HIGH : LOW);
Впоследствии логику работы светофора можно легко изменить, переписав данные в массиве и не затрагивая остальной код.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
476
137
Чтобы понять алгоритм вашей программы надо иметь большое желание. (У меня его нет).
Что мешает простому пониманию: По вызову функций не понятно, что они делают, пока не посмотришь. Впрочем и тогда не понятно, что вы хотели сделать, т.к. комментариев нет совсем.
У каждого свое видение, для меня было бы логично, что если функция начинается со слова fill.... то она только заполняет массив, а если show... то заполняет (если надо) и выводит. У вас же наоборот.
fillRed() выводит от 0 до 64; fillYellow() выводит от 64 до 128; и это надо держать в голове, и еще и думать, а вы точно так хотели или это ошибка. Возможно нагляднее было бы добавить параметры в функции, чтобы было при вызове было видно - какая область меняется.

C++:
void showClear() {
  for (int i = 64; i < 128; i++) {
    leds[i] = CRGB::Black;
  }
  //FastLED.show();
}

void fillRed() {
  for (int i = 0; i < 64; i++) {
    leds[i] = CRGB::Red;
  }
  FastLED.show();
}

void fillRedBlack() {
  for (int i = 0; i < 64; i++) {
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}

void fillYellow() {
  for (int i = 64; i < 128; i++) {
    leds[i] = CRGB::Yellow;
  }
  FastLED.show();
}
И по самой программе - проблемы проще решать по частям. Напишите например скетч, в котором на верхней матрице идет отсчет нечетных секунд, а на нижней четных. Когда разберетесь с выводом, тогда переходите к "светофору". И сам "светофор" можно начинать без матриц, выводя например сообщения в сериал.

Дополнение. Возможно FastLED.show(); имеет смысл вызывать после полного формирования картинки в массиве, а не после промежуточных шагов. Но это надо подробно смотреть алгоритм (чего я не делал).
 
Изменено:

BOT_Zilla

✩✩✩✩✩✩✩
1 Апр 2022
13
8
Что это означает? Не могу понять
Правильнее было бы написать "количество шагов работы светофора". Этим значением инициализируется размер массива
C++:
// Массив для хранения состояний
TrafficLightState states[maxStates] = {
 ...
...
};
Еще добавлю, что простой копипастой этот код работать не будет. Это просто образец, как сложить данные и как их достать.