Длительность и количество нажатий кнопки…???

prosto_andriy
Offline
Зарегистрирован: 09.12.2012

Подскажите, пожалуйста, как проще всего реализовать обработку нажатий кнопки по такому алгоритму:

- одно короткое (меньше 1 с.)  –  переключение первого выхода
- два коротких  с интервалом до 500 мс -  переключение второго
- один длинный (1 с или больше) - переключение третьего
- два длинных (1 с. или больше) с интервалом до 500 мс переключение  четвертого

Знаю, что обработать несколько нажатий (без учета длительности) можно при помощи введения дополнительной переменной – об этом написано тут. А как обрабатывать с учетом длительности нажатия? Подскажите, пожалуйста, если не трудно! Заранее спасибо!
 

Jek
Offline
Зарегистрирован: 05.01.2014

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

prosto_andriy
Offline
Зарегистрирован: 09.12.2012

Большое спасибо за подсказку!!! Код пока ещё не совтавил, но думаю, что понадобится использовать как минимум пять переменных!!!
 

first_button_state  // первоначальное состояние кнопки
button_pressed_flag //флаг, указывающий на то, что кнопка нажата
button_time_interval  // время, по которому можно отсортировать нажатия на короткие/длинные
Short_pressed_counter // счетчик коротких нажатий
Long_pressed_counter  // счетчик длинных нажатий

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

 

faraddin
Offline
Зарегистрирован: 11.08.2013

Вы так над каждой переменной размышляете? Рано Вам еще. Делайте больше переменных, больше кода, потом исправляйте ошибки, анализируйте и упрощайте..

Datak
Offline
Зарегистрирован: 09.10.2014

Отвлекитесь от "двух-длинных-двух-коротких", стремитесь к универсальности. Я бы, например, "ловил" все нажатия кнопки подряд, сохраняя нажатия, и "вдвигая" их в какую-нибудь переменную - "0" для короткого нажатия, "1" для длинного.

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

Только переменную лучше двигать начиная не с нулевого значения, а с 00000001b, иначе не получится отличить, например, одно короткое нажатие от нескольких.

Во, напридумывал. Интересно, понятно что-нибудь? :)

faraddin
Offline
Зарегистрирован: 11.08.2013

В моей, существующей пока только в моей голове, библиотеке по обработке кнопок кнопка это класс, в которой три главные вещи:

байт состояния и истории кнопки (сколько раз было нажато сколько отпущено);

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

prosto_andriy
Offline
Зарегистрирован: 09.12.2012

Datak пишет:

Отвлекитесь от "двух-длинных-двух-коротких", стремитесь к универсальности. Я бы, например, "ловил" все нажатия кнопки подряд, сохраняя нажатия, и "вдвигая" их в какую-нибудь переменную - "0" для короткого нажатия, "1" для длинного.

Большое спасибо Вам за идею! Попробовал написать следуя Вашему совету - набросок кода выглядит так:


int SHORT_BC=0; //Short Button Counter - счетчик кратковременных нажатий 
int LONG_BC=0; // Long Button Counter - счетчик длинных нажатий 
long START_BP_Millis = 0; // Start button pressed - точка начала отчета после нажатия 

void setup()    
 { 
        
     pinMode(13, OUTPUT);         
     pinMode(14, INPUT);
         
 } 

 

 void loop() 

 { 
     if(digitalRead(14)==HIGH)//если нажать кнопку ... 
     { 
	    START_BP_Millis-START_BP_Millis // начинаем отсчет длительности нажатия... с нуля
	  
       if (millis() -long START_BP_Millis < 500)
         { 
       START_BP_Millis = millis();   // счетчик длительности нажатия обнулить для следуещего отсчета  
       SHORT_BC++;                   //  увеличить счетчик кратковременных нажатий 
         } 
        
     
      
         if (millis() -long START_BP_Millis =>500) // и удерживать 0,5 cекунды  или больше...
          { 
           START_BP_Millis = millis();   // счетчик длительности нажатия обнулить для следуещего отсчета  
           LONG_BC++;                   // увеличить счетчик длинных нажатий 
          } 
     
        
      }  
 } 

Можно ли написать ещё проще??? У кого есть какие-нибудь идеи?

Jek
Offline
Зарегистрирован: 05.01.2014

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

И всё-таки наверно лучше использовать не счетчики нажатия, а переменную вида 01101, т. е. короткое-длинное-длиное-короткое-длинное.

