Организация многозадачности: циклы и мр3 плеер с ИК управлением

leo-777
Offline
Зарегистрирован: 22.03.2018

Есть LED кубик, в котором поочередно крутится несколько циклов с эффектами. Есть свободные ноги на которые хочется повесить Мп3 плеер с управлением от ИК пульта.

Сразу прошу не закидывать тапками, а дать совет престарелому чайнику, ибо програмировал последний раз лет эдак 25 назад на Basic в институте).

 Поломал все остатки мозгов видимо от недостаточности знаний дьявольского С++. Как организовать (гуру, подскажите хотя бы алгоритм) чтобы циклы крутились в рабочем режиме сами по себе, а ИК пульт был всегда готов принять и отработать команду типа переключить трек или изменить громкость... Спасайте... 
З.Ы. - кусок кода с циклами (для примера)
 

void loop() {


  randomTimer++;

    loading = true;
    timer = 0;

    renderCube();
    loading = true;
    planeBoing();
    rain();
    sendVoxels();
    woopWoop();
    cubeJump();
    glow();
    text("0123456789", 10);
    lit();
}

void renderCube() {
  for (uint8_t i = 0; i < 8; i++) {
    digitalWrite(SS, LOW);
    SPI.transfer(0x01 << i);
    for (uint8_t j = 0; j < 8; j++) {
      SPI.transfer(cube[i][j]);
    }
    digitalWrite(SS, HIGH);
  }
}

void rain() {
  if (loading) {
    clearCube();
    loading = false;
  }
  timer++;
  if (timer > RAIN_TIME) {
    timer = 0;
    shift(NEG_Y);
    uint8_t numDrops = random(0, 5);
    for (uint8_t i = 0; i < numDrops; i++) {
      setVoxel(random(0, 8), 7, random(0, 8));
    }
  }
}

uint8_t planePosition = 0;
uint8_t planeDirection = 0;
bool looped = false;

void planeBoing() {
  if (loading) {
    clearCube();
    uint8_t axis = random(0, 3);
    planePosition = random(0, 2) * 7;
    setPlane(axis, planePosition);
    if (axis == XAXIS) {
      if (planePosition == 0) {
        planeDirection = POS_X;
      } else {
        planeDirection = NEG_X;
      }
    } else if (axis == YAXIS) {
      if (planePosition == 0) {
        planeDirection = POS_Y;
      } else {
        planeDirection = NEG_Y;
      }
    } else if (axis == ZAXIS) {
      if (planePosition == 0) {
        planeDirection = POS_Z;
      } else {
        planeDirection = NEG_Z;
      }
    }
    timer = 0;
    looped = false;
    loading = false;
  }

  timer++;
  if (timer > PLANE_BOING_TIME) {
    timer = 0;
    shift(planeDirection);
    if (planeDirection % 2 == 0) {
      planePosition++;
      if (planePosition == 7) {
        if (looped) {
          loading = true;
        } else {
          planeDirection++;
          looped = true;
        }
      }
    } else {
      planePosition--;
      if (planePosition == 0) {
        if (looped) {
          loading = true;
        } else {
          planeDirection--;
          looped = true;
        }
      }
    }
  }
}
и т.д.

Спасибо за советы

Valerikum
Offline
Зарегистрирован: 10.07.2017

Я сам престарелый чайник, сам подсел на ардуино 1 год назад, только в те далекие времена я программировал не на Бейсике, а на Си.

Чтобы циклы крутились в рабочем режиме сами по себе- это называется "кооперативная многозадачность", и на эту тему имеется достаточно много библиотек для ардуино. Но мы все любим идти своим путем... :)

Чтобы не ограничивать свободу творчества, даю несколько "наводок" на тему алгоритма

1. В стандартном ардуино IDE откройте Файл->Примеры->Digital->BlinkWithoutDelay

2. Поймите как там мигает светодиод и почему

3. Представьте, что вместо digitalWrite(ledPin, ledState) в примере вызывается одна из ваших функций

4. Организуйте таблицу, в каждой строке которой хранятся: времена последнего вызова данной функции, периодичность ее вызова, и собственно указатель на функцию, которую нужно вызывать

5. Можно добавить другие поля для расширения функционала ( например, флажки типа вызывать или не вызывать эту функцию на данном шаге алгоритма). Например, после того, как ваша функция отработала, она может сама себя "запретить" для вызова, а разрешить, например, другую, которая сработает, скажем, через 2 минуты, потом сама себя "запретит", а "разрешит", еще какую-то

6. Запихайте проверку очередной строки этой таблицы внуть loop(). Там проверяйте пора или не пора эту функцию вызвать, и если пора- вызывайте ее по указателю...

7. Все у вас будет крутиться в рабочем режиме самостоятельно, с нужной периодичностью вызываться. Можете проверять наличие сигнала от ИК пульта, например 1 раз в 500 мс ( я так делал- нажатия на пульт не терялись)

8. Логику работы устройства полезно нарисовать сначала хотя бы укрупненно в виде графа, где каждый узел -- состояние "конечного автомата" - легче будет программировать переходы- какие функции "запрещать", какие "разрешать"

Вот такие общие вам рекомендации.

Будет сложно -- опубликую фрагменты кода. Никакого C++, классический C от K&R. Молодежь меня, конечно, за это закидает тапками, но мне пофиг, потому как мое устройство исправно поливало грядку в прошлом сезоне...