Пост #192 содержит код loop(), в котором все ветки ДРАКОН-схемы расписаны по отдельности, а не собраны вместе. В предыдущем скетче, у вас ветки объединены за счет сложных условий внутри if(). В частности один и тот же код занимается как включением так и ВЫключением ламп. Так ведь? А поскольку тот "объединенный" вариант вызывает трудности в розыске какой кусок как взаимодействует с остальными .. то я вам и развернул все эти условия в посту #192.
Вот и хочется увидеть результат вашего труда: полный скетч с кодом из #192 И перетасованный так, чтобы все ветки относящиеся к датчику1 были раньше чем все ветки датчика2. То есть сначала вернемся несколько назад увеличив скетч, а потом двинемся далее.
Видимо это я не так объясняю чего от Вас хочу .. смотрите, к первому датчику относятся пункты 3, 5, .. а ко второму 4, 6.. то есть идут "вперемежку", несмотря на то что это как-бы "независимые" ветки и исполнять их можно в ЛЮБОЙ последовательности (каждая ветка исполняется только при своем условии, которое изменяется глобально, то есть практически независимо от порядка в скетче) .. вот мне и хочется, чтобы Вы самостоятельно переставили пункты со своими условиями так, чтобы все ветки ДРАКОН-схемы, относящиеся к первому датчику шли друг за другом, "подряд". А за ними так же подряд уже шли все ветки, относящиеся ко второму датчику.
Угу. Условие с паузой "не на месте" .. продолжаем. Заметьте что под ним находится несколько веток от обоих датчиков, а вам надо их разделить по датчикам, но .. условие с паузой - одно. Стало быть "выбор невелик": откопировать условие паузы в обе разделяемые части. Должно получиться примерно так:
// Схема "Силуэт", обход веток датчиков последовательно:
// ветка1. "Царская дорога" она одна и разделять нечего
//---группа1--- датчик1:
// ветка2.1 "Темно" - ждем датчик1:
// ветка 3.1 поштучно включаем лампы от меньшей к большей:
// Ветка 4.1 "Лампы для датчика1 - включили все"? Включаем паузу и переходим к ветке 5.1
// Разделяем подветки ожидания:
curTime = millis();
// Ветка 5 "прошла пауза?"
// подветка 5.1 "Выключение ламп датчика1"
// Подветка 5.3 "Все лампы датчика1 выключены?"
} // конец ветки сработавшей паузы
//---группа2--- датчик2:
// ветка2.2 "Темно" - ждем датчик2:
// ветка 3.2. поштучно включаем лампы от большей к меньшей:
// Ветка 4.2 "Лампы для датчика2 - включили все"? Включаем паузу и переходим к ветке 5.2
// Разделяем подветки ожидания:
curTime = millis();
// Ветка 5 "прошла пауза?"
// Ветка 5.2 "Выключение ламп датчика2"
// Подветка 5.4 "Все лампы датчика2 выключены?"
} // конец ветки сработавшей паузы
Вот, такое перестроение кода я от вас и жду. С вас перестроенный код.
А пока продолжим со схемой: Как видите, обе группы веток практически индентичны, и их можно "завернуть" в цикл и тупо повторять его исполнение дважды. Остается только одна "проблема": надо как-то правильно определяться с используемыми данными для каждого повтора цикла: какой lamp будет использован в коде для первого или второго датчика? :)
В общем, пока ждем ваш перестроенный код согласно этому порядку веток схемы.
Да, похоже. А теперь, давайте посмотрим внимательно на код согласно предыдущему посту .. и выпишем все переменные, относящиеся к датчикам, получим:
pirPin, isGo, lamp, max, .. и startedAt, которая внутри функции fadeLED(). Именно из-за того, что мы в обоих группах использовали одну и туже функцию, которая внутри себя сама считает задержку, получалось что время пауз на изменения яркости второй группы ламп практически никогда и не срабатывали - задержка всегда отрабатывалась в первой группе. Надо иметь 2 стартовых времени.
Давайте введем структуру данных, которая будет определять все параметры рабочего цикла включения/выключения, типа так:
typedef struct{
uint8_t pir_pin; // номер пина для датчика движения
char step; // бывшая переменная isGo, теперь это "шаг" изменения яркости.
uint8_t lamp; // номер текущей лампы, которой изменяем яркость
char max; // номер последней лампы (недосчитывая) ДО которой будем перебирать лампы
unsigned long startedAt; // начало текущей паузы шага изменения лампы
} FadeCycle;
И, соответственно, теперь можем объявить массив из двух схем управления по 1 для каждого датчика:
FadeCycle fadeControl[2];
а после такого изменения данных можем оставить только одну группу веток, повторяя их в цикле дважды, перебирая схемы управления:
// Схема "Силуэт", обход веток датчиков последовательно:
// ветка1. "Царская дорога"
// if( isDayNow() ){ /*выключить всё*/ return; }
for(uint8_t num=0; num<2; num++)
{
// ветка2 "Темно" - ждем датчик:
if( digitalRead(fadeControl[num].pir_pin) )
{
fadeControl[num].step = 1;
// группа 0: от меньшей к большей, группа 1: от большей к меньшей
fadeControl[num].lamp = (num==0? 0 : MAX_LED-1);
fadeControl[num].max = (num==0? MAX_LED : -1);
}
// ветка 3 поштучно включаем лампы от меньшей к большей:
if( fadeControl[num].step == 1 )
{
// подветка 3.1 "текущая лампа уже включена? перейти к следующей"
if( fades[fadeControl[num].lamp].bright == 255 ){
fadeControl[num].lamp += (num==0? 1 : -1);
}else{
fadeLED(num); // теперь сюда передаем номер группы!
}
}
// Ветка 4 "Лампы для датчика - включили все"? Включаем паузу и переходим к ветке 5.1
if( fadeControl[num].step == 1 && fadeControl[num].lamp == fadeControl[num].max )
{
startedPause = millis();
fadeControl[num].isGo = -1;
// и тут тоже устанавливаем начало и конец в зависимости от того какая группа управления:
fadeControl[num].lamp = (num==0? 0 : MAX_LED-1);
fadeControl[num].max = (num==0? MAX_LED : -1);
}
// Ветка 5 "прошла пауза?"
curTime = millis();
if( curTime - startedPause >= WAIT_PAUSE )
{
// подветка 5.1 "Выключение ламп датчика"
if((fadeControl[num].step == -1))
{
if( fades[fadeControl[num].lamp].bright == 0 )
{
// Лампа выключена, переходим к следующей
fadeControl[num].lamp += (num==0? 1 : -1);
}else{
// продолжаем выключать лампу этой группы
fadeLED(num);
}
}
// Подветка 5.2 "Все лампы датчика выключены?"
if( fadeControl[num].step == -1 && fadeControl[num].lamp == fadeControl[num].max )
{
fadeControl[num].step = 0;
}
} // конец ветки сработавшей паузы
}
Ну и соответственно, саму функцию fadeLED() надо обучить использовать место для хранения задержек изменения яркости, и тем самым устранить предыдущий недостаток работы второй группы:
/**
* Функция изменения яркости на 1 шаг state РАЗ в 10 миллисекунд
* @param state: +1 -- включение; -1 -- выключение
*/
void fadeLED(uint8_t num)
{
Led * ptr = &(fades[fadeControl[num].lamp]); // врем. лок. указатель на структуру "лампа"
if(
millis() - fadeControl[num].startedAt >= WAIT_1 // пора изменять яркость?
&& (
(fadeControl[num].step==1 && ptr->bright < 255) // включаем И есть куда?
||
(fadeControl[num].step==-1 && ptr->bright > 0) // или вЫключаем И есть куда?
)
){
fadeControl[num].startedAt = millis(); // новое время для отсчета следующей паузы
ptr->bright += fadeControl[num].step; // изменяем яркость
analogWrite( ptr->pin, ptr->bright); // устанавливаем на выходе
Serial.print(" b="); Serial.println(ptr->bright); // передаем данные в порт для отладки
}
}
Собрать всё воедино и проверить на очепятки и пропуски, сверив со схемой.
И вот теперь снова обнаруживаем, что мы дважды проверяем условие кончились ли лампы и дважды вызываем fadeLED() - один раз при включении, другой при выключении .. то есть ветки "включить" и выключить" в общем-то похожи и их можно свернуть в одно целое:
Ну и напоследок, работа с указателями. Если мы сразу, в начале цикла заведем указатель на структуру fadeControl[num], то он не изменяется внутри цикла, а стало быть можно сделать типа так:
Ну и вызво функции fadeLed остался один, и её можно развернуть сюда напрямую. Оставим, ибо некритично, зато понятней.
P.S. Любители С++ теперь могут проявить свою фантазию и создать базовый класс FadeCycleAbstract, который будет перечислять свойства объекта "схема включения ламп", они тут уже перечислены в виде структуры, далее отнаследовать 2 класса с разными схемами управления "от меньшей к большей" и "от большей к меньшей" и создать массив из 2 объектов ровно по 1 на каждый дочерний класс. И только "потом" показать как "синтаксический сахар" улучшает читабельность конечного loop()... и внезапно убедится что код оказался "не меньше". :)
Вам это будет не менее непонятно, а мне и не интересно ни разу.
P.P.S. Осталось решить совсем мелкую проблему: в случае, когда оба датчика срабатывают (почти) одновременно, лампы будут загораться с концов как и положено. Но вот по истечению паузы .. выключаться они будут с тех же самых концов к середине. А хотелось бы "не так" ..
Но. соберите и опубликуйте уже окончательный скетч, и мы эту проблему решим.
Почти верно. Массив структур fadeControl у вас объявлен, и в нем поле pir_pin должно содержать номер того пина, на котором сидит датчик движения. Для 0 элемента массива это pirPin1, а для 1-го элемента это pirPin2 .. но они туда в setup не прописываются. Остальные параметры структуры можно и не задавать, они устанавливаются по мере необходимости. Но вот без номера пина, ваш digitalRead() читает из неизвестно откуда ..
Переставьте setup() ниже определения структур и данных и добавьте в него установку номеров пинов датчиков, типа так:
// структура - описание понятия "Лампа" - это пин и текущая яркость:
typedef struct{
uint8_t pin;
uint8_t bright;
} Led;
typedef struct{
uint8_t pir_pin; // номер пина для датчика движения
char step; // бывшая переменная isGo, теперь это "шаг" изменения яркости.
uint8_t lamp; // номер текущей лампы, которой изменяем яркость
char max; // номер последней лампы (недосчитывая) ДО которой будем перебирать лампы
unsigned long startedAt; // начало текущей паузы шага изменения лампы
} FadeCycle;
FadeCycle fadeControl[2];
void setup()
{
fadeControl[0].pir_pin = pirPin1;
fadeControl[1].pir_pin = pirPin2;
pinMode(pirPin1, INPUT); // настариваем 2 пин как вход для сигналов с датчика
pinMode(pirPin2, INPUT); // настариваем 4 пин как вход для сигналов с датчика
pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором
pinMode(fadePin2, OUTPUT);
pinMode(fadePin3, OUTPUT);
pinMode(fadePin4, OUTPUT);
pinMode(fadePin5, OUTPUT);
pinMode(fadePin6, OUTPUT);
Вечером доберусь до дуньки - посмотрю. Сейчас пока никак. Возможно, где-то оставил "грабли" по невнимательности. Проверьте все переменные и параметры, в т.ч. и в структурах на соответствие типам данных (это первое что надо проверять всегда в программах на С), потом надо будет посмотреть что происходит во всех условиях "попадалова" внутрь веток, возможно не совсем корректно была проведена перестановка и объединение веток.
Там в целом должно быть "без разницы" первый или второй датчик. Попробуйте запустить цикл только по второму датчику поставив стартовое условие цикла i=1, то есть начинаем не с 0, а сразу с 1, пропуская первый датчик ..
Ну в общем-то, посмотрел .. всё "как обычно": поле lamp в структуре FadeCycle надо сделать char .. поскольку при обратном счете оно принимает значения 5,4,3,2,1,0, .. -1 . то есть является знаковым байтом. :)
#define fadePin1 3 // пин управления MOSFET транзистором
#define fadePin2 5 // пин управления MOSFET транзистором
#define fadePin3 6 // пин управления MOSFET транзистором
#define fadePin4 9 // пин управления MOSFET транзистором
#define fadePin5 10 // пин управления MOSFET транзистором
#define fadePin6 11 // пин управления MOSFET транзистором
#define pirPin1 2 // пин подключения управляющего сигнала PIR датчика1
#define pirPin2 4 // пин подключения управляющего сигнала PIR датчика2
int calibrationTime = 30; // Время калибровки датчика (10-60 сек. по даташиту)
// структура - описание понятия "Лампа" - это пин и текущая яркость:
typedef struct{
uint8_t pin;
uint8_t bright;
} Led;
typedef struct{
uint8_t pir_pin; // номер пина для датчика движения
char step; // бывшая переменная isGo, теперь это "шаг" изменения яркости.
char lamp; // номер текущей лампы, которой изменяем яркость
char max; // номер последней лампы (недосчитывая) ДО которой будем перебирать лампы
unsigned long startedAt; // начало текущей паузы шага изменения лампы
} FadeCycle;
FadeCycle fadeControl[2];
void setup()
{
fadeControl[0].pir_pin = pirPin1;
fadeControl[1].pir_pin = pirPin2;
pinMode(pirPin1, INPUT); // настариваем 2 пин как вход для сигналов с датчика
pinMode(pirPin2, INPUT); // настариваем 4 пин как вход для сигналов с датчика
pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором
pinMode(fadePin2, OUTPUT);
pinMode(fadePin3, OUTPUT);
pinMode(fadePin4, OUTPUT);
pinMode(fadePin5, OUTPUT);
pinMode(fadePin6, OUTPUT);
Serial.begin(9600);
Serial.print("Calibrating"); //дадим датчику время на калибровку
for(int i = 0; i < calibrationTime; i++)
{
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
}
// теперь создадим список ламп, заодно и введем константу "всего ламп"
#define MAX_LED 6
Led fades[MAX_LED] = {{fadePin1, 0}, {fadePin2, 0}, {fadePin3, 0},
{fadePin4, 0}, {fadePin5, 0}, {fadePin6, 0}};
#define WAIT_1 4 // 10мсек - пауза между изменениями яркости
uint32_t startedAt = 0; // тут будем хранить время последнего запуска fadeLed
#define WAIT_PAUSE 5000 // пауза когда MAX_LED=255
uint32_t startedPause = 0; // тут будем вести отсчет паузы до выключения
//int8_t isGo1 = 0; // режим включения/выключения от левого датчика
//uint8_t lamp1 = 0; // номер текущей лампы управления левым датчиком
//uint8_t max1 = 0; // последний номер режимов левого датчика
//int8_t isGo2 = 0; // режим включения/выключения от правого датчика
//uint8_t lamp2 = 0; // номер текущей лампы управления правого датчиком
//uint8_t max2 = 0; // последний номер режимов правого датчика
uint8_t isDayNow(void){ return 0; }
/**
* Функция изменения яркости на 1 шаг state РАЗ в 10 миллисекунд
* @param state: +1 -- включение; -1 -- выключение
*/
void fadeLED(uint8_t num)
{
Led * ptr = &(fades[fadeControl[num].lamp]); // врем. лок. указатель на структуру "лампа"
if(
millis() - fadeControl[num].startedAt >= WAIT_1 // пора изменять яркость?
&& (
(fadeControl[num].step==1 && ptr->bright < 255) // включаем И есть куда?
||
(fadeControl[num].step==-1 && ptr->bright > 0) // или вЫключаем И есть куда?
)
){
fadeControl[num].startedAt = millis(); // новое время для отсчета следующей паузы
ptr->bright += fadeControl[num].step; // изменяем яркость
analogWrite( ptr->pin, ptr->bright); // устанавливаем на выходе
Serial.print(" b="); Serial.println(ptr->bright); // передаем данные в порт для отладки
}
}
//uint32_t curTime;
void loop()
{
// if( isDayNow() ){ /*выключить всё*/ return; }
for(uint8_t num=0; num<2; num++)
{
FadeCycle * cur = &(fadeControl[num]);
if( digitalRead(cur->pir_pin) )
{
cur->step = 1;
cur->lamp = (num==0? 0 : MAX_LED-1);
cur->max = (num==0? MAX_LED : -1);
}
if(
(cur->step > 0) // если включаем лампы, то сразу
|| (
(cur->step < 0) // а вот если вЫключаем, то
&& (millis() - startedPause >= WAIT_PAUSE) // по истечению паузы
)
){
if( cur->step > 0 && fades[cur->lamp].bright == 255 )
{
cur->lamp += (num==0? 1 : -1);
if( cur->lamp == cur->max )
{
startedPause = millis();
cur->step = -1;
cur->lamp = (num==0? 0 : MAX_LED-1);
cur->max = (num==0? MAX_LED : -1);
}
}else
if( cur->step < 0 && fades[cur->lamp].bright == 0 )
{
cur->lamp += (num==0? 1 : -1);
if( cur->lamp == cur->max )
{
cur->step = 0;
}
}else{
fadeLED(num); // теперь сюда передаем номер группы!
}
}
}
}
Вот ОН, рабочий скетч! ;) Мож кому сгодится! :)
#define WAIT_1 4 // 10мсек - пауза между изменениями яркости это понятно что! А где храниться переменная самой яркости, вот это понять не могу! Подскажите, как её поменять и где!?
Одно смущает, когда от двух датчиков сразу, красивее было бы тушить от центра к краям! Но и так красява:) Теперь все это в железо и куууууууучу проводов:)
Текущие яркости хранятся в поле bright структуры описания "лампа", для каждой лампы - в своем элементе массива fades[]
Да. Вам осталось сделать чтобы когда оба датчика сработали, то гашение ламп должно начинаться не "так же", а от точки их всртечи .. чем таким особенным (как обычно, все интересное в отличиях, а не общностях!) отличается поведение нашего алгоритма?
Смотрите на код: "if( cur->step > 0 && fades[cur->lamp].bright == 255 )" строка 129. Если шаг больше нуля (кстати стоит везде заменить на больше/меньше вместо ==, тогда можно будет изменять яркость не по +-1), то есть если мы включали лампу И(!) её яркость достигла предела .. в следующей строке идет попытка перейти на следующую лампу .. но она УЖЕ может быть включена вторым датчиком .. нет? Кем-то ишо? :)
Соответственно, если после 131 строки с попыткой перехода поставить проверку на текущую яркость лампы .. и если мы тут обнаруживаем что она включена .. то эта лампа и будет той самой "точкой отсчета" при последующем выключении. Нет? :)
А если да, то что надо сделать в этом случае?
P.S. И заметьте, что при обработке алгоритма второго датчика произойдет "то же самое" .. он тоже обнаружит что лампа "уже включена".. сам.
Сработали оба датчика, включили, все в норме. Но стоит сработать какому либо одному датчику(когда считаем паузу) после паузы, тухнет только одна лампа, первая, в зависимости от того какой датчик сработал!
И потом 5 ламп горят(ну тут понятно, горят то 5, а не шесть, соответственно паузу считать мы не можем), до того как не сработает какой нибудь датчик!
Вроде бы не должно быть такого косячка. Когда датчики отработали, управлялки установлены в step=-1, и последний сработавший датчик перезапустит паузу. Во время неё, исполняется код в цикле по очереди для обоих датчиков, строки: 116 (проверка датчиков), 123 - "мимо", ждем выключения ИЛИ (далее) 125 - "ок", будем выключать И 126 - "мимо", пауза ещё НЕ завершена. Всё.
Если один из дачиков в этом наборе сработает (строка 116), то он переведет себя на режим включения ламп, и далее сразу же (в этом же проходе цикла) сработает строка 123 и сразу далее строка 129 тоже сработает (лампы - горят) и сразу сработает переключение на следующую лампу, строка 131. Это всё за один проход цикла, как только обнаружено срабатывание. Далее, если пауза так и не успеет отработать, за каждый следующий вызов loop(), сработавший датчик будет переходить к следующей лампе, пока не переберет все, строкой 131. Псоле чего, отработает строка 132 и он перезапустит паузу заново, перейдя в режим выключения. То есть, если в прочессе пробежки в попытках включить лампу пауза не успела сработать для второго датчика, то никаких "косяков" вы не сможете заметить .. только лампы будут гореть ещё туже самую паузу.
Проверить можно так: запустили оба процесса "практически" одновременно - лампы должны загораться с обоих концов. С момента включения последней лампы засекаете время ожидания выключения и пока оно не завершено - запускаете один из датчиков повторно. Он "пробежится" ну, очень быстро и соответственно, с момента повторного срабатывания должна отработать пауза ещё раз и оба канал погаснуть со своих концов к середине. Так?
Если в процессе "пробежки" сработавшего датчика по горящим лампам, пауза успеет завершиться, то второй датчик должен начать гасить лампы со своего конца, в то время как сработавший будет пытаться их включать .. первая же лампа, на которой они пересекуться .. будет включаться и выключаться попеременно и наш алгоритм "зависнет" (-1 +1) в "борьбе за лампу". Вот это - косяк. Потому как процесс "завершиться" не может. :)
Да, надо добавить блокировку одновременного включения и выключения одной и той же лампы разными датчиками. Способов несколько:
1. Активизация цикла включения ламп может останавливать выключение вторым процессом. После строки 120 последней версии "вот он рабочий скетч" добавить проверку:
В этом случае, сработавший датчик останавливает процесс выключения от второго датчика. Недостаток: по истечению новой паузы лампы будут выключаться только этим процессом. Но, если в процессе ожидания лампы снова сработает какой-либо датчик, то он потом и будет всё выключать .. может и "сойдет" .. решать вам.
2. Процесс включения важнее процесса выключения, и можно в выключающую ветку вставить контроль "пересечения процессов" для остановки процесса выключения. Для этого надо менять строку 140:
3. Можно не трогать процесс выключения, а всего лишь запретить паузу .. по истечении которой он продолжит свое выключение с той лампы, где стопорнулся. Для этого после строки 120 можно добавить типа так:
startedPause = millis()+5000;
, где 5000 - время вашей паузы. Такая установка гарантировано запретит процесс выключения и повторно сработавший датчик успеет все повключать и снова переставит паузу куда надо. По истечению которой оба процесса продолжат выключение. повторно сработавший "с начала", а тормознутый с того места где прервался.. может так будет прикольней, не знаю .. решать вам.
Ну, я тоже так решил, что первый вариант самый простой и логически верный. Если в процессе ожидания что-то сработало, то логику второго датчика надо отключать .. не факт, что он тоже позже не сработает ещё раз.
С Вас "окончательный" скетч в сборе, может кому и понадобится. :)
Вот только когда сработали оба датчика, включение происходит как хотел, а вот выключение с одного края!(Край я так понял зависит от того, какой датчик передал сигнал последним)
Ну так первый вариант это и предполагает: повторное включение датчика во время ожидания паузы .. выключает из процесса второй датчик, дабы не драться "за лампу". Соответственно он уже "ничего не выкелючит" после новой паузы. :)
Третий вариант в этом плане интересней, поскольку он не выключает, а только откладывает выключение вторым датчиком на новую паузу .. но к нему будут точно такие же придирки, только "наоборот": прошли "туда и обратно" (сработали ОБА датчика) и тут, внезапно пошел народ "гуськом" с одной стороны (несколько срабатываний во время паузы одного и того же датчика) .. про второй датчик уже и забылось .. прошла наконец-то длинная пауза и пошло выключение .. с обоих сторон. Нафига?!? :)
"Лучшее - враг хорошего". В том смысле, что ни один из способов исключения "драк за лампу" не оптимален для всех случаев жизни .. на чем-то надо и остановиться. Да и с двумя датчиками, там у вас и иные "эффекты" будут .. в частности:
"вошел - включилось, постоял внутри .. упс, пошло выключение"
"вошел - включилось, прошел - на выходе сработал .. второй датчик .. и упс. выключение пошло от него, а не от первого .. или от ОБОИХ"
Пошли, сработал 1 датчик, включил все, пауза пошла, прошли 2 датчик(во время паузы) после паузы, выключение идет не с того края как должно! Не есть хорошо:(
Прошли первый, включилось если ВСЁ, то 2 датчик ТОЛЬКО продливает паузу(зачем нам что то включать, уже все горит, от своего датчика, пусть и горит дальше себе), не включает ничего!(так можно вообще?)
А вот если не все включилось еще, то включать со своей стороны!(Но я думаю редкое явление, не такое у меня тут движение:))
И во время паузы, ни чего не проверять, не включать, а только продливать паузу!
Но и тут 1000% будут косяки, я их просто не вижу:(
Я же предлагал Вам в самом начале "игнорировать" второй датчик на конец прохода того, кто "задел" первый .. иначе на выходе как раз получите именно этот эффект .. но! Если его игнорировать то .. а вдруг это и не выход из под второго датчика, а вход нового, как "отличить"? .. у вас там таких "коллизий" вагон и маленькая тележка .. расслабьтесь. С только 2-я датчиками движения можно оставить "как есть", ибо попытки избежать коллизии одного вида неизбежно приведут к друцгим. :)
В таком разе, поперву сформулируйте ваше "до ума" ясно, четко .. в виде некоего автомата, лучше в ДРАКОН-схеме. Тогда вам станет совершенно понятно что и куда надо будет поправить в этом скетче. А так .. гадать можно до бесконечности.
Можно и не пробегать. Просто предварительно проверять условие "ещё идет пауза?" .. но какой в этом специальный смысл? Пробежка по лампам позволяет нам удостовериться что они все включены и производится достаточно быстро.. очень быстро, а самое главное "прозрачно" для контроля датчиков.
На том сайте, что я Вам указывал есть несколько программ-редакторов ДРАКОН-схем. Есть платные с месяцем бесплатного пользования (ИС ДРАКОН) есть и бесплатные. Они заодно ещё и проверяют вашу схему на корректность, а то и вовсе не позволяют писать криво. Кроме того, там есть "кодогенерация" по схеме .. больше конечно ручная, но позволяет тем не менее получать вполне приемлемый код скетчей.
ну так если идет пауза, они и так включены! Тогда датчики перестанут руководить лампами, на время паузы, а будут только продливать паузу! (по логике мыслю! :)) !?
Там есть кнопочка "проверить схему" - пользовались? Левых обратных стрелок (у Вас первая по схеме) быть не может согласно правилам. Это конечно же "не та схема".. давайте вечерком выложу свою.
Да я понимаю(надо не стрелку, а просто обойти датчик 1 в этой ветке), пока не разобрался еще! Пользовался проверкой, но видимо еще не понял что куда там, вечно пишет что должен быть "хотя бы один выход", а зачем он мне, если этот цикл бесконечный?
Не могу открыть ИС Дракон, похоже триальный период кончился .. ладно, давайте по вашей схеме из #241:
1. Вообще-то выход у Вас есть, поскольку это loop() вызывается бесконечно, а сам он очень даже конечен. Ну да ладно, пока можно и так.
2. Ветка "Датчик света" .. с чего это она у вас замыкается "сама на себя"? Она должна указывать вниз на маркер "Датчик света" .. и ветвление надо поменять местами, ибо "царская дорога" - прямая линия. После смены условия, выбор "нет" окажется справа и тоже должен уходить вниз схемы на маркер "Датчик1"
3. Ветка "Датчик1" .. какова его "Царская дорога"? Да и вообще, что он делает? Он ведь если НЕ сработал, то НЕ делает ничего .. то есть уходит на "Датчик2", а если сработал .. то только устанавливает режим включения ламп присваивая переменные .. и только. А стало быть когда "да", то есть одна, простая икона "Действие" с присвоением значений и .. маркер отсутствующей ветки "Включение".
4. Ветка "Включение" - вовсе не в хвосте действий датчика1, а самостоятельная ветка. И она у вас отрабатывает ровно 1 раз за 1 вызов loop() увеличивая яркость текущей лампы на ".step"
.. и т.д.
В целом, тут надо было применить не "Силуэт" а "Конечный автомат" .. но давайте уже на этом варианте доделаем.
Да, примерно так и должно быть. Сравните с кодом: если первый датчик не сработал, то по сути цикл по датчикам - завершается и переходим ко второму датчику. Давайте я завтра проплачу эти большие деньги и таки сделаю. "ИС Дракон" сразу "не позволяет писать криво" в отличии от Drakon-Editor, который по сути просто рисовалка произвольных схем.
Пост #192 содержит код loop(), в котором все ветки ДРАКОН-схемы расписаны по отдельности, а не собраны вместе. В предыдущем скетче, у вас ветки объединены за счет сложных условий внутри if(). В частности один и тот же код занимается как включением так и ВЫключением ламп. Так ведь? А поскольку тот "объединенный" вариант вызывает трудности в розыске какой кусок как взаимодействует с остальными .. то я вам и развернул все эти условия в посту #192.
Вот и хочется увидеть результат вашего труда: полный скетч с кодом из #192 И перетасованный так, чтобы все ветки относящиеся к датчику1 были раньше чем все ветки датчика2. То есть сначала вернемся несколько назад увеличив скетч, а потом двинемся далее.
Смотрю в книгу вижу ф....у!))) Это если честно!)))
В #192 они и так вроде стоят в своем порядке, сначала 1 датчик, затем второй! Или я чего то не понимаю!?
Общее у них только
я наверно просто не пойму, но вот
Видимо это я не так объясняю чего от Вас хочу .. смотрите, к первому датчику относятся пункты 3, 5, .. а ко второму 4, 6.. то есть идут "вперемежку", несмотря на то что это как-бы "независимые" ветки и исполнять их можно в ЛЮБОЙ последовательности (каждая ветка исполняется только при своем условии, которое изменяется глобально, то есть практически независимо от порядка в скетче) .. вот мне и хочется, чтобы Вы самостоятельно переставили пункты со своими условиями так, чтобы все ветки ДРАКОН-схемы, относящиеся к первому датчику шли друг за другом, "подряд". А за ними так же подряд уже шли все ветки, относящиеся ко второму датчику.
Опять не вкурил! Но, подряд это так я думаю
Если убрать все подветки, как раз и будет по порядку!
Кроме паузы, как то она все не на своем месте, мне кажется!:)
Угу. Условие с паузой "не на месте" .. продолжаем. Заметьте что под ним находится несколько веток от обоих датчиков, а вам надо их разделить по датчикам, но .. условие с паузой - одно. Стало быть "выбор невелик": откопировать условие паузы в обе разделяемые части. Должно получиться примерно так:
Вот, такое перестроение кода я от вас и жду. С вас перестроенный код.
А пока продолжим со схемой: Как видите, обе группы веток практически индентичны, и их можно "завернуть" в цикл и тупо повторять его исполнение дважды. Остается только одна "проблема": надо как-то правильно определяться с используемыми данными для каждого повтора цикла: какой lamp будет использован в коде для первого или второго датчика? :)
В общем, пока ждем ваш перестроенный код согласно этому порядку веток схемы.
Вроде бы так!
Да, похоже. А теперь, давайте посмотрим внимательно на код согласно предыдущему посту .. и выпишем все переменные, относящиеся к датчикам, получим:
pirPin, isGo, lamp, max, .. и startedAt, которая внутри функции fadeLED(). Именно из-за того, что мы в обоих группах использовали одну и туже функцию, которая внутри себя сама считает задержку, получалось что время пауз на изменения яркости второй группы ламп практически никогда и не срабатывали - задержка всегда отрабатывалась в первой группе. Надо иметь 2 стартовых времени.
Давайте введем структуру данных, которая будет определять все параметры рабочего цикла включения/выключения, типа так:
И, соответственно, теперь можем объявить массив из двух схем управления по 1 для каждого датчика:
а после такого изменения данных можем оставить только одну группу веток, повторяя их в цикле дважды, перебирая схемы управления:
Ну и соответственно, саму функцию fadeLED() надо обучить использовать место для хранения задержек изменения яркости, и тем самым устранить предыдущий недостаток работы второй группы:
Собрать всё воедино и проверить на очепятки и пропуски, сверив со схемой.
И вот теперь снова обнаруживаем, что мы дважды проверяем условие кончились ли лампы и дважды вызываем fadeLED() - один раз при включении, другой при выключении .. то есть ветки "включить" и выключить" в общем-то похожи и их можно свернуть в одно целое:
Примерно, как-то так все сворачивается обратно. :)
Ну и напоследок, работа с указателями. Если мы сразу, в начале цикла заведем указатель на структуру fadeControl[num], то он не изменяется внутри цикла, а стало быть можно сделать типа так:
Ну и вызво функции fadeLed остался один, и её можно развернуть сюда напрямую. Оставим, ибо некритично, зато понятней.
P.S. Любители С++ теперь могут проявить свою фантазию и создать базовый класс FadeCycleAbstract, который будет перечислять свойства объекта "схема включения ламп", они тут уже перечислены в виде структуры, далее отнаследовать 2 класса с разными схемами управления "от меньшей к большей" и "от большей к меньшей" и создать массив из 2 объектов ровно по 1 на каждый дочерний класс. И только "потом" показать как "синтаксический сахар" улучшает читабельность конечного loop()... и внезапно убедится что код оказался "не меньше". :)
Вам это будет не менее непонятно, а мне и не интересно ни разу.
P.P.S. Осталось решить совсем мелкую проблему: в случае, когда оба датчика срабатывают (почти) одновременно, лампы будут загораться с концов как и положено. Но вот по истечению паузы .. выключаться они будут с тех же самых концов к середине. А хотелось бы "не так" ..
Но. соберите и опубликуйте уже окончательный скетч, и мы эту проблему решим.
Ок, через недельку-месяцок, как разберусь во всем этом)))))))))) если смогу конечно)
Но чувствую что вряд ли :(
Половину не пойму, что от куда взялось то :(
Уж не знаю, правильно или нет, но компилятор скушал :(
Но судя по работе, не правильно! :(
Почти верно. Массив структур fadeControl у вас объявлен, и в нем поле pir_pin должно содержать номер того пина, на котором сидит датчик движения. Для 0 элемента массива это pirPin1, а для 1-го элемента это pirPin2 .. но они туда в setup не прописываются. Остальные параметры структуры можно и не задавать, они устанавливаются по мере необходимости. Но вот без номера пина, ваш digitalRead() читает из неизвестно откуда ..
Переставьте setup() ниже определения структур и данных и добавьте в него установку номеров пинов датчиков, типа так:
Остальное похоже на правду.
Если я все верно понял, то вроде так!?
Пробую!
Вечером доберусь до дуньки - посмотрю. Сейчас пока никак. Возможно, где-то оставил "грабли" по невнимательности. Проверьте все переменные и параметры, в т.ч. и в структурах на соответствие типам данных (это первое что надо проверять всегда в программах на С), потом надо будет посмотреть что происходит во всех условиях "попадалова" внутрь веток, возможно не совсем корректно была проведена перестановка и объединение веток.
Там в целом должно быть "без разницы" первый или второй датчик. Попробуйте запустить цикл только по второму датчику поставив стартовое условие цикла i=1, то есть начинаем не с 0, а сразу с 1, пропуская первый датчик ..
Ну в общем-то, посмотрел .. всё "как обычно": поле lamp в структуре FadeCycle надо сделать char .. поскольку при обратном счете оно принимает значения 5,4,3,2,1,0, .. -1 . то есть является знаковым байтом. :)
Вот ОН, рабочий скетч! ;) Мож кому сгодится! :)
#define WAIT_1 4 // 10мсек - пауза между изменениями яркости это понятно что! А где храниться переменная самой яркости, вот это понять не могу! Подскажите, как её поменять и где!?
Одно смущает, когда от двух датчиков сразу, красивее было бы тушить от центра к краям! Но и так красява:) Теперь все это в железо и куууууууучу проводов:)
Текущие яркости хранятся в поле bright структуры описания "лампа", для каждой лампы - в своем элементе массива fades[]
Да. Вам осталось сделать чтобы когда оба датчика сработали, то гашение ламп должно начинаться не "так же", а от точки их всртечи .. чем таким особенным (как обычно, все интересное в отличиях, а не общностях!) отличается поведение нашего алгоритма?
Смотрите на код:
"if
( cur->step > 0 && fades[cur->lamp].bright == 255 )" строка 129. Если шаг больше нуля (кстати стоит везде заменить на больше/меньше вместо ==, тогда можно будет изменять яркость не по +-1), то есть если мы включали лампу И(!) её яркость достигла предела .. в следующей строке идет попытка перейти на следующую лампу .. но она УЖЕ может быть включена вторым датчиком .. нет? Кем-то ишо? :)
Соответственно, если после 131 строки с попыткой перехода поставить проверку на текущую яркость лампы .. и если мы тут обнаруживаем что она включена .. то эта лампа и будет той самой "точкой отсчета" при последующем выключении. Нет? :)
А если да, то что надо сделать в этом случае?
P.S. И заметьте, что при обработке алгоритма второго датчика произойдет "то же самое" .. он тоже обнаружит что лампа "уже включена".. сам.
Пока оставим так как есть!:)
Вот нашел еще косячек!
Сработали оба датчика, включили, все в норме. Но стоит сработать какому либо одному датчику(когда считаем паузу) после паузы, тухнет только одна лампа, первая, в зависимости от того какой датчик сработал!
И потом 5 ламп горят(ну тут понятно, горят то 5, а не шесть, соответственно паузу считать мы не можем), до того как не сработает какой нибудь датчик!
Вроде понятно пояснил:)
Вроде бы не должно быть такого косячка. Когда датчики отработали, управлялки установлены в step=-1, и последний сработавший датчик перезапустит паузу. Во время неё, исполняется код в цикле по очереди для обоих датчиков, строки: 116 (проверка датчиков), 123 - "мимо", ждем выключения ИЛИ (далее) 125 - "ок", будем выключать И 126 - "мимо", пауза ещё НЕ завершена. Всё.
Если один из дачиков в этом наборе сработает (строка 116), то он переведет себя на режим включения ламп, и далее сразу же (в этом же проходе цикла) сработает строка 123 и сразу далее строка 129 тоже сработает (лампы - горят) и сразу сработает переключение на следующую лампу, строка 131. Это всё за один проход цикла, как только обнаружено срабатывание. Далее, если пауза так и не успеет отработать, за каждый следующий вызов loop(), сработавший датчик будет переходить к следующей лампе, пока не переберет все, строкой 131. Псоле чего, отработает строка 132 и он перезапустит паузу заново, перейдя в режим выключения. То есть, если в прочессе пробежки в попытках включить лампу пауза не успела сработать для второго датчика, то никаких "косяков" вы не сможете заметить .. только лампы будут гореть ещё туже самую паузу.
Проверить можно так: запустили оба процесса "практически" одновременно - лампы должны загораться с обоих концов. С момента включения последней лампы засекаете время ожидания выключения и пока оно не завершено - запускаете один из датчиков повторно. Он "пробежится" ну, очень быстро и соответственно, с момента повторного срабатывания должна отработать пауза ещё раз и оба канал погаснуть со своих концов к середине. Так?
Если в процессе "пробежки" сработавшего датчика по горящим лампам, пауза успеет завершиться, то второй датчик должен начать гасить лампы со своего конца, в то время как сработавший будет пытаться их включать .. первая же лампа, на которой они пересекуться .. будет включаться и выключаться попеременно и наш алгоритм "зависнет" (-1 +1) в "борьбе за лампу". Вот это - косяк. Потому как процесс "завершиться" не может. :)
Перечитал. Похоже этот вариант косяка Вы и наблюдаете. Надо подумать как это обойти, есть несколько вариантов..
Это как раз и есть "Битва за лампу"
:)
это может быть на всех лампах, если они втретяться!
Да, надо добавить блокировку одновременного включения и выключения одной и той же лампы разными датчиками. Способов несколько:
1. Активизация цикла включения ламп может останавливать выключение вторым процессом. После строки 120 последней версии "вот он рабочий скетч" добавить проверку:
В этом случае, сработавший датчик останавливает процесс выключения от второго датчика. Недостаток: по истечению новой паузы лампы будут выключаться только этим процессом. Но, если в процессе ожидания лампы снова сработает какой-либо датчик, то он потом и будет всё выключать .. может и "сойдет" .. решать вам.
2. Процесс включения важнее процесса выключения, и можно в выключающую ветку вставить контроль "пересечения процессов" для остановки процесса выключения. Для этого надо менять строку 140:
И соответственно добавить } перед строкой 150.
3. Можно не трогать процесс выключения, а всего лишь запретить паузу .. по истечении которой он продолжит свое выключение с той лампы, где стопорнулся. Для этого после строки 120 можно добавить типа так:
, где 5000 - время вашей паузы. Такая установка гарантировано запретит процесс выключения и повторно сработавший датчик успеет все повключать и снова переставит паузу куда надо. По истечению которой оба процесса продолжат выключение. повторно сработавший "с начала", а тормознутый с того места где прервался.. может так будет прикольней, не знаю .. решать вам.
.. и ещё несколько вариаций. :)
Пока воспользовался 1 вариантом! Вроде норма! Но на макете уже не понятно что да как, начал монтаж "Царской дороги" :)
Буду добивать на месте, с ноута потом ;)
Ну, я тоже так решил, что первый вариант самый простой и логически верный. Если в процессе ожидания что-то сработало, то логику второго датчика надо отключать .. не факт, что он тоже позже не сработает ещё раз.
С Вас "окончательный" скетч в сборе, может кому и понадобится. :)
Вот только когда сработали оба датчика, включение происходит как хотел, а вот выключение с одного края!(Край я так понял зависит от того, какой датчик передал сигнал последним)
Ну так первый вариант это и предполагает: повторное включение датчика во время ожидания паузы .. выключает из процесса второй датчик, дабы не драться "за лампу". Соответственно он уже "ничего не выкелючит" после новой паузы. :)
Третий вариант в этом плане интересней, поскольку он не выключает, а только откладывает выключение вторым датчиком на новую паузу .. но к нему будут точно такие же придирки, только "наоборот": прошли "туда и обратно" (сработали ОБА датчика) и тут, внезапно пошел народ "гуськом" с одной стороны (несколько срабатываний во время паузы одного и того же датчика) .. про второй датчик уже и забылось .. прошла наконец-то длинная пауза и пошло выключение .. с обоих сторон. Нафига?!? :)
"Лучшее - враг хорошего". В том смысле, что ни один из способов исключения "драк за лампу" не оптимален для всех случаев жизни .. на чем-то надо и остановиться. Да и с двумя датчиками, там у вас и иные "эффекты" будут .. в частности:
"вошел - включилось, постоял внутри .. упс, пошло выключение"
"вошел - включилось, прошел - на выходе сработал .. второй датчик .. и упс. выключение пошло от него, а не от первого .. или от ОБОИХ"
и т.д. :)
Да, надо помозговать! :)
Потестил, вообщем так:
Пошли, сработал 1 датчик, включил все, пауза пошла, прошли 2 датчик(во время паузы) после паузы, выключение идет не с того края как должно! Не есть хорошо:(
Да, как то что то не то:(
"вошел - включилось, постоял внутри .. упс, пошло выключение"
Для этого и есть пауза! она будет минуты 3 я так думаю!
А если долго надо, будет обычный выключатель!
Но это особо и не надо, это больше для красоты, чем для освещения! Но видно будет куды ступать, и хорошо!:)
Может это обойти так?
Прошли первый, включилось если ВСЁ, то 2 датчик ТОЛЬКО продливает паузу(зачем нам что то включать, уже все горит, от своего датчика, пусть и горит дальше себе), не включает ничего!(так можно вообще?)
А вот если не все включилось еще, то включать со своей стороны!(Но я думаю редкое явление, не такое у меня тут движение:))
И во время паузы, ни чего не проверять, не включать, а только продливать паузу!
Но и тут 1000% будут косяки, я их просто не вижу:(
Я же предлагал Вам в самом начале "игнорировать" второй датчик на конец прохода того, кто "задел" первый .. иначе на выходе как раз получите именно этот эффект .. но! Если его игнорировать то .. а вдруг это и не выход из под второго датчика, а вход нового, как "отличить"? .. у вас там таких "коллизий" вагон и маленькая тележка .. расслабьтесь. С только 2-я датчиками движения можно оставить "как есть", ибо попытки избежать коллизии одного вида неизбежно приведут к друцгим. :)
Да я понимаю, что вагон, но хотя-бы чуть до ума бы довести :(
В таком разе, поперву сформулируйте ваше "до ума" ясно, четко .. в виде некоего автомата, лучше в ДРАКОН-схеме. Тогда вам станет совершенно понятно что и куда надо будет поправить в этом скетче. А так .. гадать можно до бесконечности.
Так вопрос так и остался открытым, так вообще возможно или нет!
Когда идет пауза, только продливать паузу, а не проходить по лампам?
(У нас же получается что мы пробегаем всю ветку, и приходим опять к паузе. Правильно?)
Это я думаю решит проблему! Или нет?
Пораскинул мозгами, потестил, все возможные варианты прохода датчиков (инопланетное вторжение не учел:)) думаю все таки это поможет!
лучше в ДРАКОН-схеме
Разрисовал уж целый блокнот :)
Что то просто не получается учесть, если не делать тесты!
Можно и не пробегать. Просто предварительно проверять условие "ещё идет пауза?" .. но какой в этом специальный смысл? Пробежка по лампам позволяет нам удостовериться что они все включены и производится достаточно быстро.. очень быстро, а самое главное "прозрачно" для контроля датчиков.
На том сайте, что я Вам указывал есть несколько программ-редакторов ДРАКОН-схем. Есть платные с месяцем бесплатного пользования (ИС ДРАКОН) есть и бесплатные. Они заодно ещё и проверяют вашу схему на корректность, а то и вовсе не позволяют писать криво. Кроме того, там есть "кодогенерация" по схеме .. больше конечно ручная, но позволяет тем не менее получать вполне приемлемый код скетчей.
ну так если идет пауза, они и так включены! Тогда датчики перестанут руководить лампами, на время паузы, а будут только продливать паузу! (по логике мыслю! :)) !?
Можно и не пробегать. Просто предварительно проверять условие "ещё идет пауза?" .. но какой в этом специальный смысл?
Этим мы и добьемся того что лампы не будут менять направление, так как мы будем менять только паузу!
Еще не разобрался в программе, но что то типо так!
Бред конечно составил :(
Так вроде логичнее!
Там есть кнопочка "проверить схему" - пользовались? Левых обратных стрелок (у Вас первая по схеме) быть не может согласно правилам. Это конечно же "не та схема".. давайте вечерком выложу свою.
Да я понимаю(надо не стрелку, а просто обойти датчик 1 в этой ветке), пока не разобрался еще! Пользовался проверкой, но видимо еще не понял что куда там, вечно пишет что должен быть "хотя бы один выход", а зачем он мне, если этот цикл бесконечный?
в голове оно как то проще :)
Вот я как думаю;
1) датчик сработал, все включил(запомнили что и кто включил и от куда), пошла пауза
2) пауза - опять движение - пауза ++
3) двежуха закончилась, гости свалили :)
прошла пауза(мы же помним что и кто и откуда включал ) вот и выключаем согласно самой первой сработки датчика(ов)
Не могу открыть ИС Дракон, похоже триальный период кончился .. ладно, давайте по вашей схеме из #241:
1. Вообще-то выход у Вас есть, поскольку это loop() вызывается бесконечно, а сам он очень даже конечен. Ну да ладно, пока можно и так.
2. Ветка "Датчик света" .. с чего это она у вас замыкается "сама на себя"? Она должна указывать вниз на маркер "Датчик света" .. и ветвление надо поменять местами, ибо "царская дорога" - прямая линия. После смены условия, выбор "нет" окажется справа и тоже должен уходить вниз схемы на маркер "Датчик1"
3. Ветка "Датчик1" .. какова его "Царская дорога"? Да и вообще, что он делает? Он ведь если НЕ сработал, то НЕ делает ничего .. то есть уходит на "Датчик2", а если сработал .. то только устанавливает режим включения ламп присваивая переменные .. и только. А стало быть когда "да", то есть одна, простая икона "Действие" с присвоением значений и .. маркер отсутствующей ветки "Включение".
4. Ветка "Включение" - вовсе не в хвосте действий датчика1, а самостоятельная ветка. И она у вас отрабатывает ровно 1 раз за 1 вызов loop() увеличивая яркость текущей лампы на ".step"
.. и т.д.
В целом, тут надо было применить не "Силуэт" а "Конечный автомат" .. но давайте уже на этом варианте доделаем.
Ну я так понимаю, что должно быть на много больше веток!?
1.датчик света
2.датчик 1
3.датчик 2
4.включение
5.выключение
6.пауза
Как минимум, хотя может я и ошибаюсь!
Кстати я ИС Дракон что то не понял вообще! :(
Эта программка мне больше понравилась, и вроде бесплатная! ;)
Да не проблема, кинуть автору денег. Он того заслуживает, да и дитё юзает.. Просто как обычно: "зима снова наступила неожиданно". :)
а сколько стоит? я что то не нашел!
Я на правильном пути?
Стоит в пределах 500руб. :)
Да, примерно так и должно быть. Сравните с кодом: если первый датчик не сработал, то по сути цикл по датчикам - завершается и переходим ко второму датчику. Давайте я завтра проплачу эти большие деньги и таки сделаю. "ИС Дракон" сразу "не позволяет писать криво" в отличии от Drakon-Editor, который по сути просто рисовалка произвольных схем.