код - можно ли проще?

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Спасибо!

малость понятно, но еще не совсем

#define OutLED(a) PORTD=a

это зачем, куда и почему?

Я уж привык к своему коду, и смотрю на ваш, как баран на те ворота)))))

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Tomasina пишет:

ну вот, пришел Logik и все опошлил битовыми операциями. Теперь точно никто не сможет разобраться в скетче :)

Не, ну первые 8 строк я понял)))))

Logik
Offline
Зарегистрирован: 05.08.2014

SOCHINEC пишет:

Спасибо!

малость понятно, но еще не совсем

#define OutLED(a) PORTD=a

это зачем, куда и почему?

Я уж привык к своему коду, и смотрю на ваш, как баран на те ворота)))))

Это прямой вывод в порт, чтоб не выводить каждый битик, выводим сразу байтом. 

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

SOCHINEC пишет:

#define fadePin1 10 //пин управления MOSFET транзистором

#define fadePin2 9 //пин управления MOSFET транзистором

#define fadePin3 6 //пин управления MOSFET транзистором



int calibrationTime = 30; //Время калибровки датчика (10-60 сек. по даташиту)

int pirPin1 = 2; //пин подключения управляющего сигнала PIR датчика1

int pirPin2 = 4; //пин подключения управляющего сигнала PIR датчика2



int light; //переменная для хранения состояния света (вкл/выкл)

void setup(){

Serial.begin(9600);

pinMode(pirPin1, INPUT); //настариваем 2 пин как вход для сигналов с датчика

pinMode(pirPin2, INPUT); //настариваем 4 пин как вход для сигналов с датчика

pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором

pinMode(fadePin2, OUTPUT);

pinMode(fadePin3, OUTPUT);

light = 0; //устанаваливаем переменную для первого включения света



 Serial.print("Calibrating"); //дадим датчику время на калибровку

 for(int i = 0; i < calibrationTime; i++)

{

 Serial.print(".");
 delay(1000);

}

 Serial.println(" done");
 Serial.println("SENSOR ACTIVE");
 delay(50);

}
uint8_t fades[] = {fadePin1, fadePin2, fadePin3};

int       isGo = 0; // порядок включения ламп

void fadeLED(boolean state, int is_go)
{
  int       num=0, max=0;

  if( is_go == 1 ){ num=0; max=3; }
  if( is_go == -1){ num=2; max=-1; }

  while( num != max ){
    for(int i = 255*(1-state); state ? i<=255 : i>=0; state ? i++ : i--)
    {
      analogWrite(fades[num], i);
      Serial.println(i); // передаем данные в порт
      delay(10);
    }
    num += is_go;
  }
}

void loop()
{
  if( ! light ) // сначала проверяем это!
  {
    if( digitalRead(pirPin1) ){ isGo = 1; }
    if( digitalRead(pirPin2) ){ isGo = -1; }

    fadeLED( HIGH, isGo ); // включаем лампЫ

    delay(5000);
    light = 1;
//    isGo = -isGo; // это если надо выключать в обратном порядке.

  } else {

    fadeLED( LOW, isGo );

    light = 0;
    isGo = 0;
  }
}

