Как выполнить код только 1 раз в цикле loop?

sadman41
Offline
Зарегистрирован: 19.10.2016

NeXan пишет:

Ух как тема разрослась)) Мне подсказали на другом форуме, что для добавления гистерезиса нужно всего лишь добавить простую строку (как ж я не смог догадаться!!), 

Это вам ещё в #54 подсказали, если что.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

пятерка лишняя, и это потри

NeXan
Offline
Зарегистрирован: 03.06.2019

Morroc пишет:

Писали вроде уже - через millis(). Запоминаете millis() в момент "пшика" в переменную t и ждете, когда millis() - 600000 > t, это условие можно добавить к raw >= 550,

Простите, Ардуино начал изучать только неделю назад. Вот дописал код с millis для блокировки повторного срабатывания пшика в течение 5 мин, однако Ардуино этого времени не дожидается и начинает пшикать сразу после повторного включения и выключения света. Вот пример кода, подскажите, что здесь не так?


const int photo = A0;
const int motor = 13;
unsigned long led1OnTime;
int raw = 0;
bool led1On;
boolean is_once /* = true*/;

void setup() {
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
  is_once = true;
  led1On = false;
}

void loop() {
  raw = analogRead( photo ); // читаем датчик
  if ( raw < 450) { // света - нет
    if (is_once) { // уже пшикали ?
      digitalWrite( motor, HIGH ); // нет, пшикаем
      delay(1000);
      digitalWrite( motor, LOW );
      is_once = false; // очищаем флаг, пшикнули
      led1On = true;
      led1OnTime = millis();
    }
}
if ( raw > 550) { 
is_once = true; // зажгли свет, взводим флаг 
}

    if (millis() - led1OnTime > 30000) {
      led1On = false;
    }
  }
}
xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

в строке 17 или 18 надо учесть led1On.

Morroc
Offline
Зарегистрирован: 24.10.2016

Можно и в 27 (не взводим флаг пока не истек интервал).  led1On в этом случае лишний

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

или так, красиво но не понятно для ТС )

NeXan
Offline
Зарегистрирован: 03.06.2019

Нет, чтоб участок кода дописать, лентяи)) Я уж сам догадался.

Morroc
Offline
Зарегистрирован: 24.10.2016

NeXan пишет:

Нет, чтоб участок кода дописать

фии... так неинтересно (

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

как вариант

да и гестерезис особо не нужен

#define photo A0
#define motor 13

uint32_t raw = 0; 
uint32_t cMs , pMs1, pMs2; // счетчики времени 
uint8_t Pshik = 0;

void setup() 
{ 
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
} 

void loop() { 
  cMs = millis(); //текущее время, если надо несколько таймеров будет... 

  /******************** опрос датчикa *********************/ 
  if ( cMs - pMs1 > 1000UL ){ pMs1 = cMs; // срабатывает каждые 1 секунду 
     if (analogRead( photo ) > 500 ) raw++; else raw=0; //считает число срабатываний 
  }
  /*******************************************************/
  
  if(raw == 5 || raw == 600 ) { // свет включен 5 секунд и повтор через 600 секунд (10 мин) 
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  } 
  if ( cMs - pMs2 > 1000UL &&  Pshik==1) {digitalWrite( motor, 1 ); Pshik=2; } //нажали
  if ( cMs - pMs2 > 2000UL &&  Pshik==2) {digitalWrite( motor, 0 ); Pshik=3; } //отпустили
  if ( cMs - pMs2 > 30000UL && Pshik==3) {  Pshik=0; } //сброс флага
 
}

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

ELITE пишет:

как вариант

да и гестерезис особо не нужен

#define photo A0
#define motor 13

uint32_t raw = 0; 
uint32_t cMs , pMs1, pMs2; // счетчики времени 
uint8_t Pshik = 0;

void setup() 
{ 
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
} 

void loop() { 
  cMs = millis(); //текущее время, если надо несколько таймеров будет... 

  /******************** опрос датчикa *********************/ 
  if ( cMs - pMs1 > 1000UL ){ pMs1 = cMs; // срабатывает каждые 1 секунду 
     if (analogRead( photo ) > 500 ) raw++; else raw=0; //считает число срабатываний 
  }
  /*******************************************************/
  
  if(raw == 5 || raw == 600 ) { // свет включен 5 секунд и повтор через 600 секунд (10 мин) 
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  } 
  if ( cMs - pMs2 > 1000UL &&  Pshik==1) {digitalWrite( motor, 1 ); Pshik=2; } //нажали
  if ( cMs - pMs2 > 2000UL &&  Pshik==2) {digitalWrite( motor, 0 ); Pshik=3; } //отпустили
  if ( cMs - pMs2 > 30000UL && Pshik==3) {  Pshik=0; } //сброс флага
 
}

 

второй, заход )

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

