Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: нажатие кнопки
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
romez777
Здравствуйте,

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

Есть библиотека gpio от производителя чипа с функциями чтения/записи пина и пр. (вообще это нужно сделать под линуксом, на данном этапе это будет демон, в дальнейшем хотелось бы перенести в ядро), но я решил запостить здесь, потому как меня интересует алгоритм.

Т.е. языком псевдокода как это будет выглядеть? Очевидно, нужно проверять состояние пина, и если кнопка нажата, то запускать таймер - но возникает проблема, как отслеживать два разных тайминга - 3сек и 5 ?


Буду очень признателен за идеи и советы !
DpInRock
А они разве разные?
Сначала - событие 3 сек. А уж потом (всегда - ПОТОМ, ибо в пространстве-времени Эйнштейна по-другому не бывает) событие 5 сек.

Счетчик один и тот же, разумеется. Включаем его по нажатию и останавливаем по отжатию. И смотрим.
rezident
Не нужно запускать/останавливать таймер. Таймер должен "тикать" всегда. Ведь интересуют-то относительные временные отсчеты, которые есть разность между временем свершения одного и другого события.
А сама процедура, требуемая топикстартеру, представляет из себя конечный автомат с 4-мя состояниями.
1. Ожидаем нажатия кнопки. Если нажали кнопку - засечка времени, генерируем событие "нажали кнопку". Переход в состояние 2.
2. Следим - отпустили кнопку или нет, если нет, то сравниваем засечку времени с текущим временем, если прошло 3 секунды, генерируем событие "3 секунды" и переход в состояние 3. Если отпустили кнопку, то генерируем событие "кнопку отпустили" и переход в состояние 1.
3. Опять бдим за состоянием кнопки и временем, если кнопка о сих пор нажата и прошло 5 секунд с момента засечки, то генерируем событие "5 секунд" и переходим в состояние 4. Если отпустили кнопку, то генерируем событие "кнопку отпустили" и переход в состояние 1.
4. Далее уже просто слежение за тем когда кнопку отпустят, за временем следить не требуется. При отпускании кнопки генерируем событие "кнопку отпустили" и переход в состояние 1.
Kuzmi4
2 rezident
а как же переполнения таймера ? По моему как раз чтоб о них не думать и нужно запускать/останавливать таймер по нажатию/отжатию ?
rezident
Цитата(Kuzmi4 @ Aug 19 2010, 21:49) *
а как же переполнения таймера ? По моему как раз чтоб о них не думать и нужно запускать/останавливать таймер по нажатию/отжатию ?

Переполнение не играет рояля, если период переполнения таймера превышает самый длительный интервал, который нужно засекать. Если разрядность таймера не удовлетворяет этому условию, то можно ее расширить программно. Но замечу, что вопрос топикстартера был про Линукс, а в Линуксе просто обязан быть счетчик UNIX/POSIX-времени. Отдельный таймер требуется только в том случае, если разрешение в 1 секунду не устраивает и нужна более "мелкая" дискретизация временных отметок (мс, мкс и т.п.)
romez777
rezident, большое спасибо.

Мне сейчас подумалось, а ведь можно обойтись и без таймера, только sleep. Это будет неэффективно, но работать ведь должно smile.gif
777777
Цитата(romez777 @ Aug 19 2010, 12:35) *
программно необходимо читать нажата ли кнопка и если да, то как долго удерживается нажатие (есоли 3сек., то выполнить одно, если 5 сек. то другое).

Общий принцип такой:
Код
    // проверка кнопок
    CButton* pb = &btn[shift_cntr];
    if((PINA & BT1) != 0)
        {
        // отпущена
        pb->PressTime = SysTime;
        if(pb->Pressed != RELEASED)
            pb->Pressed = ((BTN_PROC)pgm_read_word_near(&BtnProc[shift_cntr]))(RELEASED);
        }
    else
        {
        // нажата
        if(pb->Pressed != PRESSED && SysTime - pb->PressTime > 50)
            pb->Pressed = ((BTN_PROC)pgm_read_word_near(&BtnProc[shift_cntr]))(PRESSED);
        }
    }