работает, как и хотел! Спасибо! Вот только одно НО, после выключения, какая то задержка что ли, датчики не реагируют вообще секунд 5-7( почему?

Вернемся чуть назад!  все-таки дело видимо в скетче, не датчики тут виноваты! Заливаю верхний, отклик после 5-7 сек, заливаю этот

#define fadePin1 10 //пин управления MOSFET транзистором

#define fadePin2 9 //пин управления MOSFET транзистором

#define fadePin3 6 //пин управления MOSFET транзистором



int calibrationTime = 30; //Время калибровки датчика (10-60 сек. по даташиту)

int pirPin1 = 2; //пин подключения управляющего сигнала PIR датчика1

int pirPin2 = 4; //пин подключения управляющего сигнала PIR датчика2



int light; //переменная для хранения состояния света (вкл/выкл)

void setup(){

Serial.begin(9600);

pinMode(pirPin1, INPUT); //настариваем 2 пин как вход для сигналов с датчика

pinMode(pirPin2, INPUT); //настариваем 4 пин как вход для сигналов с датчика

pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором

pinMode(fadePin2, OUTPUT);

pinMode(fadePin3, OUTPUT);

light = 0; //устанаваливаем переменную для первого включения света



 Serial.print("Calibrating"); //дадим датчику время на калибровку

 for(int i = 0; i < calibrationTime; i++)

{

 Serial.print(".");
 delay(1000);

}

 Serial.println(" done");
 Serial.println("SENSOR ACTIVE");
 delay(50);

}

void fadeLED(byte pin, boolean state)

{for(int i = 255*(1-state); state ? i<=255 : i>=0; state ? i++ : i--)

{
 analogWrite(pin, i);
 Serial.println(i); // передаем данные в порт
 delay(10);
 }
}
void loop()
{

if(digitalRead(pirPin1)) // если есть движение
 { if(!light) // и если свет не был включен

 { fadeLED(fadePin1, HIGH);

   fadeLED(fadePin2, HIGH);

   fadeLED(fadePin3, HIGH);

  } // включаем по очереди

  delay(5000); // пауза после полного открытия всех транзисторов
  light = 1; // передаем значение переменной, что свет включен
}
if(digitalRead(pirPin2)) // если есть движение
 { if(!light) // и если свет не был включен

 { fadeLED(fadePin3, HIGH);

   fadeLED(fadePin2, HIGH);

   fadeLED(fadePin1, HIGH);

  } // включаем по очереди

  delay(5000); // пауза после полного открытия всех транзисторов
  light = 1; // передаем значение переменной, что свет включен
}
 

else // иначе
 {
   if(light) // и если свет включен
  { 
   fadeLED(fadePin1, LOW);

   fadeLED(fadePin2, LOW);

   fadeLED(fadePin3, LOW);

   } // выключаем по очереди

light = 0; // передаем значение переменной, что свет выключен
  }
} 

Все работает сразу, ни какой задержки! Почему так происходит?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Задержка должна отрабатывать в обоих случаях. Она там у вас прописана в delay(5000) - 5сек "как с куста". Пока этот оператор выполняется - МК просто тупит и ни на что не реагирует. Мы с этим ещё разберемся чуть позже.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Кстати, Logik вам предложил несколько иной алгоритм и в нем есть свои особенности, смотрите откомментирую:

byte LeftLED=0;
byte RigthLED=0;
int OldTime;
#define TIME_WAVE 5000  //5 sec
#define Fotodiod digitalRead(8)
#define PIR_left digitalRead(9)
#define PIR_rigth digitalRead(10)
#define OutLED(a) PORTD=a

void loop(void)
{
  int Time=millis();                       // Заходя каждый раз сюда - запоминаем время захода (мсек.)

  if(LeftLED || RigthLED)                  // чтото светит, датчик света не интересен - он блоке else! даже не смотрим!
  {
    if(Time-OldTime>TIME_WAVE)             // таймер сработал - прошла фикс. пауза (TIME_WAVE) с прошлого захода внутрь)
    {
      OldTime=Time;                        // фиксируем время захода для отсчета следующей паузы
      
      if(LeftLED==0xff)                           // светится все
        LeftLED=0x7f;                             // .. выключаем старший бит (предположительно левую лампу - см. соединения!)
      else                                        // не всё (где-то бит уже выключен!): 
        LeftLED=(LeftLED>>1) | (LeftLED & 0x80);  // .. сдвигаем картинку вправо и добавляем включение крайнего левого бита

      if(RigthLED==0xff)                          //светится все (аналогично, только справа-налево. ничего тут НЕ тушим - просто бегаем справа-налево!)
        RigthLED=0xfe;                            // тушим первую (правую)
      else
        RigthLED=(RigthLED<<1) | (RigthLED & 1); //сдвигаем с заполнением нового разряда старым значением (нет заполняем 1 - включаем)
    }
  }
  else                                           //ничего не светится, проверяем датчик света И ТОЛЬКО КОГДА НИЧЕГО НЕ СВЕТИТСЯ!
    if(Fotodiod) //светло
      return;

//-- этот блок работает независимо от предыдущего:
  
  if(!LeftLED)   //слева не стартовали
    if(PIR_left) //проверим левый датчик
    {
      LeftLED=0x80; //старт слева
      OldTime=Time; //таймер актуализируем бесполезно, если не установлено в setup()! назаданное значение ==0, но тут даже не важно.
    }
    
  if(!RigthLED)
    if(PIR_rigth)
    {
      RigthLED=1;
      OldTime=Time;
    }
    
   OutLED(RigthLED | LeftLED); // включаем всё что накрутили и сразу и мгновенно.
}

Отличия:

1. Скетч работает с цифровым выводом, а не ШИМ. То есть яркость ламп устанавливается мгновенно, а не плавно.

2. Скетч работает с байтом, предполагая поключение реле ламп строго по месту: левый (старший бит) байта порта управления должен соответствовать крайней левой лампе и тд. Младший бит - крайней правой. Не у всех Ардуин и далеко не все пины расположены "подряд" от одного регистра-порта вывода .. смотреть даташит на вашу дуньку и её распиновку тщательно. Впрочем, у вас похоже УНО - там кажется такие есть.

3. Бит, у которого стоит 0 - лампа выключена. И такой - один на каждый датчик. То есть, как только датчик сработал, программа будет "крутить" - выключать по одной лампе "по кругу", оставляя остальные включенными постоянно. Если сработал второй датчик, то ещё одна лампа будет бегать в обратном направлении.

4. Заданная пауза - это "скорость" переключения ламп - скорость кругового бега.

5. Однажды сработавший датчик запустит процесс, а код его остановки тут отсутствует "напрочь". То есть выключать лампы тут - банально нечем.

6. Если процесс мигания вкруговую запущен, то датчик освещенности - уже не играет роли и НЕ проверяется вовсе, ибо стоит в блоке else.

Как интересное решение - полезно. Может вам понравится. Заодно освоите один простой момент: все пины соттветствуют какому-то регистру вывода и собраны побайтно .. но разбросаны по ногам платы .. :)

