HELP! поочередное включение светодиодов на заданное время ( установка циклов)

Session

✩✩✩✩✩✩✩
22 Сен 2019
4
0
Привет всем !
В общем мой проект: есть светодиода , дисплей(1602) , и энкодер с кнопкой. поворачивая енкодер мы выствляем время сколько будет гореть светодиод (1) я после завершения времени должен отключиться и включиться светодиод (2) на заданное время, а затем отключяиться и по идее ве ничего сложного. Но тут я подумал и мне нужно еще выставлять количество циклов (включинеия 1и 2 светодида ). По ковырял код (ALEXGYVER теплица) есть непонятные строчки. Я пытался как то обойти PERIOD коде но!, обходя его ничего не работает. И еще почему при запуске ардуинки она ждем время указанное время Периода а потом начинаеться цикл?? И почум при выборе времени работы более чем минута все стопориться и ничего не работает? Помощь создания кода с нуля..

вот кусок метода : ( просто чтоб понять)
void periodTick() {
for (byte i = 0; i < PUPM_AMOUNT; i++) { // пробегаем по всем помпам
if ( (millis() - pump_timers > ( (long)period_time * period_coef) ) непонятное условие (
переменная millis(), которая возвращает время с момента включения ардуины вычитается время pump_timer(1) больше чем ( вермя периода period_time[1] умноженое на period_coef Если выполняется равенсво если (pump_state[1] не равенSWITCH_LEVEL)
и !(now_pumping *!PARALLEL)
&& (pump_state != SWITCH_LEVEL)
&& !(now_pumping * !PARALLEL)) {
pump_state = SWITCH_LEVEL;
digitalWrite(pump_pins, SWITCH_LEVEL);
pump_timers = millis();
now_pumping = true;
}
}
}



C++:
#define ENCODER_TYPE 0
#define DRIVER_VERSION 0    // 0 - маркировка драйвера дисплея кончается на 4АТ, 1 - на 4Т
#define PUPM_AMOUNT 2      // количество помп, подключенных через реле/мосфет
#define START_PIN 5         // подключены начиная с пина
#define SWITCH_LEVEL 1     // реле: 1 - высокого уровня (или мосфет), 0 - низкого
#define PARALLEL 0          // 1 - параллельный полив, 0 - полив в порядке очереди
#define TIMER_START 0       // 1 - отсчёт периода с момента ВЫКЛЮЧЕНИЯ помпы, 0 - с момента ВКЛЮЧЕНИЯ помпы

//#define PERIOD 0            // 1 - период в часах, 0 - в минутах
#define PUMPING 1           // 1 - время работы помпы в секундах, 0 - в минутах

#define DROP_ICON 1         // 1 - отображать капельку, 0 - будет буква "t" (time)

// названия каналов управления. БУКВУ L НЕ ТРОГАТЬ БЛЕТ!!!!!!
static const wchar_t *relayNames[]  = {
   L"Pumped ",
   L"Vaccuumed",
  // L"Pump 3",
 
};

#define CLK 2
#define DT 3
#define SW 0

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);

#include <EEPROMex.h>
#include <EEPROMVar.h>

#include "LCD_1602_RUS.h"

// -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------
// Если кончается на 4Т - это 0х27. Если на 4АТ - 0х3f
#if (DRIVER_VERSION)
LCD_1602_RUS lcd(0x27, 16, 2);
#else
LCD_1602_RUS lcd(0x3f, 16, 2);
#endif
// -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------

unsigned long pump_timers[PUPM_AMOUNT];
unsigned int pumping_time[PUPM_AMOUNT];
unsigned int period_time[PUPM_AMOUNT];
unsigned int time_left[PUPM_AMOUNT];
boolean pump_state[PUPM_AMOUNT];
byte pump_pins[PUPM_AMOUNT];

byte current_set = 2;
byte current_pump;
boolean reDraw_flag, arrow_update;
boolean now_pumping;
unsigned long period_coef, pumping_coef;

void setup() {
  // --------------------- КОНФИГУРИРУЕМ ПИНЫ ---------------------
  for (byte i = 0; i < PUPM_AMOUNT; i++) {            // пробегаем по всем помпам
    pump_pins[i] = START_PIN + i;                     // настраиваем массив пинов
    pinMode(START_PIN + i, OUTPUT);                   // настраиваем пины
    digitalWrite(START_PIN + i, !SWITCH_LEVEL);       // выключаем от греха
  }
  // --------------------- ИНИЦИАЛИЗИРУЕМ ЖЕЛЕЗО ---------------------
  lcd.init();
  lcd.backlight();
  lcd.clear();
  enc1.setStepNorm(1);
  attachInterrupt(0, encISR, CHANGE);

  // --------------------- СБРОС НАСТРОЕК ---------------------
  if (!digitalRead(SW)) {          // если нажат энкодер, сбросить настройки до 1
    lcd.setCursor(0, 0);
    lcd.print("Reset settings");
    for (byte i = 0; i < 100; i++) {
      EEPROM.updateByte(i, 1);
    }
  }
  while (!digitalRead(SW));        // ждём отпускания кнопки
  lcd.clear();                     // очищаем дисплей, продолжаем работу

  // --------------------------- НАСТРОЙКИ ---------------------------
 // if (PERIOD) period_coef = (long)1000;  // перевод в часы
   period_coef = (long)60000 ;              // перевод в минуты

   pumping_coef = 1000 ;          // перевод в секунды
   //pumping_coef = (long)1000 * 60;       // перевод в минуты

  // в ячейке 100 должен быть записан флажок 1, если его нет - делаем (ПЕРВЫЙ ЗАПУСК)
  if (EEPROM.read(100) != 1) {
    EEPROM.writeByte(100, 1);

    // для порядку сделаем 1 ячейки с 0 по 99
    for (byte i = 0; i < 100; i++) {
      EEPROM.writeByte(i, 1);
    }
  }

  for (byte i = 0; i < PUPM_AMOUNT; i++) {            // пробегаем по всем помпам
    period_time[i] = EEPROM.readByte(2 * i);          // читаем данные из памяти. На чётных - период (ч)
    pumping_time[i] = EEPROM.readByte(2 * i + 1);     // на нечётных - полив (с)
  }

  // ---------------------- ВЫВОД НА ДИСПЛЕЙ ------------------------
  // вывести буквенные подписи
  lcd.setCursor(1, 0);
  //lcd.print("Pump #");
  lcd.print(relayNames[0]);
  lcd.setCursor(1, 1);
  lcd.print("Prd: ");
  lcd.setCursor(10, 1);
  lcd.print("t:");
  //lcd.print(": ");

  arrow_update = true;        // флаг на обновление стрелочки
  reDraw();                   // вывести на дисплей
  reDraw();                   // вывести на дисплей (флаг стрелок сбросился, выведем числа...)
}

void loop() {
  encoderTick();
  flowTick();
}


void flowTick() {
  for (byte i = 0; i < PUPM_AMOUNT; i++) {            // пробегаем по всем помпам
    if (  pump_timers[i] > pumping_coef  )
        
             now_pumping = true;
             else now_pumping = false;
    
  }
}

void encISR() {
  enc1.tick();                  // отработка энкодера
}

void encoderTick() {
  enc1.tick();                  // отработка энкодера

  if (enc1.isRelease()) {       // если был нажат
    arrow_update = true;        // флаг на обновление стрелочки
    reDraw();                   // обновить дисплей
  }

  if (enc1.isTurn()) {                               // если был совершён поворот
    switch (current_set) {                           // смотрим, какая опция сейчас меняется
      case 0:                                        // если номер помпы
        current_pump = enc1.normCount;               // получить значение с энкодера
        break;
      case 1:                                        // если период работы помпы
        period_time[current_pump] = enc1.normCount;  // получить значение с энкодера
        break;
      case 2:                                        // если время работы помпы
        pumping_time[current_pump] = enc1.normCount; // получить значение с энкодера
        break;
    }
    reDraw();                                        // обновить дисплей
  }
}

void reDraw() {
  if (arrow_update) {                            // если изменился режим выбора
    if (++current_set > 2)                       // менять current_set в пределах 0.. 2
      current_set = 0;
    if (current_set == 0) update_EEPROM();       // если переключилиссь на выбор помпы, обновить данные
    switch (current_set) {                       // смотрим, какая опция сейчас выбрана
      case 0:                                    // если номер помпы
        enc1.setCounterNorm(current_pump);       // говорим энкодеру работать с номером помпы
        enc1.setLimitsNorm(0, PUPM_AMOUNT - 1);  // ограничиваем
        // стереть предыдущую стрелочку и нарисовать новую
        lcd.setCursor(0, 0); lcd.write(126); lcd.setCursor(9, 1); lcd.print(" ");
        break;
      case 1:
        enc1.setCounterNorm(period_time[current_pump]);
        enc1.setLimitsNorm(1, 99);
        lcd.setCursor(0, 1); lcd.write(126); lcd.setCursor(0, 0); lcd.print(" ");
        break;
      case 2:
        enc1.setCounterNorm(pumping_time[current_pump]);
        enc1.setLimitsNorm(1, 99);
        lcd.setCursor(9, 1); lcd.write(126); lcd.setCursor(0, 1); lcd.print(" ");
        break;
    }
    arrow_update = false;
  } else {
    // вывести все цифровые значения на их места
    //lcd.setCursor(7, 0);
    //lcd.print(current_pump);
    if (current_set == 0) {
      lcd.setCursor(1, 0);
      lcd.print("              ");
      lcd.setCursor(1, 0);
      lcd.print(relayNames[current_pump]);
    }

    lcd.setCursor(5, 1);
    lcd.print(period_time[current_pump]);
  
    lcd.print("ss ");
    lcd.setCursor(12, 1);
    lcd.print(pumping_time[current_pump]);
     lcd.print("s ");
    
    /*
        Serial.print("Pump #"); Serial.print(current_pump);

            if (PERIOD) Serial.print(" hrs, period: ");
            else Serial.print(" min, period: ");
            Serial.print(period_time[current_pump]);

            if (PUMPING) Serial.print(" sec, flow: ");
            else Serial.print(" min, flow: ");
            Serial.println(pumping_time[current_pump]);
            }
    */
  }
}

// обновляем данные в памяти
void update_EEPROM() {
  EEPROM.updateByte(2 * current_pump, period_time[current_pump]);
  EEPROM.updateByte(2 * current_pump + 1, pumping_time[current_pump]);
}
 
Изменено:

Александр Симонов

★★★★✩✩✩
2 Авг 2018
727
208
Начни с нуля. Проще будет, чем из кода теплицы выковыривать нужный кусок.
Сначала помигай светодиодами с интервалами, заданными в прошивке вручную.
Потом то же самое с помощью millis().
Потом добавь дисплей и выведи на него интервалы.
И т.д. пока не сделаешь.

Заметки Ардуинщика в помощь: https://www.youtube.com/playlist?list=PLgAbBhxTglwmVxDDC5TSYUI91oZ0LZQMw
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,262
1,300
Москва
Пробовал делать типа часов на круговой ленте на 12 светодиодов (таких полно на али)
Идея такая, имеем RGB, R- секунды, G - минуты B - часы. если с часами все понятно, то минуты и секунды можно определить по интенсивности свечения светодиодов соотв. цвета. к примеру горят красным светом диоды на 1 и 2 часа. на 1 час горит чуть ярче. тогда это будет 7 секунд. если только на 1 час, то 5. если сильно ярче горит на 2 часа, то 9. на видео видно. ниже представлен полный код. начальные значения переменных выставлены для определенного времени. может чем поможет. Задержку делал по delay, т.к. просто тестировал, баловался.

C++:
#include <FastLED.h>

#define CHIPSET     WS2812B
#define NUM_LEDS    12
#define BRIGHTNESS  150
#define DATA_PIN 3

CRGB leds[NUM_LEDS];

int chas = 2;
int minut = 01;
int n_minut = 00;
int p_minut = 2;
int p_chas = 0;
int secund = 10;
int p_secund = 5;
int n_secund = 15;



void setup() {
  FastLED.addLeds<CHIPSET, DATA_PIN, RGB>(leds, NUM_LEDS);
  for (int i = 0; i < 12; i++) {
    leds[i] = CRGB::Black;
  }; 
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.show();
}

void loop() {

  secund = ((secund + 1) % 60);
  n_secund = ((secund + 5) % 60);
  p_secund = ((secund + 55) % 60);
  if (secund == 0)
  {
    minut = ((minut + 1) % 60);
    n_minut = ((minut + 5) % 60);
    p_minut = ((minut + 55) % 60);

    if (minut == 0)
    {
      p_chas = chas;
      chas = (chas + 1) % 12;
    };
  }

  leds[p_secund / 5] .g=0;
  switch (secund % 5) {
    case 0: {
        leds[secund / 5] = CRGB(0, 255, 0);
        leds[n_secund  / 5] = CRGB(0, 0, 0);
        break;
      };
    case 1: {
        leds[secund  / 5] = CRGB(0, 200, 0);
        leds[n_secund  / 5] = CRGB(0, 10, 0);
        break;
      };
    case 2: {
        leds[secund  / 5] = CRGB(0, 150, 0);
        leds[n_secund  / 5] = CRGB(0, 30, 0);
        break;
      }
    case 3: {
        leds[secund  / 5] = CRGB(0, 30, 0);
        leds[n_secund  / 5] = CRGB(0, 150, 0);
        break;
      };
    case 4: {
        leds[secund  / 5] = CRGB(0, 10, 0);
        leds[n_secund  / 5] = CRGB(0, 200, 0);
        break;
      };
  }


  leds[p_minut / 5] .r=0;
  switch (minut % 5) {
    case 0: {
        leds[minut / 5].r = 255;
        leds[n_minut / 5].r = 0;
        break;
      };
    case 1: {
        leds[minut / 5].r = 200;
        leds[n_minut / 5].r = 10;
        break;
      };
    case 2: {
        leds[minut / 5].r = 150;
        leds[n_minut / 5].r = 30;
        break;
      }
    case 3: {
        leds[minut / 5].r = 30;
        leds[n_minut / 5].r = 150;
        break;
      };
    case 4: {
        leds[minut / 5].r = 10;
        leds[n_minut / 5].r = 200;
        break;
      };
  }
  leds[p_chas].b = 0;
  leds[chas].b = 255;

  FastLED.show();
  delay(1000);
}
 

Session

✩✩✩✩✩✩✩
22 Сен 2019
4
0
Начни с нуля. Проще будет, чем из кода теплицы выковыривать нужный кусок.
Сначала помигай светодиодами с интервалами, заданными в прошивке вручную.
Потом то же самое с помощью millis().
Потом добавь дисплей и выведи на него интервалы.
И т.д. пока не сделаешь.

Заметки Ардуинщика в помощь: https://www.youtube.com/playlist?list=PLgAbBhxTglwmVxDDC5TSYUI91oZ0LZQMw
Спасибо за ответ, буду пробовать!
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Ещё не плохо почитать и освоить автоматное программирование. Вот тут https://community.alexgyver.ru/threads/dlja-detej-kak-lego.1398/, пост №12 - есть библиотека для решения таких вопросов "левой задней пяткой" с примерами. Делал для своего дитенка в его возрасте 11-12лет. Он - разобрался. :)

Ещё, для начала, можно посмотреть как работает "Блинк без delay()" и понять суть макроса everyMillis() в посту №12. Это просто "обобщение" такого подхода.

Для управления "сначала то, потом это столько-то времени" - смотрите пример "умгный светофор". Там как раз управление красным, желтым и зеленым через конечные автоматы "по таймеру"..
 

Session

✩✩✩✩✩✩✩
22 Сен 2019
4
0
Спасибо за ответ, я не первый день программирую и, (Я раньше не встречал подобного вида сложных условий). я не стал грузить вас подробностями своего проекта, и написал светодиод 1и 2 для упрощения . по поводу выковырять "PERIOD" из кода не получилось...

Ещё не плохо почитать и освоить автоматное программирование. Вот тут https://community.alexgyver.ru/threads/dlja-detej-kak-lego.1398/, пост №12 - есть библиотека для решения таких вопросов "левой задней пяткой" с примерами. Делал для своего дитенка в его возрасте 11-12лет. Он - разобрался. :)

Ещё, для начала, можно посмотреть как работает "Блинк без delay()" и понять суть макроса everyMillis() в посту №12. Это просто "обобщение" такого подхода.

Для управления "сначала то, потом это столько-то времени" - смотрите пример "умгный светофор". Там как раз управление красным, желтым и зеленым через конечные автоматы "по таймеру"..