xDriver пишет:

второй, заход )

чтото тут тоже "не по феншую" ??

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

ELITE пишет:

xDriver пишет:

второй, заход )

чтото тут тоже "не по феншую" ??

пшикать надо в темноте, а не в лицо.

и не пшикать если зашли менее чем через 10 мин.

 

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

xDriver пишет:

ELITE пишет:

xDriver пишет:

второй, заход )

чтото тут тоже "не по феншую" ??

пшикать надо в темноте, а не в лицо.

и не пшикать если зашли менее чем через 10 мин.

 

в тех задании стоит иначе - при входе в нос...

а задержка есть... хотя надо дополнить строку 23 и выставить нужные временные интервалы

 if( (raw == 5 || raw == 600 )&& Pshik==0 )

 

NeXan
Offline
Зарегистрирован: 03.06.2019

ELITE пишет:

как вариант

да и гестерезис особо не нужен

Я как понимаю, строка

 if(raw == 5 || raw == 600 )

отвечает за то, если свет включится на 5 секунд, то после выключения пшикнуть?

Если нет, то хотелось бы еще функцию срабатывания пшика по таймеру. То есть, в среднем на посрать времени тратится около 5 минут, обоссать унитаз около минуты. Если свет был включен до 3 минут, не пшикать. Так вот, этот код, что выше сможет ли реализовать задуманное?)))

NeXan
Offline
Зарегистрирован: 03.06.2019

NeXan]</p> <p>[quote=ELITE пишет:

как вариант

да и гестерезис особо не нужен

Я как понимаю, строка

 if(raw == 5 || raw == 600 )

отвечает за то, если свет включится на 5 секунд, то после выключения пшикнуть?

Если нет, то хотелось бы еще функцию срабатывания пшика по таймеру. То есть, в среднем на посрать времени тратится около 5 минут, а по маленькому около минуты. Поэтому, если свет был включен до 3 минут, не пшикать. Так вот, этот код, что выше сможет ли реализовать задуманное или придется переписывать?)))

Millis, я как понимаю, не сбрасывает таймер, если он не дошел до заданного.

 

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

NeXan]</p> <p>[quote=NeXan пишет:

ELITE пишет:

как вариант

да и гестерезис особо не нужен

Я как понимаю, строка

 if(raw == 5 || raw == 600 )

отвечает за то, если свет включится на 5 секунд, то после выключения пшикнуть?

Если нет, то хотелось бы еще функцию срабатывания пшика по таймеру. То есть, в среднем на посрать времени тратится около 5 минут, а по маленькому около минуты. Поэтому, если свет был включен до 3 минут, не пшикать. Так вот, этот код, что выше сможет ли реализовать задуманное или придется переписывать?)))

Millis, я как понимаю, не сбрасывает таймер, если он не дошел до заданного.

 

Да, через 5 сек и 600 сек будет дана команда пшикать Тут вы можете задать своё время, как одно, так и несколько ( в примере два интервала) Только строку поправьте на if( (raw == 5 || raw == 600 )&& Pshik==0 )

только не забудьте паузу в последней строке сделать больше самого большого повтора

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

NeXan пишет:

Millis, я как понимаю, не сбрасывает таймер, если он не дошел до заданного.

Millis - это просто счетчик времени с момента включения...

все остальные действия - это запоминание в нужный момент времени и ожидание заданной разницы между запомненым и текущим временем

Pyotr
Offline
Зарегистрирован: 12.03.2014

Урок от Евгения как можно реализовать хотелки настоящие и будущие.
http://arduino.ru/forum/programmirovanie/7-i-zonnoe-osveshchenievklvykl-...

NeXan
Offline
Зарегистрирован: 03.06.2019

Разобрался в принципе действия вашего кода, но мне нужно, чтобы пшик был сразу после выключения света, а не во время включенного. Дописал фунццию analogRead( photo ) < 400 в строку 28. Однако после выключения света пшик срабатывает через раз. Без этой функции все отлично работает. Монитор порта Serial.println(Pshik); показывает, что флаг Pshik иногда не переходит после 1 в состояние 2, а сразу на 0, когда переходит на 2, все срабатывает. Судя по монитору порта Вот сам код

#define photo A1
#define motor 6
uint32_t raw = 0;
uint32_t cMs , pMs1, pMs2; // счетчики времени
uint8_t Pshik = 0;

void setup() {
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
  Serial.begin(9600);
}