Но, мне кажется что ваше ТЗ было вовсе иным.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Да, ещё немаловажный момент: скетч рассчитан из предположения ровно 8 ламп. Если ламп меньше (у вас кажется 6), то будет пауза на время переключения несуществующих ламп, в течение которой все имеющиеся лампы будут гореть одновременно.

Logik
Offline
Зарегистрирован: 05.08.2014

В общем, описали верно.

Если нужно гасить все - обнуляем LeftLED и RigthLED.

Если меньше 8 ламп правим условия if(LeftLED==0xff) на if(LeftLED==0xfс) (для 6-и) и  аналогично RigthLED для.

ШИМ и произвольный порядок пинов - развиваем OutLED в функцию делающую нужное.

Кстати можно исключить горение нескольких ламп, т.е. горит одна сопровождающая движущегося, тогда из LeftLED=(LeftLED>>1) | (LeftLED & 0x80); делаем LeftLED=(LeftLED>>1) условия if(LeftLED==0xff) на if(LeftLED==0x04) (для 6-и) . И   аналогично RigthLED.

Аналогично делается горение нескольких (2-3 ламп) сопровождающих движущегося.

 В общем есть простор для творчества.

vde69
Offline
Зарегистрирован: 10.01.2016

Tomasina пишет:

ну вот, пришел Logik и все опошлил битовыми операциями. Теперь точно никто не сможет разобраться в скетче :)

Зря Вы так :) вообще битовые операции самое то, я даже банальное сложение чисел иногда на них делаю :) сейчас то-же увлекся  переписанием своего протокола под битовые операции, тем самым сократил заголовок хедера на 3 байта (с 11 до 8), то есть скорость  малых пакетов возрасла почти на 20%....

То же самое и с внутренним массивом, нужно мне  запомнить состояния 255 устройств, с битовыми операциями я обошелся в 32 байта ОЗУ

Битовые операции - самые быстрые (большенство занимает 1 такт, правда это не не включая пересылку в регистр). Единственное чего я в себе не как не могу побороть - это излишества скобок при работе с ними, да я знаю про приоритеты выполнения, но все равно ставлю скобки...

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Logik, перечитайте то ТЗ, которое составлено и утверждено вместе с автором темы. Оно - иное, и цель там другая. Ваш код безусловно интересен как знакомство с битовыми операциями и неблокирующей работой интервальных автоматов .. но тут задача пока несколько иная. И первая часть задачи - построить верный алгоритм, а не код программы.

Кодировать программу по готовому и правильному алгоритму, можно даже в сильно нетрезвом виде и даже вовсе мало что смысля в конкретном языке, тупо смотря похожие примеры и выдирая из них готовые куски. А вот составить алгоритм, в точности соответствующий задаче - это и есть ПРОГРАММИРОВАНИЕ. И конкретный язык или реализация - тут вовсе не при чем.

Пока автор осваивает эту часть - алгоритмирование. :)

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Arhat109-2 пишет:

Задержка должна отрабатывать в обоих случаях. Она там у вас прописана в delay(5000) - 5сек "как с куста". Пока этот оператор выполняется - МК просто тупит и ни на что не реагирует. Мы с этим ещё разберемся чуть позже.

Так она же прописана между включить и выключить, а не перед (движение-включить) а она то как раз там и появляется(

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Как-то странно. Задержка в ОБОИХ скетчах прописана в одном и том же месте: сразу после включения ламп. В этой части между ними никакой разницы нет. То есть должно быть так: сработал датчик - пошли загораться лампы, зажглись - ждем 5 сек и после этого лампы выключаются. Никакой разницы.

Разница проявляется только в порядке обработки датчиков: в первом скетче они опрашиваются практически одновременно и сразу запускается процесс включения-задержки, а после задержки, при следующем вхождении в loop(), начинается процесс выключения ламп БЕЗ опроса датчиков, но и без задержек. Но пока идет выключение - тоже ничего не опрашивается.

, а во втором сначала опрашивается один .. и если ОН сработал, то начинается его процесс включения - задержки, и только потом опрашивается второй датчик и если он сработал - то начинается его процесс включения-задержки. А процесс выключения начинается ТОЛЬКО в случае НЕсрабатывания второго датчика (его блок else!).

Время на включение/выключение: 10мсек * 256 * 3 = 2.56 * 3 = 7.5секунд. Это то время, в течение которого оба варианта тупят и тоже ничего не делают как и при delay(5сек). Возможно что Вы обнаруживаете эту задержку.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

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

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Logik пишет:

SOCHINEC пишет:

Спасибо!

малость понятно, но еще не совсем

#define OutLED(a) PORTD=a

это зачем, куда и почему?

Я уж привык к своему коду, и смотрю на ваш, как баран на те ворота)))))

Это прямой вывод в порт, чтоб не выводить каждый битик, выводим сразу байтом. 