Во-первых, имеется структура CButtun описывающаю состояние каждой кнопки:
Код
typedef struct tagCButton
{
uint8_t    Pressed;
uint16_t    PressTime;
uint8_t    pad;
enum { RELEASED = 0, PRESSED, WAITING };
} CButton;

btn - массив таких структур, shift_cntr - номер текущей обрабатываемой кнопки.
В структуре содержится состояние кнопки (нажата, отпущена или неопределенной состояние, которое как раз и используется для определения длительных нажатий) и системное время. Если кнопка отпущена, время непрерывно записывается в эту переменную. Когда она нажимается, мы попадаем во вторую половину if'а. Если ее состояние не PRESSED (т.е. отпущена или неопределенное) и разность с текущим системным временем больше некоторого значения, необходимого для подавления дребезга, то вызывается функция обработки данной кнопки. Дальше эта функция может сразу выполнить некоторое действие, вернуть значение PRESSED которое будет записано в ее структуру и благодаря этому она больше не будет вызвана пока ее не отпустят. Если же действие необходимо выполнить через некоторое время, то она может возвращать WAITING до тех пор, пока разность между временем, записанным в ее структуре и системным временем не достигнет требуемого значения. Тогда она возвращает PRESSED и больше не вызывается до отпускания.
sergeeff
Классная программа:

Код
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                      With Repeat Function                            */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                      danni@specs.de                                  */
/*                                                                      */
/************************************************************************/

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU           1000000                   // processor clock frequency
#warning kein F_CPU definiert
#endif

#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            0
#define KEY1            1
#define KEY2            2
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)

#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms

#define LED_DDR         DDRA
#define LED_PORT        PORTA
#define LED0            0
#define LED1            1
#define LED2            2

volatile uint8_t key_state;                                // debounced and inverted key state:
                                                  // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect

volatile uint8_t key_rpt;                                  // key long press and repeat


ISR( TIMER0_OVF_vect )                            // every 10ms
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;

  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms

  i = key_state ^ ~KEY_PIN;                       // key changed ?
  ct0 = ~( ct0 & i );                             // reset or count ct0
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
  i &= ct0 & ct1;                                 // count until roll over ?
  key_state ^= i;                                 // then toggle debounced state
  key_press |= key_state & i;                     // 0->1: key press detect

  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}

///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}

///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}

///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}

///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}

int main( void )
{
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors

  TCCR0 = (1<<CS02)|(1<<CS00);            // divide by 1024
  TIMSK |= 1<<TOIE0;                // enable timer interrupt

  LED_PORT = 0xFF;
  LED_DDR = 0xFF;                    

  sei();

  while(1){
    if( get_key_short( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;

    if( get_key_long( 1<<KEY1 ))
      LED_PORT ^= 1<<LED2;

                                                  // single press and repeat

    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      uint8_t i = LED_PORT;

      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      
    }
  }
}
demiurg_spb
Цитата(sergeeff @ Aug 20 2010, 13:29) *
Классная программа:
На любителя...
ИМХО. Идеологически более правильно использовать буфер клавиатуры и всё свести к стандартным getc putc.
PS: и через этот же буфер можно постить и все остальные сообщения, а не только коды клавиатуры...
sergeeff
Цитата(demiurg_spb @ Aug 20 2010, 13:53) *
На любителя...
ИМХО. Идеологически более правильно использовать буфер клавиатуры и всё свести к стандартнм getch() putch(x).
PS: и через этот же буфер можно постить и сообщения...


Автора интересовало различие короткое/длинное нажатие на кнопку. В приведенном примере все это и реализовано. Чего не может быть в getch() putch(x).
777777
Цитата(demiurg_spb @ Aug 20 2010, 14:53) *
ИМХО. Идеологически более правильно использовать буфер клавиатуры и всё свести к стандартнм getch() putch(x).

Это смотря какой идеологией пользоваться - если ДОСовской, то да - вызвал getch() и висишь там пока кнопка не нажалась. А можно по нажатию кнопки генерировать событие и вызывать в соответствующем классе соответствующий метод... Кстати, только что писал, что не знаю как применить С++ в микроконтроллерах, а вот и пример: в вышеприведенном примере можно структуру CButton расширить до класса, создать для каждой кнопки свой объект, программу обработки сделать виртуальным методом и имплементить для каждой кнопки индивидуальную, и т.п...
demiurg_spb
Можно и не ждать: получил 0 - буфер пуст...

Цитата(sergeeff @ Aug 20 2010, 14:58) *
Автора интересовало различие короткое/длинное нажатие на кнопку. ... Чего не может быть в getch() putch(x).
ещё как может, у меня же сделано:-)
+KEYS_HOLD_OFFSET к коду клавиши - вот Вам и длинное нажатие, оно же и repeat.
sergeeff
Код в студию!
demiurg_spb
Код не отдам! А если есть конкретные вопросы - отвечу с удовольствием:-)
По-моему я достаточно ясно о своей реализации излагаю.
rezident
Цитата(sergeeff @ Aug 20 2010, 16:58) *
Автора интересовало различие короткое/длинное нажатие на кнопку. В приведенном примере все это и реализовано. Чего не может быть в getch() putch(x).