void loop() {
  //Serial.println(analogRead( photo )); delay (100);
  cMs = millis(); //текущее время, если надо несколько таймеров будет...

  /******************** опрос датчикa *********************/
  if ( cMs - pMs1 > 1000UL ) {
    pMs1 = cMs; // срабатывает каждые 1 секунду
    if (analogRead( photo ) > 500 ) raw++; else raw = 0; //считает число срабатываний
  }
  /*******************************************************/

  if (raw == 5 ) { // свет включен 5 секунд и повтор через 600 секунд (10 мин)
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  }
  if (analogRead( photo ) < 400 && cMs - pMs2 > 1000UL &&  Pshik == 1) {
    digitalWrite( motor, 1 );  //нажали
    Pshik = 2;
  }
  if ( cMs - pMs2 > 1800UL &&  Pshik == 2) {
    digitalWrite( motor, 0 );  //отпустили
    Pshik = 3;
  }
  if ( cMs - pMs2 > 300UL && Pshik == 3) {
    Pshik = 0;  //сброс флага
  }
}

  

Morroc
Offline
Зарегистрирован: 24.10.2016

А 5 секунд светили прежде чем затенять ? С виду вроде ниче так...

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

так логика работы в 28й строке у вас получилась противоречащая логике вышестоящего кода

вначале мы проверяем, что свет включен, и если выключен - то флаг снимаем

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

---

также вы сказали чуть выше - не пшикать, если менее 3 минут

а сейчас хотите сразу пшикать...

так чего вы хотите в итоге?

---

и да, с момента включения света до момента входа в туалет пройдет несколько секунд...

хотите наверняка и быстрее 

строка 18 - меняете интервал опроса датчика например на 0.1с (100мс)

и в строке 23 у вас уже будет не 5 секунд, а 0.5с (пол секунды) 

NeXan
Offline
Зарегистрирован: 03.06.2019

Morroc пишет:

А 5 секунд светили прежде чем затенять ? С виду вроде ниче так...

Все по феншую :)

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

и да, строка 36 - это время ДО СБРОСА флага - вы его сделали МЕНЬШЕ, чем время срабатывания пшикалки! а оно должно быть БОЛЬШЕ его, иначе возможны глюки в работе кода

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018
#define photo A0
#define motor 13

uint32_t raw = 0; 
uint32_t cMs , pMs1, pMs2; // счетчики времени 
uint8_t Pshik = 0;

void setup() 
{ 
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
} 

void loop() { 
  cMs = millis(); //текущее время, если надо несколько таймеров будет... 

  /******************** опрос датчикa *********************/ 
  if ( cMs - pMs1 > 100UL ){ pMs1 = cMs; // срабатывает каждые 0.1 секунду 
     if (analogRead( photo ) > 500 ) raw++; else raw=0; //считает число срабатываний //если свет погасили - сброс
  }
  /*******************************************************/
  
  if( raw == 5 && Pshik==0 ) { // свет включен 0,5 секунд  - гистериз от ложных срабатываний
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  } 
  if (                          Pshik==1) {digitalWrite( motor, 1 ); Pshik=2; } //нажали
  if ( cMs - pMs2 > 800UL    && Pshik==2) {digitalWrite( motor, 0 ); Pshik=3; } //отпустили (через 0.8с после нажатия)
  if ( cMs - pMs2 > 300000UL && raw == 0 && Pshik==3)  {digitalWrite( motor, 1 ); Pshik=4; } //нажали через 5 минут, если свет выключен
  if ( cMs - pMs2 > 300800UL && Pshik==4)  {digitalWrite( motor, 0 ); Pshik=5; } //отпустили через 5 минут 0.8 сек
  if ( cMs - pMs2 > 600000UL && (Pshik==5 || Pshik==3) ) {  Pshik=0; } //сброс флага через 600 сек (10 минут) даже если свет продолжает гореть
  
}

вроде нигде не запутал ничего

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

да, этот код можно (да и нужно) оптимизировать путем изменения условий при выключении света - не повторять действия, а взводить на старт 2й таймер и поменять флаг на нужный - дабы система уже повторно прошла цикл пшиканья и по его окончании уже сбросилась для новой работы

NeXan
Offline
Зарегистрирован: 03.06.2019

Спасибо, нашел решение, вместо "raw++" написал "raw=1", все работает как и раньше, а также изменил:

if (raw == 1) { // свет включен 5 секунд и повтор через 600 секунд (10 мин)
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  }

 

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

NeXan пишет:

Спасибо, нашел решение, вместо "raw++" написал "raw=1", все работает как и раньше, а также изменил:

if (raw == 1) { // свет включен 5 секунд и повтор через 600 секунд (10 мин)
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  }

 

внимательно посмотрите код постом выше - я в комментарии специально более подробно всё написал! - зачем имеенно 5 поставил, а не 1

NeXan
Offline
Зарегистрирован: 03.06.2019

ELITE пишет:

#define photo A0
#define motor 13

uint32_t raw = 0; 
uint32_t cMs , pMs1, pMs2; // счетчики времени 
uint8_t Pshik = 0;

void setup() 
{ 
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
} 