Порт - это пины ардуино по порядку, так как они есть(D2,D3,D4 и т.д) я правилно понял?

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Я так думаю эта задержка связана как раз с опросом двух датчиков по отдельности! Какое то время все таки нужно для вычислений этого!?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Практически нет. Опрос датчиков визуально проходит практически мгновенно: просто МК смотрит есть на входе лог. 1 или там лог.0 и всё. Времени на этот процесс затрачивается в несколько микросекунд.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Порт - это внутренний регистр ввода-вывода (смотря какой), где собрано 8 ножек. К нумерации ножек платы имеет практически никакое соотношение, что и представляет собой определенное неудобство в програмировании. Как было удобно - так и развели.

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Ну так понятнее)

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Arhat109-2 пишет:

Пока автор осваивает эту часть - алгоритмирование. :)

Вот тут прям у точку!:)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Давайте вернемся к нашему алгоритму. Предлагаю начать с включения-выключения ламп "по 1шт за 1 вызов loop()"

У вас есть функция fadeLed() которая делает процесс плавным, но при этом несколько "тупит". Давайте поправим её так, чтобы в этом процессе устранить delay(), хоть он и краток (но его много раз дергаем)..


// у нас был список ножек ламп .. добавляем к нему список текущих яркостей, и для этого опишем структуру "лампа"
typedef struct{
  uint8_t pin;
  uint8_t bright;
} Led;

// теперь создадим список ламп, заодно и введем константу "всего ламп"
#define MAX_LED 3
Led      fades[MAX_LED] = {{fadePin1, 0}, {fadePin2, 0}, {fadePin3, 0}};

// Функцию изменим так, чтобы она получала номер лампы и направление включать-выключать
// @param state: +1 -- включение; -1 -- выключение
// сразу формируем указатель на текущую лампу, это лучше чем смотреть в массив каждый раз
// как и положено, функция ничего не проверяет. Верный вызов - проблема вызывающего!
void fadeLED(uint8_t lamp, uint8_t state)
{
  Led * ptr = &(fades[lamp]);

  ptr->bright += state;
  analogWrite( ptr->pin, ptr->bright);
  Serial.println(i); // передаем данные в порт
}

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

вопрос: Как теперь вызывать "это чудо"? :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ваши предложения?

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Arhat109-2, прокомментируйте строки 17-20, для нас это джунгли :) Зачем нужно было водить структуру?

vde69
Offline
Зарегистрирован: 10.01.2016

Tomasina пишет:

Arhat109-2, прокомментируйте строки 17-20, для нас это джунгли :) Зачем нужно было водить структуру?

я строчку 17 понимаю как некий трюк позволяющий обращатся к одним данным используя разные типы без приведения типов, что-то похожее на record в паскале, хотя может я и не прав совсем :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Структура типа Led описывает каждую лампу как явление из 2-х сущностей: номера управляющего пина и текущего уровня яркости свечения (ШИМ). Это необходимо, чтобы отвязать код, управляющий яркостью от "цикла включения" в виде оператора for. Цикл - пробегал все значения яркости "за раз", и для достижения требуемой плавности в него вводится задержка. Небольшая на каждый шаг, но вполне ощутимая в "итого": 2.56сек на каждую лампу.

Введя структуру, теперь можно помнить состояние ШИМ (яркости) между вызовами функции, и тем самым оставить функции задачу однократного изменения яркости, а "цикл плавного изменения" вынести наружу, и связать его с вызовами loop(): на каждый вызов loop() делаем ровно один шаг изменения яроксти (если это требуется).

Строки 17-20 как раз и делают такой шаг 1 изменения ШИМ:

17 - вычисляем место хранения структуры для заданной лампы lamp. Это чтобы далее в коде не указывать "fades[lamp]." Можно и не вводить, в таком простом коде компилятор и сам это сделает за вас ..

19 - поле структуры "яркость" изменяем на величину заданного шага: +1 - яркость увеличивается; -1 - уменьшается.

20 - собственно изменяем яркость на том пине, номер которого указан в поле pin структуры, на то значение, которое только что изменили.

Просто записи fades[lamp].pin и ptr->pin эквиваленты. Если мы обращаемся к полю структуры через указатель, то используем ->, а если по имени элемента/объекта, то "." .. не думаю что это непонятно: описание языка и только.

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

строка 17 читается так: заведи временную (регистровую) переменную, которая есть адрес структуры типа Led И запиши в него АДРЕС начала элемента массива с номером lamp.

То есть тип данных указателя указан ЯВНО: Led * == "указатель на Led" (а не куда попало). Куда попало будет "void *" :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Компилятор в любом случае, формирует такой регистровый указатель. Он по иному ваще не умеет адресовать ячейки массивов в памяти .. (вычисляемые места хранения). Просто, если везде указывать fades[lamp].XXX то момент формирования указателя будет выбран компилятором .. и возможно что не единожды, а перед КАЖДЫМ оператором, что может оказаться дорого (в среднем 10-14байт кода на каждый раз).

А так, мы ему явно сообщаем, что заведи 1 раз и пользуйся. И "будь добр" не потерять его, он тебе пригодится более чем в одном операторе.. :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Продолжаем? Так как можно вызвать теперь эту функцию из loop() чтобы лампа включалась-выключалась по 1 шагу на вызов? :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Хорошо. Если вызывать так, что будет?


