Множество кнопок на 1 пине
- Войдите на сайт для отправки комментариев
Столкнулся с тем что встал остро вопрос в пинах. Готового прям решения не нашел. Ну как поверхностно есть везде, но именно такого что бы взял, вставил в проект и пользуешься нет. Ясно что АЦП мне в помощь. Придумал вот такой код:
/*
* Определяем переменные для кнопок
*/
#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 в:
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'ом там быть вовсе и не нужно.
Принципиальная схема:

Критика приветствуется.
Проходил через это, в итоге завязал с аналоговыми кнопками навсегда.
Для проминьки:
Использую i2c расширитель PCF8574 и это , одновременно в идвасю подключаю дисплей .
Под всё это есть рабочие , стабильные библиотеки. Расходуется только два пина , какие там по железу под идвасю.
Дополнительно в пин прерывания сажаю кнопку для вода в меню.
Недостаток всего этого медленная относительно параллельного подключения работа дисплея, если отображать динамику.
Однако для коммерческих проектов предпочитаю мегу, там с пинами проблем нет, а разница в цене железа малозначительна по сравнению с удобствами: простой отладкой, меньше кастомного железа, скорость работы.