задержка с рестартом

ty
Offline
Зарегистрирован: 15.06.2015

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

 

По найденым примерам пытался написать что то. Работает,  после срабатывания датчика реле включаестя и отрабатэавет весь период, повторные срабатывания датчика в этот период не регистрируются, рестарта нет. Что я сделал неправильно?

 

/* ARDUINI NANO
 * PIR Sensor[PIN GND]  -> Arduino Nano[PIN GND]
 * PIR Sensor[PIN 5V]   -> Arduino Nano[PIN 5V]
 * PIR Sensor[PIN OUT]  -> Arduino Nano[PIN A0]
 * Relay Module[PIN IN] -> Arduino Nano[PIN 13]
 */
 
const int relout = 13;//relout - пин(выходной сигнал) для модуля реле
//prevMillis - переменная для хранения времени предидущего цикла сканирования программы
unsigned long prevMillis = 0;//interval - временной интервал для отсчета секунд до выключения реле
int interval = 1000;
int DelayValue = 10;//DelayValue - период в течение которого реле удерживается во включенном состоянии
int initSecond = 10; //initSecond - Переменная итерации цикла инициализации 
static int countDelayOff = 0; //countDelayOff - счетчик временных интервалов
static bool trigger = false;//trigger - флаг срабатывания датчика движения

#define baud 9600


void setup() 
{
  Serial.begin(9600); //инициализация вывода в терминал
  
  pinMode(relout, OUTPUT); //процедура инициализации порта на который подключено реле
  digitalWrite(relout, LOW); //первоначальное состояние порта на который подключено реле

  for(int i = 0; i < initSecond; i ++) // ждем когда закончатся X циклов(переменная initSecond) продолжительностью в 1 секунду, за это время датчик "самоинициализируется"
  {
    delay(100);
  }
}

