Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить

Re: Помогите опросить кнопку

Сб авг 16, 2014 20:24:38

Дребезг нормироваться не может.... :) ...также он зависит от кол-ва выпитого перед нажатием...)))
40-50 мс - нормальное время для принятия решения об уровне сигнала с ручного механического контакта.

Re: Помогите опросить кнопку

Сб авг 16, 2014 23:03:48

Герконы вообще отличные контакты в плане дребезга, он у них меньше всего. А так у кнопок дребезг сильно зависит от силы нажатия, упругости материала контакта и его чистоты. Для нормальных кнопок дребезг порядка 10мс, у герконов 1-3мс. Герконы более долговечны, поскольку контакты находятся в инертной среде - не окисляются и не подгорают(ибо нечем там, только плавиться).

Re: Помогите опросить кнопку

Вт фев 17, 2015 22:06:17

Alexeyslav писал(а):Если кто найдет более удобную программу для рисования блок-схем, сообщите.

Я рисую в EDGE Diagrammer очень доволен. Еще работал в Diagram Designer

Re: Помогите опросить кнопку

Вт фев 17, 2015 22:11:02

Одна какая-то левая китайская, а другая триальная. Нет счастья в жизни.

Re: Помогите опросить кнопку

Вт фев 17, 2015 22:50:04

Прочитав эту ветку и взяв за основу библиотеку buttons.c решил написать свой опрос кнопок, т.е. изобрести очередной велик :)

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

Планировалась такая структура программы:

Код:
// Timer1 overflow interrupt service routine
ISR(TIMER1_OVF_vect)
   if(ticTimer == 1) {         // таймер тиков для определения временных интервалов короткого, длинного нажатий и автоповтора
      cntTic++;   
   }
}
. . .
main() {
    _delay_ms(500);
   startup();     // Controller configuration
   
   // Global enable interrupts
   sei();
   
   BUT_Init();
   
   while(1) {
      
      FPowerCheck();
      
      switch(Mode) {
         case M_SETUP:   FSetUp();   break;
            
         case M_VIEWUP:   FViewUp();   break;
            
         case M_VIEWDN:   FViewDn();   break;
            
         case M_NORMAL:   FNormal();    break;
      }
   }
}


т.е. в зависимости от текущего режима мы уходим в соответствующую функцию (подпрограмму)

Вот пример одной из подпрограмм:

Код:
/************************************************ FViewDn */
void FViewDn(void){

   // что-то выполняется

   Button();                    // вызываем опрос кнопок
   if( isKey == 1 ) {        // флаг что было нажатие

      if( (keyPress == KEY_UP) || (keyPress == KEY_ENTER) )
         Mode = LastMode;          // меняем текущий режим
         
      _resBut();                     // обнуляем кнопку
   }
}


И все бы хорошо, но есть проблема!
Если сработала, к примеру, кнопка KEY_UP - происходит смена режима. Соответственно при следующем цикле произойдет переход в соответствующую функцию. Так вот, если в этой функции также используется кнопка KEY_UP, то сразу же происходит выполнение соответствующего кода.
Например, долгое нажатие на KEY_UP переходим в режим установки и сразу же начинается увеличение показаний счетчика.
Как сделать чтобы при одном нажатии мы входили в режим установки, а смена показаний была только при следующем нажатии, а не сразу как сейчас? Может кто решал подобную задачу?
Вложения
Keys_v1.c
(5.76 KiB) Скачиваний: 297
Последний раз редактировалось skeef Ср фев 18, 2015 00:44:31, всего редактировалось 1 раз.

Re: Помогите опросить кнопку

Вт фев 17, 2015 22:54:56

Alexeyslav писал(а):Одна какая-то левая китайская, а другая триальная. Нет счастья в жизни.

Могу EDGE скинуть с ключом

Re: Помогите опросить кнопку

Вт фев 17, 2015 23:12:11

Было бы неплохо.

Re: Помогите опросить кнопку

Ср фев 18, 2015 09:48:30

Качай
Главное запомнить три кнопки F3, F4 и F5 :)
Остальное все интуитивно понятно

Re: Помогите опросить кнопку

Пт мар 13, 2015 10:03:12