void loop() { 
  cMs = millis(); //текущее время, если надо несколько таймеров будет... 

  /******************** опрос датчикa *********************/ 
  if ( cMs - pMs1 > 100UL ){ pMs1 = cMs; // срабатывает каждые 0.1 секунду 
     if (analogRead( photo ) > 500 ) raw++; else raw=0; //считает число срабатываний //если свет погасили - сброс
  }
  /*******************************************************/
  
  if( raw == 5 && Pshik==0 ) { // свет включен 0,5 секунд  - гистериз от ложных срабатываний
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  } 
  if (                          Pshik==1) {digitalWrite( motor, 1 ); Pshik=2; } //нажали
  if ( cMs - pMs2 > 800UL    && Pshik==2) {digitalWrite( motor, 0 ); Pshik=3; } //отпустили (через 0.8с после нажатия)
  if ( cMs - pMs2 > 300000UL && raw == 0 && Pshik==3)  {digitalWrite( motor, 1 ); Pshik=4; } //нажали через 5 минут, если свет выключен
  if ( cMs - pMs2 > 300800UL && Pshik==4)  {digitalWrite( motor, 0 ); Pshik=5; } //отпустили через 5 минут 0.8 сек
  if ( cMs - pMs2 > 600000UL && (Pshik==5 || Pshik==3) ) {  Pshik=0; } //сброс флага через 600 сек (10 минут) даже если свет продолжает гореть
  
}

вроде нигде не запутал ничего

Этот код сбрасывает флаг 3 автоматически на 0 при прошествии более 3 секунд и пшика после "выключения света" не происходит. Если это сделать до 3 секунд, то флаг 3 переходит на 4, потом 5 и 0.

Такая же фигня происходила и с прежним кодом. Если сразу после включения флага 1 выключить свет, то он перейдет к 2, 3, 0. Но если после включени флага 1 выключить свет, например, через 10 секунд, то он сразу переходит в 0. Целый день уже ябусь. Уже думаю оставить включение пшикалки со включенным светом(((

Монитор порта:

Serial.println(Pshik); delay (10);

 

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

вы его точно скопировали? или прошлый подправлли под него?

NeXan
Offline
Зарегистрирован: 03.06.2019

Я всего лишь уменьшил время - 800UL, 3000UL, 3800UL, 6000UL. Чтобы долго не ждать для проверки.

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

а 18 строку не меняли? - попробуйте полность скопировать еще раз 

вот с уменьшенным временем

#define photo A0
#define motor 13

uint32_t raw = 0; 
uint32_t cMs , pMs1, pMs2; // счетчики времени 
uint8_t Pshik = 0;

void setup() 
{ 
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
} 

void loop() { 
  cMs = millis(); //текущее время, если надо несколько таймеров будет... 

  /******************** опрос датчикa *********************/ 
  if ( cMs - pMs1 > 100UL ){ pMs1 = cMs; // срабатывает каждые 0.1 секунду 
     if (analogRead( photo ) > 500 ) raw++; else raw=0; //считает число срабатываний //если свет погасили - сброс
  }
  /*******************************************************/
  
  if( raw == 5 && Pshik == 0 ) { // свет включен 0,5 секунд  - гистериз от ложных срабатываний
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  } 
  if (                          Pshik==1) {digitalWrite( motor, 1 ); Pshik=2; } //нажали
  if ( cMs - pMs2 > 800UL    && Pshik==2) {digitalWrite( motor, 0 ); Pshik=3; } //отпустили (через 0.8с после нажатия)
  if ( cMs - pMs2 > 15000UL && raw == 0 && Pshik==3)  {digitalWrite( motor, 1 ); Pshik=4; } //нажали через 5 минут, если свет выключен
  if ( cMs - pMs2 > 15800UL && Pshik==4)  {digitalWrite( motor, 0 ); Pshik=5; } //отпустили через 5 минут 0.8 сек
  if ( cMs - pMs2 > 30000UL && (Pshik==5 || Pshik==3) ) {  Pshik=0; } //сброс флага через 600 сек (10 минут) даже если свет продолжает гореть
  
}

 

NeXan
Offline
Зарегистрирован: 03.06.2019

Все тоже самое, сброс флага 3 через несколько секунд.

Morroc
Offline
Зарегистрирован: 24.10.2016

Сброс флага 3 неизбежен. А что происходит до того ? Висит 1 ?

sadman41
Offline
Зарегистрирован: 19.10.2016

Увидим ли мы конец этой опупеи?..

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

в этом коде если после 15000мс (15с) продолжает гореть свет - то через 30с будет сброс флага 3

если свет выключен будет - то будет повторный пшик и через еще 15 с будет сброс флага 5

NeXan
Offline
Зарегистрирован: 03.06.2019

Давайте вернемся к прежней версии кода))

#define photo A1
#define motor 6
uint32_t raw = 0;
uint32_t cMs , pMs1, pMs2; // счетчики времени
uint8_t Pshik = 0;

void setup() {
  pinMode( photo, INPUT );
  pinMode( motor, OUTPUT );
  Serial.begin(9600);
}

void loop() {
  Serial.println(pMs2); delay (10);
  cMs = millis(); //текущее время, если надо несколько таймеров будет...

  /******************** опрос датчикa *********************/
  if ( cMs - pMs1 > 1000UL ) {
    pMs1 = cMs; // срабатывает каждые 1 секунду
    if (analogRead( photo ) > 500 ) {
      raw++;
    } else {
      raw = 0;
    }
  }
  /*******************************************************/

  if (raw == 5) { // свет включен 5 секунд и повтор через 600 секунд (10 мин)
    Pshik = 1; //флаг что надо побрызгать
    pMs2 = cMs; // таймер брызгалки старт
  }
  if (raw == 0 && cMs - pMs2 > 2000UL &&  Pshik == 1) {
    digitalWrite( motor, 1 );  //нажали
    Pshik = 2;
  }
  if ( cMs - pMs2 > 2800UL &&  Pshik == 2) {
    digitalWrite( motor, 0 );  //отпустили
    Pshik = 3;
  }
  if ( cMs - pMs2 > 5000UL && Pshik == 3) {
    Pshik = 0;  //сброс флага
    raw = 0;
  }
}

Она в принципе работает, за исключением одного но! Если по достижении таймера pMs1 - 5 секунд (смотрел по монитору порта) тут же "выключить свет", то флаг Pshik срабатывает как положено по времени (2 > 3 > 0). А на 6 секунде и далее происходит моментное обнуление флага Pshik.

Судя по монитору, таймер pMs2 запускается сразу после достижения 5 секунд pMs1 и останавливается сам по себе на значении 6037 (через пару секунд после запуска), даже с выпиленными последними тремя функциями. То есть loop заканчивается на запуске этого таймера. Может быть из-за этого и флаг Pshik обнуляется?

Просто хочется докопаться до причины, я не успокоюсь)) Без этого же намного усложняется обучение))