Почему же не может быть? Просто сделайте разные скан-коды для короткого, длинного и супердлинного нажатия одной и той же кнопки.
-JonnS-
Прилагаю вариант реализации кот. почти повторяет алгоритм предложеным rezident. Различает три состояния: нормальное когда кнопка нажата до 1сек, длиное >1сек и <2сек, и сверхдлиное >2сек. Попутно озвучивает нажатие кнопок.
CV 2.03.9, Proteus 7.6 SP0
Ivan Kuznetzov
а если я хочу помимо всего вышеперечисленного отслеживать одновременное нажатие двух кнопок? (иногда необходимо, например, для запуска скрытой функции в устройстве - обновления прошивки например)
demiurg_spb
Достаточно одну кнопку удерживать в момент включения прибора...
rezident
Цитата(Ivan Kuznetzov @ Aug 26 2010, 00:14) *
а если я хочу помимо всего вышеперечисленного отслеживать одновременное нажатие двух кнопок?

Помимо чего "этого"? К какому именно сообщению относится ваш вопрос? Если к моему, то отвечу так: хоть десять, если есть возможность распознавания кратковременного одновременного нажатия нескольких. Для каждой кнопки своя засечка времени делается и вуаля! Конечный автомат для каждой кнопки тот же самый. В одном их моих устройств было 14 кнопок, работающих независимо друг от друга с генерацией автоповтора для каждой из них с индивидуальными паузой и темпом повтора. Кстати, именно для этого случая единственный таймер лучше, чем куча перезапускаемых.
xemul
Цитата(rezident @ Aug 25 2010, 22:43) *
... В одном их моих устройств было 14 кнопок, работающих независимо друг от друга с генерацией автоповтора для каждой из них с индивидуальными паузой и темпом повтора. Кстати, именно для этого случая единственный таймер лучше, чем куча перезапускаемых.

Лучше чем?
Требует меньше ОЗУ? Вряд ли, т.к. под каждую "засечку времени" потребуется переменная разрядностью = разрядности таймера.
По коду меньше? Тоже вряд ли, т.к. вместо инкремента/декремента программных счётчиков (которые могут иметь разрядность меньше разрядности таймера) будет выполняться сравнение (через вычитание) двух чисел разрядностью = разрядности таймера.
Чем-то ещё?

Но судя по упоминанию топикстартером линукса, разрядности таймеров и счётчиков его не будут сильно беспокоить. Тем более, что свою обработку кнопок он собирается вставить в ядро.
777777
Цитата(Ivan Kuznetzov @ Aug 25 2010, 22:14) *
а если я хочу помимо всего вышеперечисленного отслеживать одновременное нажатие двух кнопок? (иногда необходимо, например, для запуска скрытой функции в устройстве - обновления прошивки например)