void loop()
{
  if(state == 1 && fades[lamp].bright<255) fadeLed(lamp, state);
}

Сколько раз надо зайти в loop() чтобы увеличить яркость с 0 до 255? :)

А если предварительно напишем так:

void loop()
{
  if( digitalRead(pirPin) == 1) { ...}

  if(state == 1 && fades[lamp].bright<255) fadeLed(lamp, state);
}

то будет ли опрашиваться датчик "одновременно" с изменением яркости? Не это ли нам и требуется? :)

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Arhat109-2, delay() выкинул, добавляй millis() иначе глазом не успеешь моргнуть, как яркость увеличится с нуля до максимума.

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Оёёй, пока пытаюсь вникнуть!)))

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

конечно жеж. 16Мгц - это ну очень быстро. Поэтому вызывать такую функцию внутри loop() надо "не часто", а согласно той самой задержке в 10 миллисекунд. Давайте её и заведем:

typedef struct{
  uint8_t pin;
  uint8_t bright;
} Led;

#define MAX_LED 3
Led      fades[MAX_LED] = {{fadePin1, 0}, {fadePin2, 0}, {fadePin3, 0}};

// Функция изменения яркости на 1 шаг state за 1 вызов
// @param state: +1 -- включение; -1 -- выключение
void fadeLED(uint8_t lamp, uint8_t state)
{
  Led * ptr = &(fades[lamp]);                           // врем. лок. указатель на структуру "лампа"

  ptr->bright += state;                                     // изменяем яркость
  analogWrite( ptr->pin, ptr->bright); // устанавливаем на выходе
  Serial.println(i); // передаем данные в порт для отладки
}

#define WAIT_1  10      // 10мсек - пауза между изменениями яркости
uint32_t startedAt = 0; // тут будем хранить время последнего запуска

void loop()
{
  // при каждом входе в loop() проверяем датчики и можем делать что-то ещё
  if( digitalRead(pirPin1)==1 ){ ...}
  ...
  // а тут изменяем яркость лампы с номером lamp:
  if(
          millis() - startedAt >= WAIT_1         // пора изменять яркость?
     && (
        (state==1 && fades[lamp].bright < 255)   // включаем И есть куда?
        ||
        (state==-1 && fades[lamp].bright > 0)    // или вЫключаем И есть куда?
      )
  ){
      startedAt = millis(); // новое время для отсчета следующей паузы
      fadeLed(lamp, state); // изменяем яркость на state.
  }
}

Сложный набор условий расписал так, чтобы было понятней.

Собственно первое условие в этом IF определяется интервалом WAIT_1. И пока не пройдет времени больше чем в нем указано, дальнейшие проверки выполняться НЕ будут. Он установлен в 10мсек. соответственно, яркость ламп изменяется не быстрее чем раз в 10 миллисекунд. Что и требовалось. Или нет? :)

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

мозголомы...

Araris
Offline
Зарегистрирован: 09.11.2012

Tomasina пишет:

мозголомы...

Ну что Вы, как раз сообразно названию темы всё ))).

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Нет. Просто решается уже несколько иная задача: создание полноценного скетча по поставленному ТЗ. Как понимаю, автор собирается это реализовать на своей улице. Надо чтобы оно не только "как-то" работало, а хорошо работало И было понятно автору. Постепенно.. осваиваем приемы программирования.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Продолжаем.

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

Можно попробовать объединить в один скетч то что получается:

#define fadePin1 10 //пин управления MOSFET транзистором
#define fadePin2 9 //пин управления MOSFET транзистором
#define fadePin3 6 //пин управления MOSFET транзистором

int calibrationTime = 30; //Время калибровки датчика (10-60 сек. по даташиту)

int pirPin1 = 2; //пин подключения управляющего сигнала PIR датчика1
int pirPin2 = 4; //пин подключения управляющего сигнала PIR датчика2

int light; //переменная для хранения состояния света (вкл/выкл)

void setup()
{
  Serial.begin(9600);
  pinMode(pirPin1, INPUT); //настариваем 2 пин как вход для сигналов с датчика
  pinMode(pirPin2, INPUT); //настариваем 4 пин как вход для сигналов с датчика
  pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором
  pinMode(fadePin2, OUTPUT);
  pinMode(fadePin3, OUTPUT);

  light = 0; //устанаваливаем переменную для первого включения света

  Serial.print("Calibrating"); //дадим датчику время на калибровку
  for(int i = 0; i < calibrationTime; i++)
  {
    Serial.print(".");
    delay(1000);
  }
  Serial.println(" done");
  Serial.println("SENSOR ACTIVE");
  delay(50);
}

// структура - описание понятия "Лампа" - это пин и текущая яркость:
typedef struct{
  uint8_t pin;
  uint8_t bright;
} Led;

// теперь создадим список ламп, заодно и введем константу "всего ламп"
#define MAX_LED 3
Led  fades[MAX_LED] = {{fadePin1, 0}, {fadePin2, 0}, {fadePin3, 0}};

#define WAIT_1  10      // 10мсек - пауза между изменениями яркости
uint32_t startedAt = 0; // тут будем хранить время последнего запуска fadeLed
#define WAIT_PAUSE = 5000
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;  // последний номер режимов правого датчика