P.S. Кажется понял. надо вместо (raw == 5) поставить (raw >= 5). Все работает и таймер pMs2 не останавливается сам по себе, и пшик работает через любое время.

P.S.2. Но это пока не точно.

Morroc
Offline
Зарегистрирован: 24.10.2016

Вывод в порт у вас где стоит ? Не должно ничего заканчиваться, да и варианта мгновенного обнуления Pshik без 2-3 вроде нет. 

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

а может потому, что вы неправильно расставили вывод в порт логи

давайте сюда код, который вы заливаете в своё устройство в полном виде 

Morroc
Offline
Зарегистрирован: 24.10.2016

Ааа... может это все (обнуление Pshik) за один цикл происходит. Надо потыкать вывод в порт внутрь всех if где Pshik меняется (вывести Pshik и значение таймера) - должно стать виднее.

NeXan
Offline
Зарегистрирован: 03.06.2019

ELITE пишет:

а может потому, что вы неправильно расставили вывод в порт логи

давайте сюда код, который вы заливаете в своё устройство в полном виде 

Он находится здесь - http://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/kak-vypolnit-kod-tolko-1-raz-v-tsikle-loop?page=1#comment-459909

Как я уже посал в том сообщении, дело было в ошибке функции (raw == 5), нужно поставить знак >=. Тогда таймер не останавливается.

Morroc, пока все работает) Интересует, до какого значения доходит таймер pMs2, он же должен потом сброситься? Не глюкнет ли ничего после сброса?

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

нет, если там будет >= то он будет при каждой итерации сбрасывать флаг на 1 и таймер 

строка 28 замените на  if( raw == 5 && Pshik == 0 )

в 18 строка изменить на if ( (cMs - pMs1 > 1000UL) && Pshik == 0 ) 

Гриша
Offline
Зарегистрирован: 27.04.2014

вот же.... да за это время я на двух (может трех) триггерах без МК уже собрал бы эту пшикалку... перечитайте пост 68 и напишите таблицу переходов... всех дел-то собрать 2 одновибратора по "и" 

создайте кучу флагов:

свет выключили Y1 = 1

если свет выключили и уже прошло время ... Y2 = 1 иначе Y1 = 0

прошло t1>x1 =1 

пшыкали t2> x2 = 1  

если все  нужные  флаги ==1, пшыкаем, скидываем и взводим нужные  флаги.

UPD лучше блоксхему нарисовать - мне они болше таблиц нравятся, но не всегда возможно их подробно нарисовать... 

bwn
Offline
Зарегистрирован: 25.08.2014

Гриша пишет:

вот же.... да за это время я на двух (может трех) триггерах без МК уже собрал бы эту пшикалку... перечитайте пост 68 и напишите таблицу переходов... всех дел-то собрать 2 одновибратора по "и" 

Не, Гриш, это не наш метод. Элита очень преподавать любит, в последний его серьезный заход,  "Работа с кнопками..." от комментариев прикрыли.

Гриша
Offline
Зарегистрирован: 27.04.2014

bwn пишет:

 Элита очень преподавать любит, в последний его серьезный заход,  "

 docendo discimus... я  редко задаю вопросы на форуме и редко отвечаю, банальная нехватка времени писать ... ИМХО не стоит отбивать благие намеренья, даже не совсем правильные, а вместе с кем-то учиться легче... 

2ТС - вспомнил еще способ -

UPD.  Был знаком с двумя товарищами, один умел писать код, другой схемотехник и электроник... в одной из задачь схемотехник объяснил программеру алгоритм работы устройства (для написания кода прогером) на листе бумаги - он расписал 150 тактов!!! А потом прогер просто написал с этих листов программу и все заработало!!!

NeXan
Offline
Зарегистрирован: 03.06.2019

ELITE пишет:

нет, если там будет >= то он будет при каждой итерации сбрасывать флаг на 1 и таймер 

строка 28 замените на  if( raw == 5 && Pshik == 0 )

в 18 строка изменить на if ( (cMs - pMs1 > 1000UL) && Pshik == 0 ) 

Вообще не работает этот вариант. Таймер pMs2 останавливается наверно на 6 секунде и ничего не работает как мне кажется из-за того, что  if ( raw == 5 ), а на 6 секунде уже не ровно 5. Но когда я поставил знак >= таймер pMs2 стал останавливаться после выключения света и продолжал отчет на 5 секунде после включения света.

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

Morroc
Offline
Зарегистрирован: 24.10.2016

NeXan пишет:
if ( raw == 5 ), а на 6 секунде уже не ровно 5

Неважно на какой секунде, но когда то 5 там будет и сразу должен запуститься "пшик", стрянно...

Для наглядности лучше вывести cMs и Pshik (и в if'ы после выполнения команд внутри тоже сунуть вывод)

NeXan
Offline
Зарегистрирован: 03.06.2019

Размещаю весь код моей пшикалки, который у меня получился. На данный момент все задуманное испытано и работает. Всем спасибо за помощь! Для новичка это очень хорошо, хоть и код получился корявым)))

Принцип действия таков. На корпусе есть переключатель - OFF > MANUAL (только кнопка) > AUTO / MANUAL (кнопка и автоматика). В последнем режиме после включения света в туалете, запускается таймер готовности пшика (3 мин), до этого времени мигает синий светодиод (стоит RGB). Если прошло менее 3 минут и свет отключился (это время обычно затрачивается на коричневые дела), то после повторного включения он начинает идти заново. Но если прошло 3 минуты синий светодиод начинает гореть постоянно, это означает, что после выключения света произойдет распыление освежителя.

Во время распыления (0,8 сек) включится зеленый светодиод и сменится мигающим красным, это блокировка повторного нажатия в течение 30 минут (запах освежителя обычно столько и держится). Также блокируется и кнопка ручного распыления.

В ручном режиме работает только кнопка. При этом во время ключенного света синий светодиод готовности постоянно мигает (таймер жеж выключен). При нажатии на кнопку, происходят описанные выше действия.

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

Также присутствует защита от переразряда батареек (2 Ni-Mh последовательно). Если заряд опустится ниже 1,9В, то работа распылителя будет заблокрована полностью и включится красный светодиод, а Ардуино уйдет в сон для уменьшения эноргопотребления.

Кстати, насчет него. Для понижения энергопотребления я понизил частоту до 1 Мгц, пришлось пересчитывать таймеры. А Ардуино запитал через повышающий DC-DC, так как максимальное напряжение батареек не хватает для нормальной работы. На выходе выставил 3.4 Вольт. Чем выше, тем больше ток потребления. При 5В - 60 мА (16Мгц), при 3.4В - 5 мА (1 Мгц) в режиме ожидания (так как напряжение батареек ниже преобразованного, ток будет выше + КПД преобразователя, после него ток получился менее 1 мА, преобразователь потребляет 0,8 мА на холостом ходу). Это все равно много, по расчетам, аккумуляторы придется заряжать примерно раз в 20 дней. В связи с этом, у меня возник вопрос, можно ли как нибудь Ардуино загнать в спящий режим после выключения блокировки, а после включения света или нажатия кнопки его будить?