Тогда можешь воспользоваться моей программой. Функция обработки кнопки всегда может посмотреть состояние других кнопок - отпущены они или нажаты и даже увидеть в течение какого времени.
rezident
Цитата(xemul @ Aug 26 2010, 02:42) *
Лучше чем?

Лучше с точки зрения количества абстракций. Ведь, например, внутри одного прибора не ставят кучу RTC для отсчета времени на каждый узел индивидуально. Я этот этап уже проходил когда-то. Опыт - сын ошибок трудных smile.gif
В первых проектах я делал таймер, который просто инкрементировался на единичку в прерывании. Хватало. Потом где-то стало нужно ориентироваться не просто на абстрактные "тики", а с более определенными единицами времени. Пришлось считать в мс, "тики" подгонять именно под эту единицу времени и инкрементировать счетчик кратно минимальной единице квантования (1мс, 4мс, 10мс, 15мс и т.п.). Потом образовалась некая кучка проектов с примерно одинаковой функциональностью, но с разным количественным набором их. В одном проекте три локальных счетчика, в другом семь, в третьем один. Да забодало! sad.gif В каждом нужно отдельно переписывать таймерное прерывание, хотя функционально оно одинаковое. Так я и пришел к единому таймеру. Мне проще написать одну функцию запроса времени к единому таймеру один раз, чем переписывать ее в каждом проекте под требуемые особенности функциональности.
xemul
Цитата(rezident @ Aug 26 2010, 12:51) *
Лучше с точки зрения количества абстракций. Ведь, например, внутри одного прибора не ставят кучу RTC для отсчета времени на каждый узел индивидуально. Я этот этап уже проходил когда-то. Опыт - сын ошибок трудных smile.gif
В первых проектах я делал таймер, который просто инкрементировался на единичку в прерывании. Хватало. Потом где-то стало нужно ориентироваться не просто на абстрактные "тики", а с более определенными единицами времени. Пришлось считать в мс, "тики" подгонять именно под эту единицу времени и инкрементировать счетчик кратно минимальной единице квантования (1мс, 4мс, 10мс, 15мс и т.п.). Потом образовалась некая кучка проектов с примерно одинаковой функциональностью, но с разным количественным набором их. В одном проекте три локальных счетчика, в другом семь, в третьем один. Да забодало! sad.gif В каждом нужно отдельно переписывать таймерное прерывание, хотя функционально оно одинаковое. Так я и пришел к единому таймеру. Мне проще написать одну функцию запроса времени к единому таймеру один раз, чем переписывать ее в каждом проекте под требуемые особенности функциональности.

Т.е. лучше тем, что стало привычным.
Мне привычнее определить для проекта минимальный требуемый тик, из которого компилятор сделает все производные кванты (достаточно в дефайнах задать Fosc и собственно тик; а квантов-то обычно требуется 2-3-4).
Для таймеров событий мне никогда не требуется абсолютное время (в масштабе коробочки), и эти таймеры я делаю минимально необходимой разрядности. Таймеры запускаются по возникновению события и декрементируются по прошествии требуемого кванта.
Таймер события живёт полем в структуре, другим полем является состояние события. Если событие приключается от дребезжащего (или, н-р, медленно ползущего зашумлённого, или кнопки радиобрелока) входа, то состояние события фильтруется одной и той же функцией, которая вызывается с указателем на поле состояния события и с квантом, требуемым для этого входа.
(я когда-то использовал механизм вертикальных счётчиков by Scott Dattolo, помянутый 777777, но ушёл от него к индивидуальному горизонтальному счётчику, живущему в поле состояния события. Вертикальные счётчики тем не менее удобны для фильтрации многих входов с одинаковой динамикой - н-р, для клавиатуры 4х4).
В моих погремушках с учётом обычно используемых 8-битных контроллеров такой подход получается более экономичным и по ОЗУ, и по ПЗУ.
rezident
Цитата(xemul @ Aug 26 2010, 18:27) *
Т.е. лучше тем, что стало привычным.

