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

alexbmd
Offline
Зарегистрирован: 15.01.2016

{преамбула}: всё описание сточки зрения логики/алгоритма. возможно гдето у меня ошибка и какаято часть не реализуемма программно а какаято хардверно. укажите плиз.

данно: переключатель. т.е. три вывода один из которых общий. т.е. имеем либо 1-2 состояние либо 2-3. {и если я не ошибаюсь} обозначим это, замкнут 1 тогда pin1 = hi. pin3 = low.  замкнут 3 тогда pin1=low pin3=hi  

алгоритм:  

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

- к примеру со старта замкнуто 2-3, тогда  pin1=low pin3=hi, тогда как только состояние изменится на противоположное (в даном примере на pin1=hi/pin3=low) то зажечь диод на 1 минуту.

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

- также нужно учесть сброс mils через `50 дней чтоб диод не горел 50 дней

 

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

 

 
Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

alexbmd пишет:

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

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

НО, как ниже сказал  andriano, в этом нет смысла. Достаточно использовать один из двух крайних контактов переключателя (например pin1).

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. То, что у Вас в "дано" немножко неоптимально. Традиционно подтяжка используется "вверх" и в Ардуино только такая встроенная подтяжка. Т.е. при замыкании кнопки на соответствующем выводе LOW, а не HIGH. Т.е. либо Вы меняете логику работы на противоположную, либо понадобятся дополнительные детали.

2. По сути у Вас две контактные группы и два входа реализуют лишь два состояния. Это явно избыточно. Целесообразнее использовать единственную контактную группу и единственный вход. Этого вполне достаточно для Ваших хотелок.

3. В свете 2 код должен быть в точности такой же, как и для одиночной кнопки.

alexbmd
Offline
Зарегистрирован: 15.01.2016

andriano 

я и понял п2 и нет. в том плане что переключатель  трех выводной и мы можем реагировать на него в обоих положениях. т.е.  диод может гореть как и в верхнем положении переключателя так и в нижнем. в случае же использования простой кнопки (он же выключатель)  диод будет гореть только в нижнем положении выключателя - что мне не приемлимо. тк. выключатель придется переводить в исходное положение (т.е. 2 переключения вместого одного в случае с переключателем).   если я не прав поправьте плиз меня?

 

вот я подумал и набросал код.  пока что в случае c pull down. мне так легче разобраться. если все правильно подумаем как перевести в pull up :)

код написан с учетом того что - всё что не 0 и не false является true.  если это не так в ардуино плиз подскажите как красиво переделать.  и вообще плиз посмотрите на мой код как еще можно больше его упростить и/или облагародить?

boolean switch = false; 
boolean light = false;
previousMillis = 0;

loop{

if (!switch) {if (digitalRead(pin1) == hi) {switch = pin3;} else {switch = pin1;}}

if (digitalRead(switch) == hi) {switch = false; previousMillis = millis(); light = !light; digitalWrite(LEDpin, light);}

if (light && millis() - previousMillis > 60000) {light = !light; digitalWrite(LEDpin, light);}

}

только про 50 дней пока не придумал как учитывать  :\

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbmd, из исходного сообщения я понял, что светодиод должен загораться по любому изменению состояния переключателя и гореть в течение минуты с последнего изменения. Это так?

Если так, то абсолютно безразлично, где там LOW, а где HIGH, т.к. прибор должен реагировать исключительно на переключения, безразлично из какого состояния в какое.

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

alexbmd пишет:

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

Считайте, что у вас переключатель это кнопка с фиксацией и все. Дребезг присутсвует и в "кнопке с фиксацией".

А так все тоже самое скетч здесь https://yadi.sk/d/WKaKvxrX3APTwN

Головной файл выкладываю для просмотра .

/* class_time_relay.ino  https://yadi.sk/d/WKaKvxrX3APTwN
  #1 реле ->13 
  #2 кнопка ->2
  Принцип кода:нажал 1 раз реле вкл на опред время. Замечение: вкл можно только когда выкл, иначе вкл будут не учтены.
*/
//#1 реле
#include "Cl_time_relay.h"
const byte relay_pin = 13;
Cl_time_relay T_Relay1;  //создать по времени отключ реле на пине 13
void func() {
  T_Relay1.ON();
}
//#2 кнопка
#include "Cl_do_btn.h"
const byte btn1_pin = 2;
Cl_do_btn Do_1; // создать кнопку на пине 2
void setup() {
  //#1 реле
  T_Relay1.setup(relay_pin, 0, 10000);// (пин,логика,время relay ON)
  //#2 кнопка
  Do_1.setup(btn1_pin);
}
void loop() {
  //#1 реле
  T_Relay1.loop();
  //#2 кнопка
  Do_1.loop(& func);
}

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

andriano пишет:

Если так, то абсолютно безразлично, где там LOW, а где HIGH, т.к. прибор должен реагировать исключительно на переключения, безразлично из какого состояния в какое.

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

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

alexbmd, Вам не нужно считывать оба пина переключателя (pin1 и pin3). Достаточно считать только один из них (любой, например pin1). Зачем считывать воторй пин (например pin3), если и так известно, что его состояние всегда противоположное первому пину? 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbmd пишет:

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

1. Объявляете глобальную перемиенную для хранения состояния пина (строго говоря, еще одну - для времени).

2. Заносите в нее состояние пина в setup().

3. В loop() читаете состояние пина. Если изменилось:

3.1. Зажечь светодиод.

3.2. Запомеить в той же переменной новое состояние.

3.3. Запомнить текущее время (во второй переменной).

4. Проверить, не пора ли выключать светодиод.

Самое главное, алгоритм абсолютно нечувствителен к тому, где LOW, а где HIGH, и порядок действий в п.3 не зависит от того, включен ли светодиод.

alexbmd
Offline
Зарегистрирован: 15.01.2016

andriano - сейчас посмотрю ваш алгоритм, а пока улучшил свой

qwone "Дребезг присутсвует" - а так ?

 

 

ledTime = 0;
debounceTime = 0;
expect = !digitalRead(pin1);

loop{

if (digitalRead(pin1) == expect && debounce == 0)
	{
	    debounce = 1;
	      expect = !expect;
	debounceTime = millis();
	     ledTime = millis();
	digitalWrite(pinLED, 1);
	}

if (debounce == 1 && millis() - debounceTime > 60) {debounce = 0;}

if (digitalRead(pinLED) == 1 && millis() - ledTime > 60000) {digitalWrite(pinLED, 0);}

}

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

andriano

если я правильно понял ваш алгоритм он очень близок к моему ?

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

alexbmd пишет:

qwone "Дребезг присутсвует" - а так ?

Вы напоминаете мне чукчу из анекдота

Два чукчи подходят к начальнику поезда.
Первый:
- Этот поезд довезет меня до Ленинграда?
- Нет.
Второй:
- А меня?

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

/* millis_1btn_1TimeRelay.ino
  //#1 реле
  реле 1  -> 12(relay1_pin) 1 включено / 0 выключено
  //#2 кнопка
  кнопка  -> 10 (btn1_pin) 0  нажата / 1 нет
  Принцип кода: реле работает только 3 секунды после нажатия
*/
//#1 реле
const int relay1_pin = 12;// нога реле
bool relay1;// состояние реле
const uint32_t TimeOFF = 3 * 1000; // время отключения
//#2 кнопка
const int btn1_pin = 10;
bool btn1, btn1_old; //нажатие кнопки
bool bounce_btn1 = 0; // антидребезговый флаг
void setup() {
  //#1 реле
  pinMode(relay1_pin, OUTPUT); // подключить реле
  digitalWrite(relay1_pin, relay1 = 0); // и выключить
  //#2 кнопка
  pinMode(btn1_pin, INPUT_PULLUP);
  btn1 = digitalRead(btn1_pin);
}
void loop() {
  //#1 реле
  static uint32_t past_1 = 0 ;
  if (relay1 && millis() - past_1 >= TimeOFF ) // если реле вкл и подошло время выключить
    digitalWrite(relay1_pin, relay1 = 0); // то его выключить

  //#2 кнопка использует дебонс
  static uint32_t past_2 = 0 ;
  if (! bounce_btn1 && btn1 != digitalRead(btn1_pin)) { // если прошел фронт изм на выводн
    bounce_btn1 = 1;                                 // выставить флаг
    past_2 = millis();                          // сделать временую отметку
  }
  else if ( bounce_btn1 && millis() - past_2 >= 5 ) { // если прошло антидребезговое время 5 ms
    bounce_btn1 = 0;      // то снять флаг
    btn1_old = btn1;
    btn1 = digitalRead(btn1_pin) ; // прочитать реальное значение на выводе
    if (btn1_old && ! btn1 && ! relay1) {      // если обнаружилось что это было нажатие и реле не вкл
      past_1 = millis(); // выставить отметку
      digitalWrite(relay1_pin, relay1 = 1); // и включить реле
    }
  }
}

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

 

qwone

[не обращайте внимание на сек, мсек и примем что скетчи у нас делают одно и тоже кроме способа зажигания и проверки дребезга]

да в моем случе мы сразу выполняем необходимое действие по нажатию кнопки, но тут же защищаем себя от дребезга, т.е. диод зажгется сразу на N секунде [время нажатия кнопки].  а второй раз мы его сможем зажечь только на N+5 секунде.

в вашем же примере мы зажигаем диод на N+5 секунде. т.е. при прочих равных в вашем варианте диод загорится на 5 секунд позже чем у меня и всё остальное одинаково. 

и теперь главный вопрос - в чем выигрыш [чем лучше] зажигать на 5 секунд позже ? когда все остальное у нас одинаково

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

alexbmd, я не хочу доказывать вам что-то. Я не хочу быть вам бесплатным репетитором. Работает ваша программа, вас она устраивает. Меня это устраивает. А то что мой скетч зажигает на 5 минут позже, то скорее вы (1) не так собрали схему, (2) не так настроили программу и т д. И просвещать как и почему , на это у меня нет времени.

alexbmd
Offline
Зарегистрирован: 15.01.2016

qwone

 так схемы програмы и прочее у нас одинаково (для простоты понимания) разница только в коде дребезга.

исходя из вашего кода вы производите действие только после 5.  && millis() - past_2 >= 5

и я не осуждал и не спорил с вами а только спросил - чем это лучше ? что мы не сразу стартуем (как у меня) а с задержкой?

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

Ну а вдруг на пине помеха, короткий импульс меньше нажатия. По вашему коду будет подсчет, а у меня игнор. Для маленьких программ это не критично. А вот ловить глюки в большом и сложном тяжеловато.  Вы заметили, что я пытаюсь создавать классы в подключаемых файлах. Это упрощает отладку программы.

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

alexbmd пишет:

разница только в коде дребезга.

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

изменение состояния пина кнопки программно фиксируется, если фильтр дребезга неактивен.
изменение состояния пина кнопки активирует фильтр дребезга.
т.е.
если фильтр дребезга неактивен, то изменение состояния пина кнопки фиксируется немедленно.
если фильтр дребезга активен, то изменение состояния пина кнопки фиксируется после того, как фильтр дребезга отработал и неактивен(см. первую строку)
alexbmd
Offline
Зарегистрирован: 15.01.2016

 "если фильтр дребезга неактивен" 

фильтр программный или железный и что значит неактивен ? 

если мы говорим о программном то что в моем коде что у qwone  и джае в велосипеде он всегда активен (для того они и были рождены), поту неясна формулировка

alexbmd
Offline
Зарегистрирован: 15.01.2016

Клапауций не захотел отвечать, ну да ладно. прито что логика во всех трех случаях (из кода выше, из кода qwone,и из велосипеда) абсолютно одинаково.  о какой ясной формулировке говорилось :)

 

qwone andriano спасибо за наводку.

а есть элегантное решение/хитрость победить сброс millis при переполнении ?

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Удален неуместный политизированный комментарий. 
 

Модератор

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

А тут я просто хамил, а модератор, редиска, стер.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbmd пишет:

а есть элегантное решение/хитрость победить сброс millis при переполнении ?

Есть элегантное решение его (сброс) не замечать (см. blink without delay).

alexbmd
Offline
Зарегистрирован: 15.01.2016

andriano

если я правильно понял  в случае unsigned  он не будет уходить в exception когда вычетаемое больше а коректно считает, вы это имели ввиду ?   нет компилятора сейчас под рукой. 

а то я во избежание exception  дополнительные проверки нагородил а оказывается если я правильно понял все просто :)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbmd, unsigned тут ни при чем. Просто арифметические операции нужно записывать инвариантно относительно потери старшего разряда при переполнении. Т.е. если между двумя отсчетами счетчика возникло переполнение, чтобы оно было скомпенсировано последующей арифметической операцией.

alexbmd
Offline
Зарегистрирован: 15.01.2016

andriano

что значит инвариантно  ?

я в компиляторе с++ (ардуины нету пока)   провел вычетание (такое же как обычно когда вычетаемое меньше 60000-59990) но когда вычетаемое больше (5-6550 а-ля переполнение) и получил правильный ответ а не отрицательное число или exception как я предпологал до этого. если также в ардуино то проблемма решена :)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbmd, так компилятор-то один и тот же. Да и двоичная арифметика тоже одна и та же. Так что чему удивляться?

alexbmd
Offline
Зарегистрирован: 15.01.2016

ну лучше уточнить чем потом не понимать где проблемма :)

спасибо за помощь

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

alexbmd пишет:

ну лучше уточнить чем потом не понимать где проблемма :)

в ДНК проблема