const int photo = A1;                   // фоторезистор
const int charge = A5;                  // вход 3В от батареек (защита от переразряда)
const int motor = 2;                    // привод распылителя
const int button = 3;                   // кнопка
const int led_block = 4;                // светодиод блокировки (красный)
const int manual_mode = 5;              // автоматический и ручный режимы
const int led_work = 6;                 // светодиод работы (зеленый)
const int led_on = 7 ;                  // светодиод готовности (синий)
float vout = 0.0;
float vin = 0.0;
float R1 = 7500;
float R2 = 1000;
int value = 0;                          // контроль батареек
int raw = 0;                            // переменная фоторезистора
int stlk = 1;                           // блокировка кнопки в течение 30 минут после срабатывания пшика по свету
int chrg = 1;                           // блокировка работы устройства с разряженными батарейками
int btn = 1;                            // блокировка нескольких пшиков при удержании кнопки
int led = 1;                            // индикация готовности пшика после выключения света
int pht = 1;                            // блокировака пшика по свету в течении 30 минут после нажатия на кнопку
int statblk = 1;                        // отключение счетчика stat
uint32_t stat = 1;                      // управление шпиком
uint32_t svet = 0;                      // флаг управления готовности для пшика по свету
uint32_t cMs, pMs1, blokTime;           // счетчики времени по свету
uint8_t Pshik = 0;                      // разрешение пшика после получения готовности
bool pshikBlock;                        // флаг блокировки блокировка повторного пшика
int ledState = LOW;                     // состояние светодиода
int32_t  previousMillis = 0;            // храним время последнего переключения светодиода
int32_t  interval = 62.5;               // интервал между включение/выключением светодиода ожидания (1 секунда)


#include <avr/power.h>
#include <avr/sleep.h>

void setup() {
  clock_prescale_set(clock_div_16);     // понижение частоты работы микроконтроллера до 1 Мгц для экономии заряда батареек
  pinMode( photo, INPUT );
  pinMode( manual_mode, INPUT );
  pinMode( charge, INPUT );
  pinMode( motor, OUTPUT );
  pinMode( button, INPUT );
  pinMode( led_block, OUTPUT );
  pinMode( led_work, OUTPUT );
  pinMode( led_on, OUTPUT );
  digitalWrite( led_block, LOW );
  digitalWrite( led_work, LOW );
  digitalWrite( motor, LOW );
  pshikBlock = false;
}