skeef писал(а):1. По отпусканию кнопки определяется была ли она нажата и было ли короткое или длинное нажатие.
...
Например, долгое нажатие на KEY_UP переходим в режим установки и сразу же начинается увеличение показаний счетчика.
Как сделать чтобы при одном нажатии мы входили в режим установки, а смена показаний была только при следующем нажатии, а не сразу как сейчас? Может кто решал подобную задачу?

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

Re: Помогите опросить кнопку

Вт апр 14, 2015 09:57:01

Вот, как и обещал. :hunger:
Выкусил из своего проекта все лишнее, оставил только то, что надо.
Проект заточен под Tiny13A
Выполнен на Atmel Studio 6.1 (она официально бесплатна)
FUSE: частота 9.6MHz включен SKDIV8
при использовании другого контроллера или частоты, нужно пересчитать константу задержки (_StabKnob в файле defs.inc)
в зависимости от частоты и делителя таймера

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

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

Данный алгоритм рабочий и используется, протестирован с использованием анализатора.
Размер всего кода (FLASH) 156 байт
Вложения
Switch.rar
Обработка кнопки
(8.61 KiB) Скачиваний: 298

Re: Помогите опросить кнопку

Вт апр 14, 2015 22:06:19

Чем это лучше фиксации состояния кнопки по таймеру каждые 10мс?

Re: Помогите опросить кнопку

Ср апр 15, 2015 00:59:02

Alexeyslav писал(а):Чем это лучше фиксации состояния кнопки по таймеру каждые 10мс?


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

В любом случае с моей точки зрения, событийный механизм имеет неоспоримые преимущества в сложных системах.
Давайте представим, что мы обрабатываем не только кнопки, но и LCD 2x16 буфер для которого сканируем
15 раз в секунду и 4 канала ADC с MAV фильтром, также у нас USB соединение с компьютером, который может управлять всем процессом, плюс расчет двух каналов с использованием ПИД алгоритма и все эти прелести в реальном времени. И еще валкодер будем накручивать!
Ну и где тут будет фиксация по таймеру каждые 10 ms? В сложной программе мы рискуем "потерять" нажатие на кнопку, а событие не потеряешь! Даже если два события придут одновременно контроллер все равно обработает и второе тоже и ничего не потеряем. :hunger:

А что лучше или хуже это дело сугубо индивидуальное и зависит от постановки задачи.
Кому-то лучше поставить SN74AHCT14D и забыть про дребезг, а кому-то и SN74AHCT14D не поможет.

Это часть прошлого проекта, все не относящееся к одной кнопке убрано и обработчик сильно упрощен.

А еще можно использовать MikroC, там есть готовые функции с соответствующими входными параметрами
:hunger:

Re: Помогите опросить кнопку

Ср апр 15, 2015 04:32:35

fox15 писал(а):Ну и где тут будет фиксация по таймеру каждые 10 ms? В сложной программе мы рискуем "потерять" нажатие на кнопку, а событие не потеряешь!

Как можно потерять событие, происходящее реже, чем опрос этого события? :dont_know:
В сложной системе достаточно применить один из таймеров как системный и все подобные вещи повесить в обработчике прерываний по этому таймеру. Причем таймер может иметь интервал пересчета (прерываний) соответствующий самым быстрым событиям (например 0,5 мс), а медленные будут обрабатываться через делитель в обработчике (например каждое 16 прерывание или даже реже).
И вообще нужно стараться писать код подобный структуре ОСРВ. С прозрачным разделением ресурсов между задачами.

Re: Помогите опросить кнопку

Ср апр 15, 2015 05:24:17

Так ведь да, 10мс дает тот же таймер по прерыванию и никак его не пропустить. Кнопке вообще безразлично когда её будут проверять, единственное условие - не чаще чем длится потенциальный дребезг который надо подавить. Преимущества - отсутствие сложного алгоритма подавления дребезга, просто считал и все. Сравнил с предыдущим значением и получил такие события как "нажатие" и "отпускание".
С энкодером дело конечно сложнее...

Re: Помогите опросить кнопку

Ср апр 15, 2015 07:12:49

Alexeyslav писал(а):С энкодером дело конечно сложнее...

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

Re: Помогите опросить кнопку