void loop() 
{
  if(analogRead(A0) > 500) //Считать значение с аналогового порта А0, Если значение выше 500 
  {
    trigger = true; //устаналиваем флаг trigger=1
  }
  else
  {
    trigger = false; //В противном случае устаналиваем флаг trigger=0
  }

 Serial.println(trigger); //вывод состояния флага в терминал

  while(trigger) //Пока флаг срабатывания датчика движения =1
  {
    unsigned long currMillis = millis(); //Сохранить в переменной currMillis  значение миллисекунд прошедших с момента начала выполнения программы
   
    if(currMillis - prevMillis > interval) //Сравниваем с предидущим значением миллисекунд, если разница больше заданного интервала, то:
    {
      prevMillis = currMillis;  //Сохранить текущее значение миллисекунд в переменную prevMillis
      if(countDelayOff >= DelayValue) //Проверяем счетчик задержки сравнивая его со значением периода  в течение которого реле должно удерживаться во включенном состоянии
      {
        trigger = false; //Если значение сравнялось, то сбросить флаг срабатывания датчика движения
        countDelayOff = 0; //Обнулить счетчик задержки
        digitalWrite(relout, LOW);  //Выключить реле
        break; //Прервать цикл
      }
    else //Если значение всё еще меньше, то инкрементировать счетчик задержки на единицу
      {
        countDelayOff ++;
        digitalWrite(relout, HIGH);//Удерживать реле во включенном состоянии
      }
    }
  }
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

ty пишет:

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

Вот так, навскидку:

#define RELAY_WORK_TIME 10000 // сколько миллисекунд на работу реле при срабатывания датчика
unsigned long relayTimer = 0; // таймер времени начала работы реле
bool isRelayOn = false; // флаг того, что реле включено

void relayOn()
{
	if(isRelayOn)
		return;
	
	// тут включаем реле
	
	isRelayOn = true;
}

void relayOff()
{
	if(!isRelayOn)
		return;
	
	// тут выключаем реле
	
	isRelayOn = false;
}

void loop()
{ 
	if(analogRead(A0) > 500) // сработал датчик
	{
		relayTimer = millis(); // сбрасываем таймер начала работы
		relayOn(); // включаем реле
	}
	
	// если реле включено и прошло нужное время - вырубаем его
	if(isRelayOn && millis() - relayTimer >  RELAY_WORK_TIME)
	{
		relayOff(); // выключаем реле
	}
}

Логика проста: при любом срабатывании датчика сбрасываем таймер начала работы реле. Если датчик не срабатывал долгое время - реле выключится после истечения нужного интервала.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
const byte sensPin =/*пин реле*/A0;
bool old=0;
const byte relPin =/*пин реле*/ 13;
bool rel = 0;
unsigned long past;
const int time = 1000;
//----------------------------------------------------------
void setup() {
  pinMode(relPin, OUTPUT);
  digitalWrite(relPin, rel = 0);
}

void loop() {
  if (!old && analogRead(sensPin) > 500) {
    old = 1;
    digitalWrite(relPin, rel = 1);
    past = millis();
  }
  if (old && analogRead(sensPin) <= 500) {
    old = 0;
  }
  if (rel && millis() - past > time) {
    digitalWrite(relPin, rel = 0);
  }
}
/**/

 

ty
Offline
Зарегистрирован: 15.06.2015

qwone пишет:

/**/
const byte sensPin =/*пин реле*/A0;
bool old=0;
const byte relPin =/*пин реле*/ 13;
bool rel = 0;
unsigned long past;
const int time = 1000;
//----------------------------------------------------------
void setup() {
  pinMode(relPin, OUTPUT);
  digitalWrite(relPin, rel = 0);
}

void loop() {
  if (!old && analogRead(sensPin) > 500) {
    old = 1;
    digitalWrite(relPin, rel = 1);
    past = millis();
  }
  if (old && analogRead(sensPin) <= 500) {
    old = 0;
  }
  if (rel && millis() - past > time) {
    digitalWrite(relPin, rel = 0);
  }
}
/**/

 

 

Если А0 остается с высоким уровнем, рестарта нет, отрабатывается только один интервал.

ty
Offline
Зарегистрирован: 15.06.2015

DIYMan пишет:

ty пишет:

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

Вот так, навскидку:

#define RELAY_WORK_TIME 10000 // сколько миллисекунд на работу реле при срабатывания датчика
unsigned long relayTimer = 0; // таймер времени начала работы реле
bool isRelayOn = false; // флаг того, что реле включено

void relayOn()
{
	if(isRelayOn)
		return;
	
	// тут включаем реле
	
	isRelayOn = true;
}

void relayOff()
{
	if(!isRelayOn)
		return;
	
	// тут выключаем реле
	
	isRelayOn = false;
}

void loop()
{ 
	if(analogRead(A0) > 500) // сработал датчик
	{
		relayTimer = millis(); // сбрасываем таймер начала работы
		relayOn(); // включаем реле
	}
	
	// если реле включено и прошло нужное время - вырубаем его
	if(isRelayOn && millis() - relayTimer >  RELAY_WORK_TIME)
	{
		relayOff(); // выключаем реле
	}
}

Логика проста: при любом срабатывании датчика сбрасываем таймер начала работы реле. Если датчик не срабатывал долгое время - реле выключится после истечения нужного интервала.

 

Спасибо! Попробую это завтра.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ty пишет:

Если А0 остается с высоким уровнем, рестарта нет, отрабатывается только один интервал.


/**/
const byte sensPin =/*пин сенсора*/A0;
const byte relPin  =/*пин реле*/ 13;
bool old, rel;
unsigned long past;
const int time = 1000;
//----------------------------------------------------------
void setup() {
  pinMode(relPin, OUTPUT);
  digitalWrite(relPin, rel = 0);
  old = 0;
}

void loop() {
  // сработка если уровень снизится ниже 500
  if (!old && analogRead(sensPin) < 500) {
    old = 1;
    digitalWrite(relPin, rel = 1);
    past = millis();
  }
  if (old && analogRead(sensPin) >= 500) {
    old = 0;
  }
  if (rel && millis() - past > time) {
    digitalWrite(relPin, rel = 0);
  }
}
/*Скетч использует 1496 байт (0%) памяти устройства. Всего доступно 253952 байт.
  Глобальные переменные используют 15 байт (0%) динамической памяти, оставляя 8177 байт для локальных переменных. Максимум: 8192 байт.
*/

 

ty
Offline
Зарегистрирован: 15.06.2015

qwone пишет:

ty пишет:

Если А0 остается с высоким уровнем, рестарта нет, отрабатывается только один интервал.


/**/
const byte sensPin =/*пин сенсора*/A0;
const byte relPin  =/*пин реле*/ 13;
bool old, rel;
unsigned long past;
const int time = 1000;
//----------------------------------------------------------
void setup() {
  pinMode(relPin, OUTPUT);
  digitalWrite(relPin, rel = 0);
  old = 0;
}

void loop() {
  // сработка если уровень снизится ниже 500
  if (!old && analogRead(sensPin) < 500) {
    old = 1;
    digitalWrite(relPin, rel = 1);
    past = millis();
  }
  if (old && analogRead(sensPin) >= 500) {
    old = 0;
  }
  if (rel && millis() - past > time) {
    digitalWrite(relPin, rel = 0);
  }
}
/*Скетч использует 1496 байт (0%) памяти устройства. Всего доступно 253952 байт.
  Глобальные переменные используют 15 байт (0%) динамической памяти, оставляя 8177 байт для локальных переменных. Максимум: 8192 байт.
*/

 

Спасибо, почти то что надо если дергать А0 вверх вниз, есть рестарт но если сохраняется высокий уровень рестарта нет. Видимо я плохо описал задачу.  Ситуация, человек зашел в комнату, датчик сработал, период включения допустим 20 минут, человек ходит по комнате, датчик может подавать все время высокий уровень на А0 но может и дергатся если человек выходит из зоны действия и заходит обратно. Свет в это время включен. Когда человек из комнаты выйдет свет должен оставатся включеным 20 минут после ухода.

Т.е. реле должно включится по фронту сигнала от датчика и выключится через X минут после спада сигнала от датчика.

В любом случае спасибо, идей подкинули, буду разбиратся.

 

ty
Offline
Зарегистрирован: 15.06.2015

DIYMan пишет:

ty пишет:

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

Вот так, навскидку:

#define RELAY_WORK_TIME 10000 // сколько миллисекунд на работу реле при срабатывания датчика
unsigned long relayTimer = 0; // таймер времени начала работы реле
bool isRelayOn = false; // флаг того, что реле включено

void relayOn()
{
	if(isRelayOn)
		return;
	
	// тут включаем реле
	
	isRelayOn = true;
}

void relayOff()
{
	if(!isRelayOn)
		return;
	
	// тут выключаем реле
	
	isRelayOn = false;
}

void loop()
{ 
	if(analogRead(A0) > 500) // сработал датчик
	{
		relayTimer = millis(); // сбрасываем таймер начала работы
		relayOn(); // включаем реле
	}
	
	// если реле включено и прошло нужное время - вырубаем его
	if(isRelayOn && millis() - relayTimer >  RELAY_WORK_TIME)
	{
		relayOff(); // выключаем реле
	}
}

Логика проста: при любом срабатывании датчика сбрасываем таймер начала работы реле. Если датчик не срабатывал долгое время - реле выключится после истечения нужного интервала.

Спасибо огромное! Это то что надо, проверю завтра еще раз на свежую голову, но сейчас все выглядит хорошо, посмотрел таймер в мониторе, работает как надо, при нажатой кнопке добавляется. В общем спасибо!

Код такой сейчас:

/* ARDUINI NANO
 * PIR Sensor[PIN GND]  -> Arduino Nano[PIN GND]
 * PIR Sensor[PIN 5V]   -> Arduino Nano[PIN 5V]
 * PIR Sensor[PIN OUT]  -> Arduino Nano[PIN A0]
 * Relay Module[PIN IN] -> Arduino Nano[PIN 13]
 */

#define RELAY_WORK_TIME 1000 // сколько миллисекунд на работу реле при срабатывания датчика
unsigned long relayTimer = 0; // таймер времени начала работы реле
bool isRelayOn = false; // флаг того, что реле включено
const int relout = 13;//relout - пин(выходной сигнал) для модуля реле

void setup() 

{
   Serial.begin(9600);
}

void relayOn()
{
  if(isRelayOn)
    return;
    isRelayOn = true; // тут включаем реле
    digitalWrite(relout, HIGH);
}

void relayOff()
{
  if(!isRelayOn)
    return;
    isRelayOn = false;// тут выключаем реле
    digitalWrite(relout, LOW);
}

void loop()
{ 
 Serial.println ("relayTimer"); 
 Serial.println (relayTimer);
  
     if(analogRead(A0) > 500) // сработал датчик
  {
    relayTimer = millis(); // сбрасываем таймер начала работы
    relayOn(); // включаем реле
  }
     if(isRelayOn && millis() - relayTimer >  RELAY_WORK_TIME) // если реле включено и прошло нужное время - вырубаем его
  {
    relayOff(); // выключаем реле
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Легким движением руки ...

/**/
const byte sensPin =/*пин сенсора*/A0;
const byte relPin  =/*пин реле*/ 13;
bool rel;
unsigned long past;
const int time = 1000;
//----------------------------------------------------------
void setup() {
  pinMode(relPin, OUTPUT);
  digitalWrite(relPin, rel = 0);
}

void loop() {
  // сработка если уровень снизится ниже 500
  if (analogRead(sensPin) < 500) { 
    digitalWrite(relPin, rel = 1);
    past = millis();
  }
  if (rel && millis() - past > time) {
    digitalWrite(relPin, rel = 0);
  }
}
/**/

пс:тоже самое что написали вы.:)

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Строго говоря, подобные вещи лучше делать без ардуины вообще - на NE555, например. Тот же датчик движения китайский уже умеет в задержку: при срабатывании на выходе появляется сигнал, который может пропадать через определённое настраиваемое потенциометром время, при повторных срабатываниях, ессно, это время отодвигается в будущее. Никакой ардуины - чистая магия :)

ty
Offline
Зарегистрирован: 15.06.2015

DIYMan пишет:

Строго говоря, подобные вещи лучше делать без ардуины вообще - на NE555, например. Тот же датчик движения китайский уже умеет в задержку: при срабатывании на выходе появляется сигнал, который может пропадать через определённое настраиваемое потенциометром время, при повторных срабатываниях, ессно, это время отодвигается в будущее. Никакой ардуины - чистая магия :)

