Однолуповая кнопка

Вопросы не вошедшие в форумы из категории
Oleg M.
Сообщения: 4
Зарегистрирован: 18 апр 2017, 11:59

Однолуповая кнопка

Сообщение Oleg M. » 23 июн 2017, 16:59

Всем привет!

Полку кнопок прибыло.
При работе нед одним проектом столкнулся с необходимостью уменьшать/увеличивать технологическую переменную на один шаг при нажатии кнопки.
Если использовать обычную кнопку, то часто возникает ситуация неконтролируемого многократного уменьшения/увеличения параметра, пока кнопка нажата. Поэтому приходится придумывать разные блокировки таких процессов. Однако оказалось проще "сделать" кнопку, которая бы при достижении условий срабатывания выдавала однократно "Нажата" в текущем лупе.
Следующее срабатывание такой кнопки возможно только после ее отпускания и последующего нажатия с выполнением условий срабатывания.

Код: Выделить всё

// Однолуповая кнопка
// Не забудьте включить монитор порта для контроля работы скетча

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/

#define BUTT    5                                                     // tested Button
#define BEEP   13                                                     // звуковой выход

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/
class Button

{
  public:

    void Set( byte pin, boolean defaultButt, boolean pullup,          // метод начальной установки
              int retention ) ;

    void mScan() ;                                                    // опроса состояния моноимпульсной кнопки
    boolean pressed = false ;                                         // кнопка длительно/хорошо нажата


  private:
    byte     _digitPin ;                                              // номер опрашиваемого цифрового пина
    boolean  _defaultButt ;                                           // исходное состояние кнопки/пина
    boolean  _pullup ;                                                // "подтяжка" ( или нет )
    int      _retention ;                                             // время непрерывного удержания кнопки [ мсек ]

} ;

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/

Button keyTest ;                                                      // объявление кнопки keyTest

unsigned int i = 0 ;                                                  // вспомогательня демо-переменная

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/
void setup() {                                                        // put your setup code here, to run once:

  Serial.begin(9600) ;
  keyTest.Set  ( BUTT, true, true, 200  ) ;                           // нажатие кнопки 200 мсек
  pinMode( BEEP, OUTPUT ) ;                                           // включение биппера/зуммера

}

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/
void loop() {                                                         // put your main code here, to run repeatedly:

  keyTest.mScan () ;

  if (keyTest.pressed) {
    i = i + 1 ;
    tone ( BEEP, 880, 100 ) ;
    Serial.println ( "Button pressed " + String ( i ) ) ;
  }

  delay( 1 ) ;

}



/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/
/*
   Методы обработки нажатия кнопки и очистки от дребезга
  путем многократного непрерывного в течение заданного интервала времени
                    опроса состояния
*/
/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/

void Button:: Set( byte pin, boolean defaultButt,                     // установка параметров кнопки
                   boolean pullup, int retention )  {

  _digitPin    = pin ;                                                // присвоение номера PIN
  _defaultButt = defaultButt ;                                        // исходное состояние разомкнуто
  _pullup      = pullup ;                                             // подтяжка к ПЛЮС
  _retention   = retention ;                                          // время удержания [ мсек ]

  if (_pullup) {
    pinMode(_digitPin, INPUT_PULLUP) ;
  } else {
    pinMode(_digitPin, INPUT) ;
  }
}

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/

void Button:: mScan ( ) {                                             // моноимпульсная кнопка

  static boolean _lock ;                                              // параметр "захвата" срабатывания кнопки
  static unsigned long timeClick ;                                    // момент нажатия кнопки [мсек]

  if ( digitalRead( _digitPin) == _defaultButt )   {                  // кнопка в исходном состоянии ОТЖАТО
   
    timeClick = millis() ;                                            // непрерывно запоминаем время вызова
    pressed =  false ;                                                // кнопка не нажата
    _lock = false ;                                                   // "захват" сброшен
  } else {                                                            // НАЖАТО
   
    if ( millis() - timeClick > _retention ) {                        // время прошло -
      if ( !_lock ) {                                                 // проверяем "захват"
       
        _lock = true ;                                                // фиксируем событие захвата
        pressed = true ;                                              // возвращаем состояние ВКЛ
      } else                                                          // в следующем цикле
     
        pressed =  false ;                                            // сбрасываем состояние ВКЛ
    }
  }
}



PS. Может, кто подскажет что нужно сделать, чтобы упростить луп и улучшить читаемость скетча объединив чтение PIN и получение состояния кнопки?

Код: Выделить всё

