Множество кнопок на 1 пине

sirota
Offline
Зарегистрирован: 18.08.2015

Столкнулся с тем что встал остро вопрос в пинах. Готового прям решения не нашел. Ну как поверхностно есть везде, но именно такого что бы взял, вставил в проект и пользуешься нет. Ясно что АЦП мне в помощь. Придумал вот такой код:

/*
*   Определяем переменные для кнопок
*/
#define NUM_KEYS 10
int  adc_key_val[NUM_KEYS] = {200, 300, 373, 455, 525, 561, 594, 622, 646, 700};
const int button_pin = 0; //Пин на котором висят кнопки/ Не забыдь поменять настройки в setup()
int button_reapete = 0; //Есть ли повторение кнопки
int button_now = 0; //Какая сейчас нажата кнопка
const int button_count_reapete = 5000;
int button_cycle = 0; //Цикл для проверки кнопок
const int button_check_cycle = 5; //Через сколько циклов проверять нажатие кнопок

//Проверяем нажата ли какая кнопка, если нажата, возвращаем код АЦП
int temp_get_key(int key_pin)
{
  return analogRead(key_pin);
}

//Проверяем нажата ли какая кнопка, если нажата, возвращаем ее номер
//После использования сразу нужно скинуть нажатие
int get_key(int key_pin)
{
  int input = analogRead(key_pin);
  if (input > adc_key_val[NUM_KEYS - 1])
  return 0;
  int k;
  for (k = 0; k < NUM_KEYS; k++)
  if (input <= adc_key_val[k])
  return k + 1;
}

//Нажата ли кнопка, если нажата, возвращается 1 и в now_button помещается номер нажатой кнопки,
//и проверяется тип нажатия. Если нажата кнопка быстро, то  button_reapete=0, иначе 1
int button(int button_check_pin) {
button_cycle++;
if (button_cycle > button_check_cycle) {
button_cycle=0;
  int button_count = 0;
  button_now = get_key(button_check_pin);
  if (button_now > 0) {      
      //На время отладочных работ используем:
      /*
      button_reapete = 0;
      while (get_key(button_check_pin) == button_now) ;
      if (button_now==2) {
        if (_setup==0) {_setup=1; button_reapete = 1;}
        //else {_setup_now++; if (_setup_now>_setup_now_count) _setup_now=0;}
      }
      return 1;
      */
      //В работе дожен использоватся код:
      ///*
      while (get_key(button_check_pin) == button_now) {
        button_count++;
      }
      if (button_count >= button_count_reapete) button_reapete = 1;
      else button_reapete = 0;
      return 1;
      //*/

  }//if (result > 0)
  button_now = 0;
}
  return 0;
}

temp_get_key - для теста. Возвращает значение АЦП.

get_key - возвращает уже номер кнопки непосредственно. 0 - если ни чего не нажато

button - если вернуло 1 - значит нажали что-то, если вернули 0, то ни чего не нажали. При 1 в:

button_reapete - долгое или нет нажатие.
button_now - Нажатая кнопка
button_count_reapete - количество циклов определающее долгое или короткое нажатие. 5000 - примерно 1 секунда.
 
В setup():
analogReference(EXTERNAL);

и питание естестенно на AREF отдельное. так как мне кажется проще.

 
 
void main_button() {
  if (button(button_pin) == 1) {
    switch (button_now) {
      case 1: {
          if (button_reapete == 0) { //без задержки
          }
else
{ //С задержкой

}
          break;
        } //case 0:
}
}

main_button - непосредственно сам опрос.

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

У меня вся работа с кнопками в этой функции. И я не парюсь.

Если нужна проверка в нескольких местах и конкретно на нужную кнопку, то ни кто нам не заперит:

if (button(button_pin) == 1 && button_now==1 && button_reapete == 0) {}

Т.е. непосредственно - нажата кнопка 1 коротким нажатием.

Еще планирую вывести отдельно кнопки у которых не будет долгих нажатий, т.е. цикл  

while (get_key(button_check_pin) == button_now) {
        button_count++;
      }

Будет игнорироваться. Единственное нужно добавить возможно счетчик нажатий и возможность включать задержку на повторения. Т.е. скажем нажал на кнопку увеличиваую i на 1, и она не со скростью 16MHz увеличилась в небеса, а скажем регистрация нажатия будет тоьлко раз в настраиваемый промежуток времени. Но это позже. Потом можно и отдельной библиотекой забабахать.

Собственно вопрос - может кто подскажет что переделать для облегчения и ускорения? Я имею ввиду алгоритм? С типами данных еще не оптимизировал, там все в int хотя читай ни кому int'ом там быть вовсе и не нужно.

Принципиальная схема:

Критика приветствуется.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Проходил через это, в итоге завязал с аналоговыми кнопками навсегда. 

Для проминьки:

Использую i2c расширитель PCF8574 и это , одновременно в идвасю подключаю дисплей .

Под всё это есть рабочие , стабильные библиотеки. Расходуется только два пина , какие там по железу под идвасю.

Дополнительно в пин прерывания сажаю кнопку для вода в меню.

Недостаток всего этого медленная относительно параллельного подключения работа дисплея, если отображать динамику.

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