/**
 * Функция изменения яркости на 1 шаг state РАЗ в 10 миллисекунд
 * @param state: +1 -- включение; -1 -- выключение
 */
void fadeLED(uint8_t lamp, uint8_t state)
{
  Led * ptr = &(fades[lamp]);  // врем. лок. указатель на структуру "лампа"

  if(
          millis() - startedAt >= WAIT_1  // пора изменять яркость?
     && (
        (state==1 && ptr->bright < 255)   // включаем И есть куда?
        ||
        (state==-1 && ptr->bright > 0)    // или вЫключаем И есть куда?
      )
  ){
      startedAt = millis();                // новое время для отсчета следующей паузы

      ptr->bright += state;                // изменяем яркость
      analogWrite( ptr->pin, ptr->bright); // устанавливаем на выходе
      Serial.println(i);                   // передаем данные в порт для отладки
  }
}

//========== loop() ========

void loop()
{
  // п.1. Если светло - выходим.
  if( isDayNow() ) return;

  // п.2: проверяем датчики движения и запускаем включение если надо:
  if( digitalRead(pirPin1) ){ isGo1 =  1; lamp1=0;         max1 = MAX_LED; }
  if( digitalRead(pirPin2) ){ isGo2 =  1; lamp1=MAX_LED-1; max1 = -1;      }

  // п.3. поштучно включаем (п.5 - выключаем) лампы, если левый датчик сработал (2-й датчик точно также можно ниже .. не показан):
  if(
        (isGo1 == 1) // если включаем лампы, то сразу
      || (
           (isGo1 == -1) // а вот если вЫключаем, то
           && (millis() - startedPause >= WAIT_PAUSE) // по истечению паузы
        )
  ){
    // 3.1. проверяем лампа уже горит? переходим к следующей:
    if( isGo1==1 && fades[lamp1].bright == 255 ){ lamp1++; }
    // 5.1. или лампа уже выключена? переходим к следующей:
    else if( isGo == -1 && fades[lamp1].bright == 0 ){ lamp--; }
    else{
      // 3.2. + 5.2 увеличиваем/уменьшаем яркость на 1 каждые 10мсек:
      fadeLED(lamp1, isGo);
    }
    // 3.3., 5.3 проверяем лампы кончились? включаем паузу:
    if( lamp1 == max1 ){
      if( isGo1 == 1){           // а мы лампы включали?
        startedPause = millis(); // .. время паузы "пошло".
        isGo1 = -1;              // .. после паузы будем выключать
        lamp1=MAX_LED-1;         // .. в обратном порядке
        max = -1;
      }else if( isGo == -1 ){    // нет, мы их выключали
        isGo = 0;                // .. ну и ладушки, всё погасло.
      }
    }
  }
}
Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Я вам даже прописал примерные номера икон согласно вашей ДРАКОН-схеме, если вы её конечно же отрисовали .. заметьте что п.3 и п.5 - включение и выключение отличаются "деталями". Поэтому я их объединил насколько это возможно.

Точно также можно объединить и работу двух дачтиков, поскольку она практически "идентична". А можно отдублировать ниже код для второго датчика п3-п.5.

функция isDayNow() тут отсутствует. Это проверка датчика освещенности. Для отладки пока нет самого датчика можно сделать заглушку типа uint8_t isDayNow(void){ return 0; }

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Arhat109-2 пишет:

 Постепенно.. осваиваем приемы программирования.

Ща такое ощущение, что я в (-)9 классе, как минимум :(

SOCHINEC
Offline
Зарегистрирован: 01.05.2016
&& (millis() - startedPause >= WAIT_PAUSE) // по истечению паузы

а вот тут рагается, есть еще кое где, но то вроде устранил?!

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

в строке 46 знак = не нужен.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ну, как обычно. При слиянии скетчей без проверочной компиляции остается много огрехов переименований и пр. ерунды. Будем считать, что найти все очепятки было "домашним заданием". :)

Вот вроде бы компилирующийся вариант:

#define fadePin1 10       // пин управления MOSFET транзистором
#define fadePin2  9       // пин управления MOSFET транзистором
#define fadePin3  6       // пин управления MOSFET транзистором

#define pirPin1 2         // пин подключения управляющего сигнала PIR датчика1
#define pirPin2 4         // пин подключения управляющего сигнала PIR датчика2

int calibrationTime = 30; // Время калибровки датчика (10-60 сек. по даташиту)

void setup()
{
  pinMode(pirPin1, INPUT);   // настариваем 2 пин как вход для сигналов с датчика
  pinMode(pirPin2, INPUT);   // настариваем 4 пин как вход для сигналов с датчика
  pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором
  pinMode(fadePin2, OUTPUT);
  pinMode(fadePin3, 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);
}

// структура - описание понятия "Лампа" - это пин и текущая яркость:
typedef struct{
  uint8_t pin;
  uint8_t bright;
} Led;

// теперь создадим список ламп, заодно и введем константу "всего ламп"
#define MAX_LED 3
Led  fades[MAX_LED] = {{fadePin1, 0}, {fadePin2, 0}, {fadePin3, 0}};