...
  keyTest.mScan () ;
  if ( keyTest.pressed == true ) {
...


на, предположим, ЭТО

Код: Выделить всё

...
  if ( keyTest () == true )  {
...


Благодарности моей не будет предела в рамках моих скромных возможностей :)


Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Однолуповая кнопка

Сообщение Эдуард » 23 июн 2017, 17:19

Здравствуйте!
Я написал библиотеку Button.h , которая выделяет фронт нажатия кнопки. http://mypractic.ru/urok-9-sozdanie-biblioteki-dlya-arduino.html
Там все эти проблемы решены. Кроме того используется цифровая фильтрация от дребезга и помех.

Oleg M.
Сообщения: 4
Зарегистрирован: 18 апр 2017, 11:59

Re: Однолуповая кнопка

Сообщение Oleg M. » 23 июн 2017, 19:00

Спасибо, Эдуард, за быстрый ответ и полезную ссылку.
Я просмотрел не только этот форум и учебники, но не нашел ответ на мой вопрос.
Например, в Вашей ссылке "Как пользоваться библиотекой" записано так:

Код: Выделить всё

// цикл с периодом 2 мс
void loop() {

  button1.filterAvarage();  // вызов метода фильтрации по среднему для кнопки 1
  button2.scanState();  // вызов метода ожидания стабильного состояния для кнопки 2

 
  // блок управления светодиодом 1
  if ( button1.flagClick == true ) {  // был клик кнопки
    button1.flagClick= false;         // сброс признака
    ledState1= ! ledState1;             // инверсия состояние светодиода
    digitalWrite(LED_1_PIN, ledState1);  // вывод состояния светодиода   
  }
 


То, есть, методы обработки состояния кнопки и получения результата РАЗДЕЛЕНЫ.
Но ведь после окончания метода результат внутри уже есть!
Поэтому я хотел бы, чтобы луп выглядел примерно так:

Код: Выделить всё

// цикл с периодом 2 мс
void loop() {

  if (button1.filterAvarage() == true ) { ..........       ;  // вызов метода фильтрации и РЕЗУЛЬТАТА  по среднему для кнопки 1
 
  if (button2.scanState() == true ) { ...... ;  // вызов метода ожидания стабильного состояния и РЕЗУЛЬТАТА  для кнопки 2
...
 

Тогда бы не было необходимости вызывать раздельно МЕТОД и получать РЕЗУЛЬТАТ метода.
Можно ли научить метод возвращать значения?
Как функция?

Как то так...

Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Однолуповая кнопка

Сообщение Эдуард » 23 июн 2017, 19:30

Я считаю, что обработка сигнала кнопки в параллельной задаче всегда предпочтительна. В цикле loop выполняется основная задача. В параллельном процессе регулярно обрабатывается сигнал кнопки, а основная задача получает результат.
По поводу моей библиотеки для LED индикаторов с динамической индикацией Led4Digits.h люди с удивлением писали, что только в ней разряды индикаторов светятся равномерно, не мигают. Это потому, что управление разрядами происходит регулярно в параллельном процессе. Каждый разряд включен одинаковое время. Может на кнопке это не так заметно, но не менее значимо. Сигнал с кнопки это источник дребезга и помех. Чтобы получить достоверное состояние кнопки надо его обрабатывать (уроки 6, 7 , 8).

Oleg M.
Сообщения: 4
Зарегистрирован: 18 апр 2017, 11:59

Re: Однолуповая кнопка

Сообщение Oleg M. » 23 июн 2017, 22:00

Я не спорю с Вами о пользе распараллеливания процессов, Эдуард, и не подвергаю сомнению качество Ваших библиотек.
Я пытаюсь узнать, возможно ли реализовать в среде Ардуино классы с некоторыми инвариантными функциями, возвращающими значение. Или ссылку на значения.
Решение в "лоб" возможно таким корявым способом:

Код: Выделить всё

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/
//    Функция  чтения состояния кнопки

boolean keyRead ( ) {
  keyTest.mScan () ;
  if ( keyTest.pressed )
    return true ;
  else
    return false ;
}

/*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+*/
void loop() {                                                         // put your main code here, to run repeatedly:

  if (keyRead()) {
    i = i + 1 ;
    tone ( BEEP, 880, 100 ) ;
    Serial.println ( "Button pressed " + String ( i ) ) ;
  }

  delay( 1 ) ;

}



Корявость предложенной функции в том, что для каждой кнопки нужно писать свою функцию, т.е. в решении не инвариантности :(


Вернуться в «Прочее»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 3 гостя