Кнопки,Прерывания.
- Войдите на сайт для отправки комментариев
Пт, 26/12/2014 - 00:05
Возможно ли к одному прерыванию подключить несколько кнопок, например 5 штук. И в прерывании определять какая из них была нажата?
Возможно ли к одному прерыванию подключить несколько кнопок, например 5 штук. И в прерывании определять какая из них была нажата?
Можно. Для этого нужно использовать логический элемент ИЛИ, который при упрощении можно свести к кучке диодов. Сигнал с каждой кнопки идет на вывод ардуины и через диод на вывод прерывания. А в прерывании мы проверяем выводы и находим активные.
аналоговую кнопку сделайте. Каждой кнопке на ножке будет соответстоввать свое напряжение. АЦП снимаете уровень. Хватит 1 ножки арудины
аналоговую кнопку сделайте. Каждой кнопке на ножке будет соответстоввать свое напряжение. АЦП снимаете уровень. Хватит 1 ножки арудины
А прерывания куда?
Можно. Для этого нужно использовать логический элемент ИЛИ, который при упрощении можно свести к кучке диодов. Сигнал с каждой кнопки идет на вывод ардуины и через диод на вывод прерывания. А в прерывании мы проверяем выводы и находим активные.
Эту микросхему получится прикрутить?
74HC597
1)Аналоговую клаву делал, только как к прерыванию ее "прикрепить"?
2)
на каждую кнопку по выходу=расточительство
С дребезгом тригером Шмидта можно бороться.
Все равно иногда бывает лишнее нажатие. Что я делаю не так)? Может как-то программно бороться можно?
Это просто пример, по которому я определяю был дребезг или нет.
byte intPin = 0; byte ledPin = 13; volatile int x = 0; boolean LED=true; void setup() { attachInterrupt(intPin,pause,RISING);. pinMode(ledPin, OUTPUT); pinMode(7, INPUT); pinMode(9, INPUT); Serial.begin(9600); } void pause() { int i=0; while(i <70) {i++; } LED=!LED; // включаем/выключаем LED if ((digitalRead(7)==LOW)and(digitalRead(9)==HIGH)) { x=x-1; Serial.println(x); } else if ((digitalRead(7)==HIGH)and(digitalRead(9)==LOW)) { x=x+1; Serial.println(x); } if ((digitalRead(7)==HIGH)and(digitalRead(9)==HIGH)) { Serial.println(x); } } void loop() { digitalWrite(ledPin,LED); }frielender, можно сделать прерывание по таймеру скажем раз в секунду, и в прерывании опрашивать кнопки. Тогда проблемы дребезга скорее всего не будет. Если с таймерами не очень дружите, то можно взять готовую библу типа timerOne.
Спасибо за ответы, решил проблему с дребезгом. Но появилась другая проблемка...
Программа не выходит из прерывания(Это понятно по светодиоду, который должен менять свое состояние в основной программе)
Я выяснил что это из-за части вывода меню на экран, если выводить что то в Serial, то все работает. В чем может быть проблема? И как мне выводить на экран через прерывание?
<div> #include <Wire.h> #include <LiquidCrystal_I2C.h> byte intPin = 0; // Номер прерывания, которое будет вызыватся.Контакт которому соответствует прерывание 2. byte ledPin = 13; // Светодиод volatile int x = 0; // volotile означает возможность внезапного, для основной программы, изменения переменной. // В данном случае изменение произойдет в прерывании volatile int y = 0; volatile int A = 10; boolean LED=true; //Состояние светодиода // Set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_I2C lcd(0x27, 16, 2); void setup() { attachInterrupt(intPin,pause,RISING); pinMode(ledPin, OUTPUT); pinMode(7, INPUT); pinMode(9, INPUT); Serial.begin(9600); lcd.begin(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("WELCOME!"); } void pause() { int i=0; while(i <70) {i++; } if ((digitalRead(7)==LOW)&&(digitalRead(9)==HIGH))// OK { if((A==10)||(A==20)) A++; else if((A==11)||(A==21)) A--; Serial.println(A); } if ((digitalRead(7)==HIGH)&&(digitalRead(9)==LOW))// - { if(A==20) {A=10;} if(A==11){ x--;} if(A==12){ y--;} Serial.println(A); } if ((digitalRead(7)==HIGH)&&(digitalRead(9)==HIGH))// + { if(A==10) {A=20;} if(A==11){ x++;} if(A==12){ y++;} Serial.println(A); } //////////////////////////////////////////////////////////////////////// Не выходит из прерывания из- за этой части, именно вывода на экран if (A==10) { lcd.clear(); lcd.print("Main Menu"); lcd.setCursor(13,0); lcd.print(">1<"); lcd.setCursor(0,1); lcd.print("Speed"); } if(A==20) { lcd.clear(); lcd.print("Main Menu"); lcd.setCursor(13,0); lcd.print(">2<"); lcd.setCursor(0,1); lcd.print("Animation"); } if(A==11) { lcd.clear(); lcd.print("Speed="); lcd.setCursor(7,0); lcd.print(x); lcd.setCursor(4,1); lcd.print("- OK +"); } if(A==11) { lcd.clear(); lcd.print("Animation#"); lcd.setCursor(11,0); lcd.print(y); lcd.setCursor(4,1); lcd.print("- OK +"); } //////////////////////////////////////////////////////////////////////// } void loop() { digitalWrite(ledPin,HIGH); delay(1000); digitalWrite(ledPin,LOW); delay(1000); } </div>Возможно ли к одному прерыванию подключить несколько кнопок, например 5 штук. И в прерывании определять какая из них была нажата?
PCINT
Может как-то программно бороться можно?
Не только можно, а нужно.
И как мне выводить на экран через прерывание?
bool change = 0; // флаг изменения char dispmem[2][17] = {" "," "}; // то что выводим на дисплей void setup() { //.... attachInterrupt(0, Interrupt, CHANGE); //.... } void loop() { //.... Display(); //.... } void Interrupt() { //.... strcpy(&dispmem[1][4], "WELCOME!"); change = 1; // взводим флаг } void Display() { if(change == 1) // Если есть изменения выводим на дисплей { lcd.setCursor(0,0); lcd.print(dispmem[0]); lcd.setCursor(0,1); lcd.print(dispmem[1]); change = 0; // сбрасываем флаг } }Получается,если у меня в loop программа выполняется 20 сек, то мне придется ждать эти 20 секунд перед обновлением информации выводимой на экран?
Просто не нужно блокировать основной цикл на 20 секунд.
Да и вообще ну сделали вы вывод на дисплей в фоновом режиме, и что дальше? Вот вы изменили скорость чего то там, ну и когда эти измения вступят в силу, если у вас основной цикл длится 20 секунд?
Через 20 секунд вступят в силу мои изменения. Но ведь не раз в 20 секунд экран обновляться будет. Тогда моджно "целый час " что-то настраивать, перемещаясь по меню. Я вероятно что-то не понимаю, но мне казалось что обновление экрана должно быть в момент нажатия на кнопку, а не после выполнения основного цикла. Иначе экран теряет свою актуальность вообще.
Через 20 секунд вступят в силу мои изменения. Но ведь не раз в 20 секунд экран обновляться будет. Тогда моджно "целый час " что-то настраивать, перемещаясь по меню. Я вероятно что-то не понимаю, но мне казалось что обновление экрана должно быть в момент нажатия на кнопку, а не после выполнения основного цикла. Иначе экран теряет свою актуальность вообще.
А это уже зависит от алгоритма, который вы накодите. Здесь, каждый сам кузнец своего счастья.
Накодил) только не работает вывод на экран через прерывание.
Накодил) только не работает вывод на экран через прерывание.
А вывод на экран через прерывание, это знаете ли моветонс. В прерываниях делаются минимально необходимые операции, а уже обсчет, экран и прочие действия в loop()/
В целом это у вас и сделано, только если loop()20 секунд, то как выведет дисплей?
Ошибся, сделано не у вас, у maksim.
Делать по этому же принципу, только дисплей должен выводить информацию регулярно с минимально допустимым интервалом.
и еще, вы упомянули "меню". Конкретизируйте, на каком этапе для вас становится критичной частота вывода на экран?
Как вообще делается меню на устройстве, мб я координально что то делаю не так?
Сейчас вот так, но если программа в loop() будет длинной, и долгой в исполнении , то общение с экраном будет через большие промежутки времени,что не есть хорошо.
#include <Wire.h> #include <LiquidCrystal_I2C.h> byte intPin = 0; byte ledPin = 13; volatile int x = 0; volatile int y = 0; volatile int A = 10; boolean LED=true; boolean klick = 0; LiquidCrystal_I2C lcd(0x27, 16, 2); void setup() { attachInterrupt(intPin,pause,RISING); pinMode(ledPin, OUTPUT); pinMode(7, INPUT); pinMode(9, INPUT); Serial.begin(9600); // initialize the LCD lcd.begin(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("WELCOME!"); } void pause() { int i=0; while(i <70) {i++; } //////////////////////////////////////////////////////////////////////// if ((digitalRead(7)==LOW)&&(digitalRead(9)==HIGH))// OK { if((A==10)||(A==20)) A++; else if((A==11)||(A==21)) A--; Serial.println(A); } if ((digitalRead(7)==HIGH)&&(digitalRead(9)==LOW))// - { if(A==20) {A=10;} if(A==11){ x--;} if(A==21){ y--;} Serial.println(A); } if ((digitalRead(7)==HIGH)&&(digitalRead(9)==HIGH))// + { if(A==10) {A=20;} if(A==11){ x++;} if(A==21){ y++;} Serial.println(A); } klick = 1; } void button(){ if(klick == 1) { if (A==10) { lcd.clear(); lcd.print("Main Menu"); lcd.setCursor(13,0); lcd.print(">1<"); lcd.setCursor(0,1); lcd.print("Speed"); } if(A==20) { lcd.clear(); lcd.print("Main Menu"); lcd.setCursor(13,0); lcd.print(">2<"); lcd.setCursor(0,1); lcd.print("Animation"); } if(A==11) { lcd.clear(); lcd.print("Speed="); lcd.setCursor(7,0); lcd.print(x); lcd.setCursor(4,1); lcd.print("- OK +"); } if(A==21) { lcd.clear(); lcd.print("Animation#"); lcd.setCursor(11,0); lcd.print(y); lcd.setCursor(4,1); lcd.print("- OK +"); } klick = 0; } } void loop() { button(); }Честно говоря, вы там начали делать жуткие вещи, мало что загнали в цикл, так еще и печатать оттуда пытаетесь. Пример правильного прерывания вам дал maksim, там необходимый минимум.
По уму, вам надо в прерывании определять сработку кнопки, а все остальное вне его.
Да , я могу наделать ужасных вещей) только начал разбираться в этом.
Да вроде нету у меня цикла в прерывании...
Так тоже не правильно?
#include <Wire.h> #include <LiquidCrystal_I2C.h> byte intPin = 0; // Номер прерывания, которое будет вызыватся.Контакт которому соответствует прерывание 2. byte ledPin = 13; // Светодиод volatile int x = 0; // volotile означает возможность внезапного, для основной программы, изменения переменной. // В данном случае изменение произойдет в прерывании volatile int y = 0; volatile int A = 10; volatile int B = 0; boolean klick = 0; // Set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_I2C lcd(0x27, 16, 2); // Основные параметры платы. void setup() { attachInterrupt(intPin,pause,RISING); // Параметры прерывания. pinMode(ledPin, OUTPUT); pinMode(7, INPUT); pinMode(9, INPUT); Serial.begin(9600); // initialize the LCD lcd.begin(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("WELCOME!"); } // Функция которая будет выполнятся при нажатии на кнопку. void pause() { //Определеине какая кнопка была нажата if ((digitalRead(7)==HIGH)&&(digitalRead(9)==LOW)) B=1;// - if ((digitalRead(7)==LOW)&&(digitalRead(9)==HIGH)) B=2;// OK if ((digitalRead(7)==HIGH)&&(digitalRead(9)==HIGH))B=3;// + klick = 1; } // Основная программа. void button(){ if(klick == 1) { // Определения в каком месте меню нахожусь if (B==1) { if(A==20) {A=10;} if(A==11){ x--;} if(A==21){ y--;} } if (B==2) { if((A==10)||(A==20)) A++; else if((A==11)||(A==21)) A--; } if (B==3) { if(A==10) {A=20;} if(A==11){ x++;} if(A==21){ y++;} } //Вывод на дисплей пункт меню, в котором нахожусь if (A==10) { lcd.clear(); lcd.print("Main Menu"); lcd.setCursor(13,0); lcd.print(">1<"); lcd.setCursor(0,1); lcd.print("Speed"); } if(A==20) { lcd.clear(); lcd.print("Main Menu"); lcd.setCursor(13,0); lcd.print(">2<"); lcd.setCursor(0,1); lcd.print("Animation"); } if(A==11) { lcd.clear(); lcd.print("Speed="); lcd.setCursor(7,0); lcd.print(x); lcd.setCursor(4,1); lcd.print("- OK +"); } if(A==21) { lcd.clear(); lcd.print("Animation#"); lcd.setCursor(11,0); lcd.print(y); lcd.setCursor(4,1); lcd.print("- OK +"); } klick = 0; } } void loop() { button(); //... }Для наглядности, по такому принципу организовано перемещение по меню.
А что у вас делает строка 33?
033inti=0;while(i <70) {i++; }В целом лучше, но if-ы тоже не есть хорошо.
И еще, вы с кнопками на прерываниях заморочились для тренировки или есть некий сакральный смысл?
*33 строчка, это я нашел на этом форуме, так советовали с дребезгом бороться, но так как у меня уже стоит тригер шмитта, это уже не нужно.
*А как же без ифов определить какая из кнопок нажата?
*И как возможно без прерывания? Если у меня в loop( ) будут выполняться какие-то действия, то нажатия на кнопки контроллер не "увидит".
*33 строчка, это я нашел на этом форуме, так советовали с дребезгом бороться, но так как у меня уже стоит тригер шмитта, это уже не нужно.
*А как же без ифов определить какая из кнопок нажата?
*А как возможно без прерывания? Если у меня в loop( ) будут выполняться какие-то действия, то нажатия на кнопки контроллер не "увидит".
При нормальном loop() кнопки будут определятся без проблем. Прерывания обычно используют для быстротекущих процессов, нажатие кнопки к ним не относится. Не используйте delay(), входите в функции обработки по мере надобности (тайминги) и цикл будет проходить быстро.
Сейчас по вашей логике получается, что при каждом проходе loop() вы запрыгиваете в меню. Зачем? Меню это отдельная функция и должна вызыватся по какому то действию (пара кнопок нажато, длинное нажатие и т.д.). Если кнопки будут использоватся только для меню, то и исходите из этого. loop() отдельно, меню отдельно. Когда работаете с меню, loop() все равно стоит. Многозадачность это конечно круто, но вряд ли реализуемо.