#define WAIT_1  10      // 10мсек - пауза между изменениями яркости
uint32_t startedAt = 0; // тут будем хранить время последнего запуска fadeLed
#define WAIT_PAUSE 5000
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 lamp, uint8_t state)
{
  Led * ptr = &(fades[lamp]);  // врем. лок. указатель на структуру "лампа"

  if(
          millis() - startedAt >= WAIT_1  // пора изменять яркость?
     && (
        (state==1 && ptr->bright < 255)   // включаем И есть куда?
        ||
        (state==-1 && ptr->bright > 0)    // или вЫключаем И есть куда?
      )
  ){
      startedAt = millis();                // новое время для отсчета следующей паузы

      ptr->bright += state;                // изменяем яркость
      analogWrite( ptr->pin, ptr->bright); // устанавливаем на выходе
      Serial.println(ptr->bright);         // передаем данные в порт для отладки
  }
}

//========== loop() ========

void loop()
{
  // п.1. Если светло - выходим.
  if( isDayNow() ) return;

  // п.2: проверяем датчики движения и запускаем включение если надо:
  if( digitalRead(pirPin1) ){ isGo1 =  1; lamp1=0;         max1 = MAX_LED; }
  if( digitalRead(pirPin2) ){ isGo2 =  1; lamp1=MAX_LED-1; max1 = -1;      }

  // п.3. поштучно включаем (п.5 - выключаем) лампы, если левый датчик сработал (2-й датчик точно также можно ниже .. не показан):
  if(
        (isGo1 == 1) // если включаем лампы, то сразу
      || (
           (isGo1 == -1) // а вот если вЫключаем, то
           && (millis() - startedPause >= WAIT_PAUSE) // по истечению паузы
        )
  ){
    // 3.1. проверяем лампа уже горит? переходим к следующей:
    if( isGo1==1 && fades[lamp1].bright == 255 ){ lamp1++; }
    // 5.1. или лампа уже выключена? переходим к следующей:
    else if( isGo1 == -1 && fades[lamp1].bright == 0 ){ lamp1--; }
    else{
      // 3.2. + 5.2 увеличиваем/уменьшаем яркость на 1 каждые 10мсек:
      fadeLED(lamp1, isGo1);
    }
    // 3.3., 5.3 проверяем лампы кончились? включаем паузу:
    if( lamp1 == max1 ){
      if( isGo1 == 1){           // а мы лампы включали?
        startedPause = millis(); // .. время паузы "пошло".
        isGo1 = -1;              // .. после паузы будем выключать
        lamp1=MAX_LED-1;         // .. в обратном порядке
        max1 = -1;
      }else if( isGo1 == -1 ){    // нет, мы их выключали
        isGo1 = 0;                // .. ну и ладушки, всё погасло.
      }
    }
  }
}

Но, опять же: вопрос проверки работоспособности и отладки - на ваших плечах. Заодно и разберетесь. :)

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Arhat109-2 пишет:

 Будем считать, что найти все очепятки было "домашним заданием". :)

 

Но, опять же: вопрос проверки работоспособности и отладки - на ваших плечах. Заодно и разберетесь. :)

Ну с ним я справился)), нашел косяки) Во я какой,а)))))

а вот второе, большой ?????) 

1. калибровка датчика - норма

2. датчик сработал(движение) - включаем лампы(норма)

3. а вот тут начинается весело; Зажигаем плавно №6, №10, №9 (должно же быть по другому 10,9,6 или 6,9,10)

4. и НЕ тухнем, вообще

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

6. и зачем то опять проходим калибровку

7. еще сработка датчика - резко тушим и сразу плавно зажигаем в том же порядке(причем другие 2 горят постоянно)

8. опять проходим калибровку

И преход в п.5

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ну, уже успех. :)

Далее, как обычно втыкиваем отладку во все подходящие и ключевые места:

#define fadePin1 10       // пин управления MOSFET транзистором
#define fadePin2  9       // пин управления MOSFET транзистором
#define fadePin3  6       // пин управления MOSFET транзистором

#define pirPin1 2         // пин подключения управляющего сигнала PIR датчика1
#define pirPin2 4         // пин подключения управляющего сигнала PIR датчика2

int calibrationTime = 30; // Время калибровки датчика (10-60 сек. по даташиту)

void setup()
{
  pinMode(pirPin1, INPUT);   // настариваем 2 пин как вход для сигналов с датчика
  pinMode(pirPin2, INPUT);   // настариваем 4 пин как вход для сигналов с датчика
  pinMode(fadePin1, OUTPUT); // пины на выход, для управления транзисотором
  pinMode(fadePin2, OUTPUT);
  pinMode(fadePin3, 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);
}

// структура - описание понятия "Лампа" - это пин и текущая яркость:
typedef struct{
  uint8_t pin;
  uint8_t bright;
} Led;

// теперь создадим список ламп, заодно и введем константу "всего ламп"
#define MAX_LED 3
Led  fades[MAX_LED] = {{fadePin1, 0}, {fadePin2, 0}, {fadePin3, 0}};

