реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> нажатие кнопки, в течение определенного интервала
romez777
сообщение Aug 19 2010, 08:35
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Здравствуйте,

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

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

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


Буду очень признателен за идеи и советы !
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Aug 19 2010, 08:46
Сообщение #2


Гуру
******

Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515



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

Счетчик один и тот же, разумеется. Включаем его по нажатию и останавливаем по отжатию. И смотрим.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
rezident
сообщение Aug 19 2010, 15:46
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Не нужно запускать/останавливать таймер. Таймер должен "тикать" всегда. Ведь интересуют-то относительные временные отсчеты, которые есть разность между временем свершения одного и другого события.
А сама процедура, требуемая топикстартеру, представляет из себя конечный автомат с 4-мя состояниями.
1. Ожидаем нажатия кнопки. Если нажали кнопку - засечка времени, генерируем событие "нажали кнопку". Переход в состояние 2.
2. Следим - отпустили кнопку или нет, если нет, то сравниваем засечку времени с текущим временем, если прошло 3 секунды, генерируем событие "3 секунды" и переход в состояние 3. Если отпустили кнопку, то генерируем событие "кнопку отпустили" и переход в состояние 1.
3. Опять бдим за состоянием кнопки и временем, если кнопка о сих пор нажата и прошло 5 секунд с момента засечки, то генерируем событие "5 секунд" и переходим в состояние 4. Если отпустили кнопку, то генерируем событие "кнопку отпустили" и переход в состояние 1.
4. Далее уже просто слежение за тем когда кнопку отпустят, за временем следить не требуется. При отпускании кнопки генерируем событие "кнопку отпустили" и переход в состояние 1.
Go to the top of the page
 
+Quote Post
Kuzmi4
сообщение Aug 19 2010, 15:49
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 304
Регистрация: 13-02-07
Из: 55°55′5″ 37°52′16″
Пользователь №: 25 329



2 rezident
а как же переполнения таймера ? По моему как раз чтоб о них не думать и нужно запускать/останавливать таймер по нажатию/отжатию ?
Go to the top of the page
 
+Quote Post
rezident
сообщение Aug 19 2010, 16:15
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Kuzmi4 @ Aug 19 2010, 21:49) *
а как же переполнения таймера ? По моему как раз чтоб о них не думать и нужно запускать/останавливать таймер по нажатию/отжатию ?

Переполнение не играет рояля, если период переполнения таймера превышает самый длительный интервал, который нужно засекать. Если разрядность таймера не удовлетворяет этому условию, то можно ее расширить программно. Но замечу, что вопрос топикстартера был про Линукс, а в Линуксе просто обязан быть счетчик UNIX/POSIX-времени. Отдельный таймер требуется только в том случае, если разрешение в 1 секунду не устраивает и нужна более "мелкая" дискретизация временных отметок (мс, мкс и т.п.)
Go to the top of the page
 
+Quote Post
romez777
сообщение Aug 20 2010, 04:13
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



rezident, большое спасибо.

Мне сейчас подумалось, а ведь можно обойтись и без таймера, только sleep. Это будет неэффективно, но работать ведь должно smile.gif
Go to the top of the page
 
+Quote Post
777777
сообщение Aug 20 2010, 09:06
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(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 и больше не вызывается до отпускания.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Aug 20 2010, 09:29
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Классная программа:

Код
/************************************************************************/
/*                                                                      */
/*                      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;      
    }
  }
}
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Aug 20 2010, 10:53
Сообщение #9


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(sergeeff @ Aug 20 2010, 13:29) *
Классная программа:
На любителя...
ИМХО. Идеологически более правильно использовать буфер клавиатуры и всё свести к стандартным getc putc.
PS: и через этот же буфер можно постить и все остальные сообщения, а не только коды клавиатуры...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Aug 20 2010, 10:58
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(demiurg_spb @ Aug 20 2010, 13:53) *
На любителя...
ИМХО. Идеологически более правильно использовать буфер клавиатуры и всё свести к стандартнм getch() putch(x).
PS: и через этот же буфер можно постить и сообщения...


Автора интересовало различие короткое/длинное нажатие на кнопку. В приведенном примере все это и реализовано. Чего не может быть в getch() putch(x).
Go to the top of the page
 
+Quote Post
777777
сообщение Aug 20 2010, 11:04
Сообщение #11


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



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

Это смотря какой идеологией пользоваться - если ДОСовской, то да - вызвал getch() и висишь там пока кнопка не нажалась. А можно по нажатию кнопки генерировать событие и вызывать в соответствующем классе соответствующий метод... Кстати, только что писал, что не знаю как применить С++ в микроконтроллерах, а вот и пример: в вышеприведенном примере можно структуру CButton расширить до класса, создать для каждой кнопки свой объект, программу обработки сделать виртуальным методом и имплементить для каждой кнопки индивидуальную, и т.п...
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Aug 20 2010, 11:15
Сообщение #12


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Можно и не ждать: получил 0 - буфер пуст...

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


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Aug 20 2010, 11:21
Сообщение #13


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Код в студию!
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Aug 20 2010, 11:45
Сообщение #14


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Код не отдам! А если есть конкретные вопросы - отвечу с удовольствием:-)
По-моему я достаточно ясно о своей реализации излагаю.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
rezident
сообщение Aug 20 2010, 11:52
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(sergeeff @ Aug 20 2010, 16:58) *
Автора интересовало различие короткое/длинное нажатие на кнопку. В приведенном примере все это и реализовано. Чего не может быть в getch() putch(x).

Почему же не может быть? Просто сделайте разные скан-коды для короткого, длинного и супердлинного нажатия одной и той же кнопки.
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 11th June 2024 - 02:06
Рейтинг@Mail.ru


Страница сгенерированна за 0.01524 секунд с 7
ELECTRONIX ©2004-2016