Дык, это не религия и я не проповедник, чтобы обращать в нее biggrin.gif Могу еще такой аргумент "за" привести. "Мой" таймер живет в таймерном прерывании один. А все временные отметки могут жить где угодно, хоть в main-е, хоть в любой другой функции. Ваши же старт-стопные таймеры вынуждены жить все вместе в каком-либо таймерном прерывании, либо вам требуется из прерывания вызывать функцию для инкремента поля структуры таймера. Вызов функции в прерывании это доп. накладные расходы. Это я считаю минусом. И немалым. Еще один минус в том, что вам нужно обеспечивать атомарность доступа к содержимому каждого старт-стопного таймера, а мне эту задачу нужно всего лишь для одного таймера решить.
xemul
Цитата(rezident @ Aug 26 2010, 16:52) *
Дык, это не религия и я не проповедник, чтобы обращать в нее biggrin.gif

Я ж тоже не настаиваю - у меня куча более вредных привычек smile.gif.
Цитата
Могу еще такой аргумент "за" привести. "Мой" таймер живет в таймерном прерывании один. А все временные отметки могут жить где угодно, хоть в main-е, хоть в любой другой функции. Ваши же старт-стопные таймеры вынуждены жить все вместе в каком-либо таймерном прерывании, либо вам требуется из прерывания вызывать функцию для инкремента поля структуры таймера. Вызов функции в прерывании это доп. накладные расходы. Это я считаю минусом. И немалым.

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

Угу, с соответствующим оверхедом при каждом обращении к этому одному таймеру.
Ivan Kuznetzov
Цитата(demiurg_spb @ Aug 25 2010, 23:39) *
Достаточно одну кнопку удерживать в момент включения прибора...

нее! а вдруг клиент попой сядет на девайс и запусит программирование - именно две надо чтобы нажато было - как разблокировка на сотовых!
demiurg_spb
Ну пусть сядет. При этом надо чтобы ещё в этот момент передёрнули питание.
По таймауту и выйдет из загрузчика. Ничего "страшного" при этом не произойдёт.

Цитата(Ivan Kuznetzov @ Aug 27 2010, 18:56) *
а вдруг клиент попой сядет
Попы толстые бывают - и сразу несколько кнопок могут охватитьsmile.gif
Не стоит развивать в себе паранойу...
Demeny
Цитата(rezident @ Aug 19 2010, 19:46) *
А сама процедура, требуемая топикстартеру, представляет из себя конечный автомат с 4-мя состояниями.

К сожалению, Ваша процедура не удовлетворяет условию, поставленному автором темы (по нажатию 3 с запускать одно действие, по нажатию 5 с - другое). У Вас трёхсекундное событие генерируется ненужным "бонусом" к пятисекундному.
Тут всё проще - за временем надо следить, когда кнопка уже отпущена, ибо пока она нажата - ничего о времени её нажатия предсказать невозможно. Получается конечный автомат из 2 состояний, которым можно по ходу дела давить и дребезг контактов:
1. Кнопка отпущена. Если кнопка нажата - присваивание переменной Т текущего времени, переход в состояние 2.
2. Кнопка нажата. Если кнопка отжата - вычисление разницы D текущего времени и переменной Т. При D < 500 мс игнорирование нажатия, при 5 c > D > 3 c действие для трёхсекундного нажатия, при D > 5 c действие для пятисекундного нажатия. Переход в состояние 1.
MrYuran
Цитата(xemul @ Aug 26 2010, 18:21) *
В прерывании железного таймера только взводится флаг инкремента таймера программного. Старт-стопные таймеры в прерываниях тем более обрабатывать не требуется (хотя и можно достаточно безболезненно - они обычно 1-байтовые).

А не могли бы вы привести пример кода?
Допустим, в прерывании взвели флаг, пусть он называется TimerTickEvent.
Что и где с ним нужно делать, если у нас, к примеру, заведено одновременно 10 таймеров?
Насколько я понимаю, декрементировать все [ненулевые] таймеры вплоть до нуля, а по нулю запускать обработчик?