Ср апр 15, 2015 10:41:11

КРАМ писал(а):
Alexeyslav писал(а):С энкодером дело конечно сложнее...

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


Не как обычные кнопки! Там время нужно уменьшать, иначе не комфортно крутить энкодер.
Его же можно крутить не только медленно, но и немного быстрее.
А для кнопок время можно существенно увеличить.

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

С моей точки зрения событийный механизм имеет преимущество :hunger:
Вот я любитель событий и оптимального кода, такой уж я есть. 8)

Кому-то нравится Black Deniels, а кому-то Red Label. :beer:
Это очень хорошо, когда есть много различных предложений.

Re: Помогите опросить кнопку

Ср апр 15, 2015 11:51:00

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

Re: Помогите опросить кнопку

Ср апр 15, 2015 13:09:25

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


обработчик примитивный примерно десяток процессорных команд, обрабатывает только кнопки. Сложности на ровном месте если и есть то только от компаратора, но я ведь не использовал внешний компаратор в противном случае и алгоритм был бы другой или события от внешнего компаратора сидели бы на другом порту (ну сугубо индивидуально вариантов тысяча).
В том то и дело, что рассчитано на неожиданный момент, тут ведь в реальном времени еще и события о пришедших по USB пакетов из компьютера, которые приходят со скоростью 1.2 Мбит/сек (если точнее то UART поверх USB), шесть прерываний используется.
Все это прекрасно работает не конфликтуя и без пропусков.
Я же это выдрал из прошлого своего проекта, который был на Mega88PA. Проверено ведь в реальной работе.
Ну создает немного сложностей из-за самого факта использования механизма прерывания.
Но это ерунда, десяток процессорных инструкций.
А почему не использовать?
Контроллер набит всякими аппаратными "вкусностями" и удобствами и все это обычно не используется.

Re: Помогите опросить кнопку

Пн май 04, 2015 11:57:07

Подскажите, почему не работает 3-я кнопка? Первые две отрабатывают все как надо, а третья ни в какую не хочет нажиматься...

Код:
DDRB = 0b11111000;
PORTB= 0b00000111;


switch(count)
   {
      case 1:
      display = 10;
      break;
      
      case 2:
      display = 20;
      break;
      
      case 3:
      display = 30;
      break;
   }
   
   if(!(PINB&1)) // опрашиваем кнопку 1(+)
   {
      flag1=1; //кнопка нажата (устанавливаем флаг в 1)
      _delay_ms(10); //задержка (защита от дребезга)
   }
   
   if((flag1==1 )&&(PINB&1)) //условие если кнопка была нажата а потом отпущена
   { count++; flag1=0; }  // увеличиваем счетную переменную на единицу и сбрасываем флажок
   
   if(!(PINB&2)) // опрашиваем кнопку 2(+)
   {
      Flag2=1; //кнопка нажата (устанавливаем флаг в 1)
      _delay_ms(10); //задержка (защита от дребезга)
   }
   
   if(( Flag2==1 )&&(PINB&2)) //условие если кнопка была нажата о потом отпущена
   { count--; Flag2=0; } // уменьшаем счетную переменную на единицу и сбрасываем флажок
      
         
   if(!(PINB&3)) // опрашиваем кнопку 3(+)
   {
      flag3=1; //кнопка нажата (устанавливаем флаг в 1)
      _delay_ms(10); //задержка (защита от дребезга)
   }
   
   if(( flag3==1 )&&(PINB&3)) //условие если кнопка была нажата о потом отпущена
   { count++; flag3=0; }
   
        if(count>3) count=1;
   if(count<1) count=3;

Re: Помогите опросить кнопку

Пн май 04, 2015 13:04:53

-=eagle=- писал(а):...а третья ни в какую не хочет нажиматься...

Может надо так?
Код:
   if(!(PINB&4)) // опрашиваем кнопку 3(+)
   {
      flag3=1; //кнопка нажата (устанавливаем флаг в 1)
      _delay_ms(10); //задержка (защита от дребезга)
   }
   
   if(( flag3==1 )&&(PINB&4)) //условие если кнопка была нажата о потом отпущена
   { count++; flag3=0; }

И старайтесь не использовать "магические числа".
Ответить