Три индикатора с таймерами

В этом примере мы разберем несколько новых для нас понятий. Обратите внимание на то, что классы мы не используем только потому, что ещё пока их не проходили, но уже скоро всё станет значительно проще.

Данная программа содержит три виртуальных индикатора. Каждый индикатор определен параметрами структуры vLed.

struct vLed {           //аппаратно - виртуальный индикатор
  int pin;              //номер пина, к которому подключен светодиод
  int nFlash;           //число миганий светодиода этого индикатора
  int statTimer;        //состояние индикатора, текущий полупериод
  unsigned long time_x; //длительность включения светодиода
  timer vTimer;         //внутренний таймер виртуального индикатора
};

Значения pin, nFlash и time_x мы задаем при инициализации индикаторов один раз. Каждому индикатору свои. Они используются на протяжении всего цикла выполнения программы.

Для включения любого нашего индикатора необходимо вызвать функцию setVLed(vLed *vLed), передав ей в качестве параметра указатель на соответствующую структуру типа vLed. Функция запускает счетчик включений светодиода и запускает внутренний таймер (определяющий время включения светодиода).

Таймер я упростил и описал с помощью структуры timer. Эта структура входит в виртуальный индикатор, для управления временем свечения светодиода. Функции управления – setTimer и getTimer. В эти функции, в качестве параметра, передается указатель на переменную типа timer.

Указатель – переменная, содержащая адрес области памяти, в которой находится значение переменной необходимой для выполнения функции. Здесь описано более подробно.

#define BLUE 9     
#define GREEN 10
#define RED 11
#define LONG_TIME 2550

struct timer {
  unsigned long ulTime; //заданное время выключения
};

struct vLed {           //аппаратно - виртуальный индикатор
  int pin;              //номер пина, к которому подключен светодиод
  int nFlash;           //число миганий светодиода этого индикатора
  int statTimer;        //состояние индикатора, текущий полупериод
  unsigned long time_x; //длительность включения светодиода
  timer vTimer;         //внутренний таймер виртуального индикатора
};
//*****************************       установка времени задержки таймера
bool setTimer(unsigned long dt, timer *vTimer){     //dt - длительность задержки, nTimer - номер таймера
  bool bActive = false;
  if(vTimer->ulTime == 0){           //если таймер не включен
    bActive = true;
    vTimer->ulTime = millis() + dt;  //задаем значение - сумма текущего времени
  }                               //и заданного времни ожидания
  return bActive;
}
//***************************** запрос состояния таймера. Возвращает true, если включен.
bool getTimer(timer *vTimer){
  if(vTimer->ulTime <= millis()){   //проверяем состояние таймера
     vTimer->ulTime = 0;            //если время истекло, сбрасываем заданное значение, выключаем таймер.
  }
  return vTimer->ulTime != 0;       //возвращаем логическое состояние таймера, если включен - true
}
//***********************
bool setVLed(vLed *vLed){   //включение индикатора
  if(vLed->statTimer == 0){ //если индикатор свободен
    vLed->statTimer = vLed -> nFlash * 2; //переводим в полупериоды
    setTimer(vLed->time_x, &vLed->vTimer);
    return true;            //индикатор включен
  } else return false;      //индикатор занят
}
//************************************
bool cycleVLed(vLed *vLed){           //обеспечение работы индикатора
  if(vLed->statTimer > 0 && !getTimer(&vLed->vTimer)){ //определяем состояние таймера и если выключился,
      setTimer(vLed->time_x, &vLed->vTimer);           //запускаем заново
      int st = (vLed->statTimer & 1) == 0;            //состояние светодиода определяется младшим разрядом счетчика индикатора
      digitalWrite(vLed->pin, st);
      Serial.println(vLed->pin);
      vLed->statTimer--;      //уменьшаем счетчик индикатора
  }
  return vLed->statTimer > 0;
}
//***********************************
vLed arTimers[] = { //массив структур задающий параметры работы индикаторов
    {RED, 2, 0, 200, 0},
    {GREEN, 3, 0, 180, 0},
    {BLUE, 4, 0, 220, 0}
  };
timer randEvent = {0};    //таймер генерации случайного события для включения индикатора
int randLed = 0;          //индекс активного индикатора
//************************************
void setup() {
  for(int i=0; i < sizeof(arTimers)/sizeof(vLed); i++)
    pinMode(arTimers[i].pin, OUTPUT); //инициализация портов индикаторов
   Serial.begin(9600);
}
//*******************************
void loop() {
    if(!getTimer(&randEvent)){   //проверка состояния таймера randEvent, отвечающего за генерацию события включающего индикатор
      randLed = random(0, 3);    //получение случайного номера индикатора
      setTimer(LONG_TIME, &randEvent);  //запуск таймера randEvent
      setVLed(&arTimers[randLed]);  //включение индикатора
    }
    cycleVLed(&arTimers[randLed]);  //вызов функции обрабатывающей состояние активного индикатора
}