prosto_andriy
Offline
Зарегистрирован: 09.12.2012

Согласен! Это сэкономило бы память - хватило бы одного байта! Если в зависомости от длитеьности импульса пропихивать в него 1 или 0  командой (1<<x), увеличивая x в цикле (x++) пока он меньше 8 (x<8).

Насчет кода Вы тоже правы - я допустил несколько ошибок, но уже их исправил (в соответствиями с замечаниями компилятора) теперь компиляция проходит без проблем:

Вот код


int SHORT_BC=0; //Short Button Counter - счетчик кратковременных нажатий 
int LONG_BC=0; // Long Button Counter - счетчик длинных нажатий 
long START_BP_Millis = 0; // Start button pressed - точка начала отчета после нажатия 

void setup()    
 { 
        
     pinMode(13, OUTPUT);         
     pinMode(14, INPUT);
         
 } 

 

 void loop() 

 { 
     if(digitalRead(14)==HIGH)//если нажать кнопку ... 
     { 
	   START_BP_Millis-START_BP_Millis; // начинаем отсчет длительности нажатия... с нуля
	  
       if (millis() - START_BP_Millis < 500)
       
      
         { 
       START_BP_Millis = millis();   // счетчик длительности нажатия обнулить для следуещего отсчета  
       SHORT_BC++;                   //  увеличить счетчик кратковременных нажатий 
         } 
        
     
      
         if (millis() - START_BP_Millis >= 500) // и удерживать 0,5 cекунды  или больше...
          { 
           START_BP_Millis = millis();   // счетчик длительности нажатия обнулить для следуещего отсчета  
           LONG_BC++;                   // увеличить счетчик длинных нажатий 
          } 
     
        
      }  
 } 

 

Jek
Offline
Зарегистрирован: 05.01.2014

Это не для экономии памяти, а для расшифровки введенной команды. Посмотрите азбуку морзе например...

prosto_andriy
Offline
Зарегистрирован: 09.12.2012

А если так:

IF (SHORT_BC==1 && LONG_BC==0)
{
// ...код, который будет выполнен при одном коротком нажатии
{
IF (SHORT_BC==0 && LONG_BC==2)
{
// ...код, который будет выполнен при ввух длинных нажатиях 
{
// .. и т.д.

Что скажете о таком варианте? По-моему нет ничего проще!

 

Dorrin
Offline
Зарегистрирован: 06.12.2014

Есть готовое решение, в нем длина нажатия снимаются от одного до 20 раз подряд, потом усредняются и выводятся в форме MIDI, но вы можете допилить код сами http://gameimho.com/?p=54

satelit
Offline
Зарегистрирован: 12.12.2015

что то я в коде OUTPUT не нашел

prosto_andriy
Offline
Зарегистрирован: 09.12.2012

Datak пишет:

Отвлекитесь от "двух-длинных-двух-коротких", стремитесь к универсальности. Я бы, например, "ловил" все нажатия кнопки подряд, сохраняя нажатия, и "вдвигая" их в какую-нибудь переменную - "0" для короткого нажатия, "1" для длинного.

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

... и обязательно обнуляем переменную! Не так ли?

А можно ли вот так?

  // функция чтения кнопки
 int button_read() { 
	 byte ButtonClics = B00000001; // переменная, в которую записываются нажатия кнопки
	 long button_press_delay; // переменная для проверки длительности нажатия
 if(digitalRead(14)== HIGH) { // если нажатие кнопки обраружено, то...
     button_press_delay = millis; //  начинаем отсчет времени нажатия
       if (button_press_delay - millis > 200) {
		   ButtonClics << 1;  // сдвигаем число влево на одну позицию
	 }
	 if(digitalRead(14)== HIGH) { // если нажатие кнопки обраружено, то...
     button_press_delay = millis; //  начинаем отсчет времени нажатия
       if (button_press_delay - millis > 800) { // если нажатие длительное, то...
		   ButtonClics << 1;   // сдвигаем число влево на одну позицию
		   ButtonClics ++;     // и прибавляем 1
	 }
 else button_press_delay = millis; // ошибочные нажатия и дребезг контактов игнорировать
return ButtonClics
	 

К сожалению я не программист, поэтому не знаю, правильно ли написал!

satelit
Offline
Зарегистрирован: 12.12.2015

вот мне интересную ссылку скинули

https://code.google.com/archive/p/clickbutton/