void loop() {
  cMs = millis();                                             // текущее время
  int buttonState = digitalRead( button );                    // считывание значения с пина кнопки
  int manualState = digitalRead( manual_mode );               // считывание значения с пина ручного режима
  raw = analogRead( photo );                                  // считывание значения с пина фоторезистора
  value = analogRead( charge );                               // считывание напряжения с пина (контроль заряда)
  vout = (value * 5.0) / 1024;                                // конвертор в понятные единицы измерения
  vin = vout / (R2 / (R1 + R2));

  if (chrg == 1) {                                            // если заряд АКБ в норме
    if ( buttonState == HIGH  && btn == 1 && stlk == 1) {     // если кнопка нажата и не заблокирована
      btn = 0;                                                // переключить флаг защиты повторных пшиков при удержании кнопки
      pht = 0;                                                // заблокировать пшик по свету на 30 минут
      digitalWrite( led_on, LOW );                            // выключаем светодиод готовности
      digitalWrite( led_work, HIGH );                         // включаем светодиод работы
      digitalWrite( motor, HIGH );                            // включаем пшик
      delay(50);                                              // ждем 800 миллисекунд
      digitalWrite( motor, LOW );                             // выключаем пшик
      digitalWrite( led_work, LOW );                          // выключаем светодиод работы
      pshikBlock = true;                                      // запустить таймер блокировки повторного срабатывания на 30 минут
      blokTime = millis();
    } else if (btn == 0) {
      if ( raw < 350 && vin <= 4.8 ) {                        // если в туалете темно
        digitalWrite( led_block, LOW );                       // выключаем светодиод блокировки
      } else {                                                // если в туалете светло
        if (cMs - previousMillis > interval) {                // сохраняем время последнего переключения
          previousMillis = cMs;
          if (ledState == LOW)                                // если светодиод блокировки не горит, то зажигаем, и наоборот
            ledState = HIGH;
          else
            ledState = LOW;
          digitalWrite(led_block, ledState);                  // устанавливаем состояния выхода, чтобы включить или выключить светодиод
        }
      }
    } else if (stlk == 1) {
      if ( raw < 350 && vin <= 4.8 ) {                        // если в туалете темно
        digitalWrite( led_on, LOW );                          // выключаем светодиод разряда батареи
      } else if (led == 0) {                                  // если наступила готовность автоматического пшика
        digitalWrite( led_on, HIGH );                         // светодиод готовности горит постоянно
      } else {
        if (cMs - previousMillis > interval) {                // сохраняем время последнего переключения
          previousMillis = cMs;
          if (ledState == LOW)                               // если светодиод не горит, то зажигаем, и наоборот
            ledState = HIGH;
          else
            ledState = LOW;
          digitalWrite(led_on, ledState);                    // устанавливаем состояния выхода, чтобы включить или выключить светодиод
        }
      }
    }
    if ( buttonState == LOW && millis() - blokTime > 112500 )  btn = 1;   // если кнопка не нажата и время блокировки прошло, разблокировать повторное нажатие

    if ( manualState == HIGH ) {                              // если включен автометический и ручной режимы
      if ( cMs - pMs1 > 62UL ) {                              // запускаем таймер отстчета готовности автоматического пшика
        pMs1 = cMs;                                           // время опроса фотореле каждые 1 секунду
        if ( raw > 450 ) {                                    // если в туалете светло
          svet++;                                             // запустить таймер
        } else {                                              // если темно
          svet = 0;                                           // обнулить таймер
        }
      }
      if ( svet == 180 ) {                                    // если свет включен 3 минуты и более
        Pshik = 1;                                            // включаем флаг разрешения пшика
        led = 0;                                              // включаем постоянное свечение светодиода готовности
      }
      if ( Pshik == 1 ) {                                     // если автоматическое срабатывание пшикалки разрешено
        if ( raw < 350 && stat <= 4294967295 && pht == 1 && statblk == 1 ) stat++;    // если свет выключился, все блокировки выключены, запустить таймер отсчета
        if ( stat == 300 ) {                                  // после пары секунд
          stat ++;
          digitalWrite( led_on, LOW );                        // выключаем светодиод готовности
          digitalWrite( led_work, HIGH );                     // включаем светодиод работы
          digitalWrite( motor, HIGH );                        // включаем привод
          delay(50);                                          // ждем 800 миллисекунд
          digitalWrite( motor, LOW );                         // выключаем привод
          digitalWrite( led_work, LOW );                      // выключаем светодиод работы
          stlk = 0;                                           // заблокировать кнопку на некоторое время
          statblk = 0;                                        // отключить таймер stat
          pshikBlock = true;                                  // запустить таймер блокировки повторного срабатывания на 30 минут
          blokTime = millis();
        } else if ( stlk == 0 ) {
          if ( raw < 350 && vin <= 4.8 ) {                    // если в туалете темно
            digitalWrite( led_block, LOW );                   // выключаем светодиод блокировки
          } else {                                            // если светло
            if (cMs - previousMillis > interval) {            // сохраняем время последнего переключения
              previousMillis = cMs;
              if (ledState == LOW)                            // если светодиод не горит, то зажигаем, и наоборот
                ledState = HIGH;
              else
                ledState = LOW;
              digitalWrite(led_block, ledState);              // устанавливаем состояния выхода, чтобы включить или выключить светодиод
            }
          }
        }
      }
    }
  }

  if ( raw > 450 && millis() - blokTime > 112500 ) {          // если в туалете светло и время блокировки вышло
    digitalWrite( led_block, LOW );                           // отключить светодиод блокировки
    stat = 1;                                                 // разблокировать таймер
    stlk = 1;                                                 // разблокировать кнопку
    pht = 1;                                                  // разблокировать автоматический пшик
    statblk = 1;
  }

  if (pshikBlock)                                             // если блокировка активна
    if (millis() - blokTime > 112500) {
      digitalWrite( led_block, LOW );                         // включаем светодиод блокировки
      stlk = 1;                                               // разблокировать таймер
      Pshik = 0;                                              // сбросить флаг готовности автоматического пшика
      svet = 0;                                               // сбросить таймер готовности
      led = 1;                                                // влючить мигание синим светодиодом
      pshikBlock = false;
    }

  if ( vin <= 2.5 ) {                                         // и если заряд батареи слабый
    chrg = 0;
    digitalWrite( led_on, LOW );                              // выключаем светодиод готовности
    digitalWrite( led_work, LOW );                            // выключаем светодиод работы
    digitalWrite( motor, LOW );                               // включаем мотор
    digitalWrite( led_block, HIGH );                          // включаем светодиод разряда батареи
    ADCSRA = 0;
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_mode();
    MCUCR = bit (BODS) | bit (BODSE);                         // turn on brown-out enable select
    MCUCR = bit (BODS);                                       // this must be done within 4 clock cycles of above
    sleep_cpu ();
  }

}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Ардуино в спящем режиме - это как гопник в цилиндре. Смешно и бессмысленно.

NeXan
Offline
Зарегистрирован: 03.06.2019

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

Morroc
Offline
Зарегистрирован: 24.10.2016

NeXan пишет:
В связи с этом, у меня возник вопрос, можно ли как нибудь Ардуино загнать в спящий режим после выключения блокировки, а после включения света или нажатия кнопки его будить?

Так выключайте все, а по кнопке включайте :) "Загнать" можно, но придется копнуть поглубже https://tsibrov.blogspot.com/2018/02/arduino-power-down.html