Что-то в этом есть...
Хотя я использую метод, на котором настаивает уважаемый rezident
rezident
Цитата(Demeny @ Sep 8 2010, 19:21) *
К сожалению, Ваша процедура не удовлетворяет условию, поставленному автором темы (по нажатию 3 с запускать одно действие, по нажатию 5 с - другое). У Вас трёхсекундное событие генерируется ненужным "бонусом" к пятисекундному.

Ну и что? Пауза 3с всегда короче 5с и возникает раньше второго события. Время штука непрерывная и необратимая.
Цитата(Demeny @ Sep 8 2010, 19:21) *
Тут всё проще - за временем надо следить, когда кнопка уже отпущена, ибо пока она нажата - ничего о времени её нажатия предсказать невозможно.

Вот именно! Событие нужно получить не только за определенный промежуток времени, но и немедленно через этот же промежуток. Зачем нужно 5с событие, которое произошло полчаса назад, когда на кнопку, например, сели попой и заметили это только сейчас? В случае устройства с автономным питанием, которое должно отключаться после 5с удержания кнопки, за полчаса оно может просто "высосать" весь аккумулятор, ожидая когда кнопку отпустят wink.gif
Впрочем топикстартер, думаю, сам разберется какой алгоритм ему больше подходит.
XVR
Цитата
Зачем нужно 5с событие, которое произошло полчаса назад, когда на кнопку, например, сели попой и заметили это только сейчас?
Кстати, это весьма ценное замечание (про 'сели попой')
Реальный случай -
Делали систему управления конференц залом (среди прочего управляемые шторы, экран, проектор, свет). У системы было 4 пульты управления (3 на основе LCD экранчиков с touch screen'ом и один полноразмерный PC). У заказчиков было требование - ко всем этим пультам сделать еще в добавок одну 'тревожную' кнопку - при коротком нажатии на нее должен был включаться свет (если что то не так пойдет в презентации, что бы люди в зале не сидели в темноте), а при длительном - весь зал приводится в исходное состояние (открыть шторы, поднять экран, выключить проектор и т.д.)
Кнопка была сделана, в добавок к кнопке был сделан светодиод для индикации времени нажатия, и был сделан 3й таймаут (как раз из серии 'сели попой') - он индицировался вспышками светодиода.
Заказчик потом долго благодарил за 3й таймаут, когда в процессе одной ОЧЕНЬ важной презентации на кнопку в темноте положили книгу smile.gif
Demeny
Цитата(rezident @ Sep 8 2010, 23:19) *
Ну и что? Пауза 3с всегда короче 5с и возникает раньше второго события. Время штука непрерывная и необратимая.

Тогда объясните, пожалуйста, как в Вашем алгоритме запустить действие (вызвать функцию), которое необходимо выполнять по трёхсекундному удержанию кнопки ? Я думаю, очевидно, что если кнопка удерживается 5 секунд - то трёхсекундное действие выполнять НЕ нужно.
А у Вас событие "кнопка удержана 3 с" формируется даже тогда, когда кнопка удерживается уже 5 с -- вот собственно суть того, с чем я не согласен. Поэтому, на мой взгляд, и логично формировать событие "кнопка удержана 3 с", когда она уже отпущена.
rezident
Цитата(Demeny @ Sep 9 2010, 17:49) *
Тогда объясните, пожалуйста, как в Вашем алгоритме запустить действие (вызвать функцию), которое необходимо выполнять по трёхсекундному удержанию кнопки ? Я думаю, очевидно, что если кнопка удерживается 5 секунд - то трёхсекундное действие выполнять НЕ нужно.

Не нужно - не выполняйте. laughing.gif События разные и (скан-)коды, соответствующие этим событиям, тоже разные. Вас ведь наверное не удивляет, что стандартная клавиатура состоящая из 102 кнопок генерирует больше двух сотен скан-кодов, не так ли? wink.gif По крайней мере каждая клавиша в ней генерирует два скан-конда, один соответствует ее нажатию, а второй ее отпусканию. А еще играет рояль сочетание клавиш.
MrYuran
По "отжатию" не стоит работать ещё и потому, что это очень неприятно для оператора.
Обычно люди отпускают кнопку, реагируя не некое событие (звуковой сигнал, смена картинки и т.д.)
Если этого нет, возникает дискомфорт.
Да и вообще, как узнать, прошли уже 5 секунд, или только 4? А если 4.99?
Так что как минимум аудио-визуальный раздражитель по истечении периода должен быть.
ILYAUL
Цитата(MrYuran @ Sep 9 2010, 16:40) *
По "отжатию" не стоит работать ещё и потому, что это очень неприятно для оператора.

Странно , психологи считают наоборот. И основываются на физиологии нажатия и отпускания кнопки человеком. Но на клавиатуре компа используется и нажатие и отпускание кнопки.
Хотя об этом уже было написано.
AHTOXA
Цитата(ILYAUL @ Sep 9 2010, 22:27) *
Странно , психологи считают наоборот.

Так это небось британские психологи? biggrin.gif
ILYAUL
Цитата(AHTOXA @ Sep 9 2010, 21:56) *
Так это небось британские психологи? biggrin.gif

Вы попробуйте сами оценить как Вы нажимаете кнопки клавиатуры и все поймёте. laughing.gif
rezident
Цитата(ILYAUL @ Sep 9 2010, 22:27) *
Странно , психологи считают наоборот. И основываются на физиологии нажатия и отпускания кнопки человеком.

Ерунда какая-то. Пользователь жмет (увеличивает усилие на) кнопку пока не поймет, что кнопка нажата и устройство ввода восприняло его команду нажатия. Так что на клавиатуре без тактильного эффекта работать по отпусканию вообще невозможно. Пользователь через пять минут весь исплюется и потребует себе нормальную клаву, которая либо "клик" дает, либо по факту нажатия работает.
Demeny
Цитата(rezident @ Sep 9 2010, 16:20) *
Не нужно - не выполняйте. laughing.gif События разные и (скан-)коды, соответствующие этим событиям, тоже разные. Вас ведь наверное не удивляет, что стандартная клавиатура состоящая из 102 кнопок генерирует больше двух сотен скан-кодов, не так ли? wink.gif

Рассмотрим пример. Кофейный автомат с одной кнопкой. По трёхсекундному нажатию он должен наливать кофе, а по пятисекундному - возвращать клиенту деньги. Проще говоря, короткое нажатие - наливаем кофе (если деньги внесены), длинное нажатие - возврат денег.
Ваш конечный автомат, обслуживающий кнопку, сначала начнёт наливать кофе, а потом вернёт деньги. Как ни крутите - решение о выполняемом действии надо принимать при отпускании кнопки.
MrYuran
Цитата(ILYAUL @ Sep 10 2010, 01:29) *
Вы попробуйте сами оценить как Вы нажимаете кнопки клавиатуры и все поймёте. laughing.gif

Вообще-то, буквы выскакивают при нажатии, а не при отпускании.
А вот инженеры филипса при проектировании радиотрубки руководствовались наверно мнением британских психологов.
При нажатии кнопки раздаётся звук, а при отпускании - появляется цифра на экране.
Бесит этот факт неимоверно. Особенно поначалу.
ILYAUL
Цитата(rezident @ Sep 10 2010, 02:27) *
Ерунда какая-то. Пользователь жмет (увеличивает усилие на) кнопку пока не поймет, что кнопка нажата и устройство ввода восприняло его команду нажатия. Так что на клавиатуре без тактильного эффекта работать по отпусканию вообще невозможно. Пользователь через пять минут весь исплюется и потребует себе нормальную клаву, которая либо "клик" дает, либо по факту нажатия работает.

Я же написал , что клавиатура работает по двойному принципу и нажатие и отпускание.
Их иследования показали , что при нажатии на кнопку , человек производит целую гамму всевозможных действий , т.т "выцеливание кнопки , расчёт силы нажатия (удара) по кнопке , удержание и ещё чего то заумное ( типа , а толи я нажал) то есть напрягаются целлая гамма мышец и мозгового вещества. ( Ищу снова эту статью) . Зато при отжатии , мозги вообще не работают. Не нужны . Мышицы под давлением кнопки раслабляются и все и Вы не отслеживаете чё там с этой кнопкой
AHTOXA
Цитата(MrYuran @ Sep 10 2010, 12:59) *
При нажатии кнопки раздаётся звук, а при отпускании - появляется цифра на экране.

Видимо, там как-то отрабатывается ещё и длинное нажатие. В этом случае иначе -- никак. Хорошо хоть звук сразу.
Цитата(ILYAUL @ Sep 10 2010, 14:33) *
Мышицы под давлением кнопки раслабляются и все и Вы не отслеживаете чё там с этой кнопкой

Шикарное научное объяснение! У британских учёных завёлся достойный последовательsmile.gif
MrYuran
Цитата(AHTOXA @ Sep 10 2010, 12:42) *
Видимо, там как-то отрабатывается ещё и длинное нажатие. В этом случае иначе &mdash; никак. Хорошо хоть звук сразу.

В сотовых трубках тоже отрабатывается длинное нажатие. Однако, цифра выскакивает при нажатии. Если этого не происходит, человек пользователь с непривычки давит ещё раз, в результате дублирование цифры и сочные эпитеты в адрес разработчиков
AHTOXA
Оно там не всегда обрабатывается, а только из режима ожидания. Поэтому цифры появляются сразу, но не все. Первая цифра (когда возможно длинное нажатие) - появляется при отпускании. По крайней мере в тех телефонах, которые у меня были, так.
ЗЫ. Хотя да, можно и по нажатию, а потом стирать...
rezident
Цитата(Demeny @ Sep 10 2010, 12:35) *
Ваш конечный автомат, обслуживающий кнопку, сначала начнёт наливать кофе, а потом вернёт деньги. Как ни крутите - решение о выполняемом действии надо принимать при отпускании кнопки.

Я понял вас. Это немного другой случай. Для него автомат состояний дополняется еще одним состоянием - "отложенное событие 3с". Т.е. если кнопку отпустили после 3с, но до истечения 5с, то генерируется событие 3с. В то время как событие 5с генерируется точно также как и раньше - сразу по истечение 5с интервала нажатия.
kolisnichenko_r
Цитата(ILYAUL @ Sep 10 2010, 11:33) *
Я же написал , что клавиатура работает по двойному принципу и нажатие и отпускание.
Их иследования показали , что при нажатии на кнопку , человек производит целую гамму всевозможных действий , т.т "выцеливание кнопки , расчёт силы нажатия (удара) по кнопке , удержание и ещё чего то заумное ( типа , а толи я нажал) то есть напрягаются целлая гамма мышец и мозгового вещества. ( Ищу снова эту статью) . Зато при отжатии , мозги вообще не работают. Не нужны . Мышицы под давлением кнопки раслабляются и все и Вы не отслеживаете чё там с этой кнопкой

А статейку не нашли? Интересно почитать.
ILYAUL
Цитата(kolisnichenko_r @ Sep 14 2010, 12:33) *
А статейку не нашли? Интересно почитать.

Нашёл. Оказалось не в инете , а в книжке вычитал - Юрий Ревич " Практическое программирование микроконтроллеров AVR на языке ассемблера" Думаю ,что ив инете ее можно найти.
AHTOXA
Цитата(ILYAUL @ Sep 14 2010, 22:37) *
Юрий Ревич " Практическое программирование микроконтроллеров AVR на языке ассемблера"

Да уж, знатный психологsmile.gif Но всё же хотелось бы цитату, про отпускание.
ILYAUL
Цитата(AHTOXA @ Sep 14 2010, 20:52) *
Да уж, знатный психологsmile.gif Но всё же хотелось бы цитату, про отпускание.

Вся книга весит 25 мегов
AHTOXA
Так там про мышь, а это совсем другое дело. А про клаву и кнопки как раз написано "по нажатию". И, кстати, - никаких упоминаний о психологах...
Короче, "ниачом".
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.