#define WAIT_1  200      // 10мсек - пауза между изменениями яркости
uint32_t startedAt = 0; // тут будем хранить время последнего запуска fadeLed
#define WAIT_PAUSE 10000
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 lamp, uint8_t state)
{
  Led * ptr = &(fades[lamp]);  // врем. лок. указатель на структуру "лампа"

  if(
          millis() - startedAt >= WAIT_1  // пора изменять яркость?
     && (
        (state==1 && ptr->bright < 255)   // включаем И есть куда?
        ||
        (state==-1 && ptr->bright > 0)    // или вЫключаем И есть куда?
      )
  ){
      startedAt = millis();                // новое время для отсчета следующей паузы

      ptr->bright += state;                // изменяем яркость
      analogWrite( ptr->pin, ptr->bright); // устанавливаем на выходе
      Serial.println(ptr->bright);         // передаем данные в порт для отладки
  }
}

//========== loop() ========
uint32_t curTime;

void loop()
{
  Serial.println(""); Serial.print("t="); Serial.print(millis(), 10); // заход с новой строки.

  // п.1. Если светло - выходим.
  if( isDayNow() ) return;

  // п.2: проверяем датчики движения и запускаем включение если надо:
  if( digitalRead(pirPin1) ){
    isGo1 =  1; lamp1=0;         max1 = MAX_LED;
    Serial.pint(",r1! ");
  }
// пока не надо  if( digitalRead(pirPin2) ){ isGo2 =  1; lamp1=MAX_LED-1; max1 = -1;      }

  // п.3. поштучно включаем (п.5 - выключаем) лампы, если левый датчик сработал (2-й датчик точно также можно ниже .. не показан):
  curTime = millis();
  if(
        (isGo1 == 1) // если включаем лампы, то сразу
      || (
           (isGo1 == -1) // а вот если вЫключаем, то
           && (curTime - startedPause >= WAIT_PAUSE) // по истечению паузы
        )
  ){

Serial.print(":p3/p5:, isGo1="); Serial.print(isGo1, 10);
Serial.print(", t="); Serial.print(startedPause, 10);

    // 3.1. проверяем лампа уже горит? переходим к следующей:
    if( isGo1==1 && fades[lamp1].bright == 255 ){ lamp1++; Serial.print(" :+: "); Serial.print(lamp1, 10); }

    // 5.1. или лампа уже выключена? переходим к следующей:
    else if( isGo1 == -1 && fades[lamp1].bright == 0 ){ lamp1--; Serial.print(" :-: "); Serial.print(lamp1, 10);  }
    else{
Serial.print(" :f: "); Serial.print(fades[lamp1].bright, 10); 

      // 3.2. + 5.2 увеличиваем/уменьшаем яркость на 1 каждые 10мсек:
      fadeLED(lamp1, isGo1);
    }
    // 3.3., 5.3 проверяем лампы кончились? включаем паузу:
    if( lamp1 == max1 ){
Serial.print(" :max: ");
      if( isGo1 == 1){           // а мы лампы включали?
        startedPause = millis(); // .. время паузы "пошло".
        isGo1 = -1;              // .. после паузы будем выключать
        lamp1=MAX_LED-1;         // .. в обратном порядке
        max1 = -1;
Serial.print(" :m+: ");
Serial.print(",t="); Serial.print(startedPause, 10); 
Serial.print(",go="); Serial.print(isGo1, 10); 
Serial.print(",l="); Serial.print(lamp1, 10); 
      }else if( isGo1 == -1 ){    // нет, мы их выключали
        isGo1 = 0;                // .. ну и ладушки, всё погасло.
Serial.print(" :m-: ");
Serial.print(",go="); Serial.print(isGo1, 10); 
      }
    }else{
Serial.print(",lamp=");Serial.print(lamp1, 10);
    }
  }else{
Serial.print(",not: go=");Serial.print(isGo1, 10);
Serial.print(",t0=");Serial.print(cutTime, 10);
Serial.print(",t1=");Serial.print(startedPause, 10);
  }
}

Например так. Заодно растягиваем паузы и смотрим чего происходит. :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

повтор калибровки возможен только в одном случае: перезагрузка МК заново.

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

ну значит чего то его перезагружает!)

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ещё есть смысл обозначить значение в кностанте WAIT_PAUSE и WAIT_1 как 10UL и 5000UL соответственно. Чиселки должны быть длинные и беззнаковые. Эти проверки периодов времени работают нормально только на беззнаковой арифметике. Точнее работают в любом случае, но переполнение нормально переживают только в беззнаковом виде... поэтому и результат millis() и переменная и .. константа должны быть объявлены исключительно как беззнаковые. :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Показывайте вывод сериалов .. будем смотреть где ошибка.

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

ругается в 92 и 142 строчках, но разобрался)

SOCHINEC
Offline
Зарегистрирован: 01.05.2016

Arhat109-2 пишет:

Показывайте вывод сериалов .. будем смотреть где ошибка.

так там их МОРЕ, как их сюда то показать?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

В мониторе отключаете галочку "скроллировать" или как она там .. возвращаетесь в начало странички и копипастите сюда солидный кусос под видом кода программы. :)