Да, конечно, но в учебных целях и если нужны задежки по пол часа, ардуино мне больше нравица :) Длинные задежки плохо реализуются без цифры. Ну и одна ардуина вполне может работать с датчиками в 3-4 помещениях отрабатывая выдежки хоть по часу, что мне собственно и надо.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну для нескольких пар сенсор-реле лучше всего так написать.

/**/
//-----Cl_SensRel-------------------------------
class Cl_SensRel {
  protected:
    const byte sensPin;
    const byte relPin;
    const unsigned long time;
    bool rel;
    unsigned long past;
  public:
    /*конструктор Cl_SensRel()
      описание :создать объект
      вход: _sensPin: пин сенсора
            _relPin: пин реле
            _time: длительность удержания
    */
    Cl_SensRel(byte _sensPin, byte _relPin, unsigned int _time = 1000)
      : sensPin(_sensPin), relPin(_relPin), time(_time)   {}
    /*функция init()
       описание :иницирование объекта/ вставить в setup()
    */
    void init() {
      pinMode(relPin, OUTPUT);
      digitalWrite(relPin, rel = 0);
    }
    /*функция run()
      описание :работа объекта/ вставить в loop()
    */
    void run() {
      if (analogRead(sensPin) < 500) {
        digitalWrite(relPin, rel = 1);
        past = millis();
      }
      if (rel && millis() - past > time) {
        digitalWrite(relPin, rel = 0);
      }
    }
};
//-------Компоновка-----------------------------
const unsigned long time_1s = 1000; //задержка 1сек
Cl_SensRel SensRel_1(/*пин сенсора*/A0,/*пин реле*/ 13,/*время задержки*/time_1s);
Cl_SensRel SensRel_2(/*пин сенсора*/A1,/*пин реле*/ 12,/*время задержки*/time_1s);
Cl_SensRel SensRel_3(/*пин сенсора*/A2,/*пин реле*/ 11,/*время задержки*/time_1s);
//------main()------------------------------
void setup() {
  SensRel_1.init();
  SensRel_2.init();
  SensRel_3.init();
}

void loop() {
  SensRel_1.run();
  SensRel_2.run();
  SensRel_3.run();
}
/**/

 

ty
Offline
Зарегистрирован: 15.06.2015

Спасибо, как добавлю сенсоров попробую.