Кнопки,Прерывания.
- Войдите на сайт для отправки комментариев
Пт, 26/12/2014 - 00:05
Возможно ли к одному прерыванию подключить несколько кнопок, например 5 штук. И в прерывании определять какая из них была нажата?
Возможно ли к одному прерыванию подключить несколько кнопок, например 5 штук. И в прерывании определять какая из них была нажата?
Можно. Для этого нужно использовать логический элемент ИЛИ, который при упрощении можно свести к кучке диодов. Сигнал с каждой кнопки идет на вывод ардуины и через диод на вывод прерывания. А в прерывании мы проверяем выводы и находим активные.
аналоговую кнопку сделайте. Каждой кнопке на ножке будет соответстоввать свое напряжение. АЦП снимаете уровень. Хватит 1 ножки арудины
аналоговую кнопку сделайте. Каждой кнопке на ножке будет соответстоввать свое напряжение. АЦП снимаете уровень. Хватит 1 ножки арудины
А прерывания куда?
Можно. Для этого нужно использовать логический элемент ИЛИ, который при упрощении можно свести к кучке диодов. Сигнал с каждой кнопки идет на вывод ардуины и через диод на вывод прерывания. А в прерывании мы проверяем выводы и находим активные.
Эту микросхему получится прикрутить?
74HC597
1)Аналоговую клаву делал, только как к прерыванию ее "прикрепить"?
2)
на каждую кнопку по выходу=расточительство
С дребезгом тригером Шмидта можно бороться.
Все равно иногда бывает лишнее нажатие. Что я делаю не так)? Может как-то программно бороться можно?
Это просто пример, по которому я определяю был дребезг или нет.
01
byte
intPin = 0;
02
byte
ledPin = 13;
03
volatile
int
x = 0;
04
boolean LED=
true
;
05
06
void
setup
()
07
{
08
attachInterrupt(intPin,pause,RISING);.
09
pinMode(ledPin, OUTPUT);
10
pinMode(7, INPUT);
11
pinMode(9, INPUT);
12
Serial
.begin(9600);
13
}
14
15
16
void
pause()
17
{
18
int
i=0;
19
while
(i <70) {i++; }
20
21
LED=!LED;
// включаем/выключаем LED
22
if
((digitalRead(7)==LOW)and(digitalRead(9)==HIGH))
23
{
24
x=x-1;
25
Serial
.println(x);
26
}
else
27
if
((digitalRead(7)==HIGH)and(digitalRead(9)==LOW))
28
{
29
x=x+1;
30
Serial
.println(x);
31
}
32
if
((digitalRead(7)==HIGH)and(digitalRead(9)==HIGH))
33
{
34
Serial
.println(x);
35
}
36
37
}
38
39
void
loop
()
40
{
41
digitalWrite(ledPin,LED);
42
}
frielender, можно сделать прерывание по таймеру скажем раз в секунду, и в прерывании опрашивать кнопки. Тогда проблемы дребезга скорее всего не будет. Если с таймерами не очень дружите, то можно взять готовую библу типа timerOne.
Спасибо за ответы, решил проблему с дребезгом. Но появилась другая проблемка...
Программа не выходит из прерывания(Это понятно по светодиоду, который должен менять свое состояние в основной программе)
Я выяснил что это из-за части вывода меню на экран, если выводить что то в Serial, то все работает. В чем может быть проблема? И как мне выводить на экран через прерывание?
001
<div>
002
#include <Wire.h>
003
#include <LiquidCrystal_I2C.h>
004
byte
intPin = 0;
// Номер прерывания, которое будет вызыватся.Контакт которому соответствует прерывание 2.
005
byte
ledPin = 13;
// Светодиод
006
volatile
int
x = 0;
// volotile означает возможность внезапного, для основной программы, изменения переменной.
007
// В данном случае изменение произойдет в прерывании
008
volatile
int
y = 0;
009
volatile
int
A = 10;
010
boolean LED=
true
;
//Состояние светодиода
011
// Set the LCD address to 0x27 for a 16 chars and 2 line display
012
LiquidCrystal_I2C lcd(0x27, 16, 2);
013
014
void
setup
()
015
{
016
attachInterrupt(intPin,pause,RISING);
017
pinMode(ledPin, OUTPUT);
018
pinMode(7, INPUT);
019
pinMode(9, INPUT);
020
Serial
.begin(9600);
021
lcd.begin();
022
lcd.backlight();
023
lcd.setCursor(4,0);
024
lcd.print(
"WELCOME!"
);
025
026
}
027
028
029
void
pause()
030
{
031
int
i=0;
032
while
(i <70) {i++; }
033
034
if
((digitalRead(7)==LOW)&&(digitalRead(9)==HIGH))
// OK
035
{
if
((A==10)||(A==20)) A++;
036
else
037
if
((A==11)||(A==21)) A--;
038
Serial
.println(A);
039
}
040
if
((digitalRead(7)==HIGH)&&(digitalRead(9)==LOW))
// -
041
{
042
if
(A==20) {A=10;}
043
if
(A==11){ x--;}
044
if
(A==12){ y--;}
045
Serial
.println(A);
046
}
047
if
((digitalRead(7)==HIGH)&&(digitalRead(9)==HIGH))
// +
048
{
049
if
(A==10) {A=20;}
050
if
(A==11){ x++;}
051
if
(A==12){ y++;}
052
Serial
.println(A);
053
}
054
//////////////////////////////////////////////////////////////////////// Не выходит из прерывания из- за этой части, именно вывода на экран
055
if
(A==10)
056
{ lcd.clear();
057
lcd.print(
"Main Menu"
);
058
lcd.setCursor(13,0);
059
lcd.print(
">1<"
);
060
lcd.setCursor(0,1);
061
lcd.print(
"Speed"
);
062
063
}
064
if
(A==20)
065
{ lcd.clear();
066
lcd.print(
"Main Menu"
);
067
lcd.setCursor(13,0);
068
lcd.print(
">2<"
);
069
lcd.setCursor(0,1);
070
lcd.print(
"Animation"
);
071
}
072
if
(A==11)
073
{ lcd.clear();
074
lcd.print(
"Speed="
);
075
lcd.setCursor(7,0);
076
lcd.print(x);
077
lcd.setCursor(4,1);
078
lcd.print(
"- OK +"
);
079
}
080
if
(A==11)
081
{ lcd.clear();
082
lcd.print(
"Animation#"
);
083
lcd.setCursor(11,0);
084
lcd.print(y);
085
lcd.setCursor(4,1);
086
lcd.print(
"- OK +"
);
087
}
088
089
////////////////////////////////////////////////////////////////////////
090
}
091
092
void
loop
()
093
{
094
digitalWrite(ledPin,HIGH);
095
delay(1000);
096
digitalWrite(ledPin,LOW);
097
delay(1000);
098
099
}
100
101
102
</div>
Возможно ли к одному прерыванию подключить несколько кнопок, например 5 штук. И в прерывании определять какая из них была нажата?
PCINT
Может как-то программно бороться можно?
Не только можно, а нужно.
И как мне выводить на экран через прерывание?
01
bool
change = 0;
// флаг изменения
02
char
dispmem[2][17] = {
" "
,
" "
};
// то что выводим на дисплей
03
04
void
setup
()
05
{
06
//....
07
attachInterrupt(0, Interrupt, CHANGE);
08
//....
09
}
10
11
void
loop
()
12
{
13
//....
14
Display();
15
//....
16
}
17
18
void
Interrupt()
19
{
20
//....
21
strcpy(&dispmem[1][4],
"WELCOME!"
);
22
change = 1;
// взводим флаг
23
}
24
25
void
Display()
26
{
27
if
(change == 1)
// Если есть изменения выводим на дисплей
28
{
29
lcd.setCursor(0,0);
30
lcd.print(dispmem[0]);
31
lcd.setCursor(0,1);
32
lcd.print(dispmem[1]);
33
change = 0;
// сбрасываем флаг
34
}
35
}
Получается,если у меня в loop программа выполняется 20 сек, то мне придется ждать эти 20 секунд перед обновлением информации выводимой на экран?
Просто не нужно блокировать основной цикл на 20 секунд.
Да и вообще ну сделали вы вывод на дисплей в фоновом режиме, и что дальше? Вот вы изменили скорость чего то там, ну и когда эти измения вступят в силу, если у вас основной цикл длится 20 секунд?
Через 20 секунд вступят в силу мои изменения. Но ведь не раз в 20 секунд экран обновляться будет. Тогда моджно "целый час " что-то настраивать, перемещаясь по меню. Я вероятно что-то не понимаю, но мне казалось что обновление экрана должно быть в момент нажатия на кнопку, а не после выполнения основного цикла. Иначе экран теряет свою актуальность вообще.
Через 20 секунд вступят в силу мои изменения. Но ведь не раз в 20 секунд экран обновляться будет. Тогда моджно "целый час " что-то настраивать, перемещаясь по меню. Я вероятно что-то не понимаю, но мне казалось что обновление экрана должно быть в момент нажатия на кнопку, а не после выполнения основного цикла. Иначе экран теряет свою актуальность вообще.
А это уже зависит от алгоритма, который вы накодите. Здесь, каждый сам кузнец своего счастья.
Накодил) только не работает вывод на экран через прерывание.
Накодил) только не работает вывод на экран через прерывание.
А вывод на экран через прерывание, это знаете ли моветонс. В прерываниях делаются минимально необходимые операции, а уже обсчет, экран и прочие действия в loop()/
В целом это у вас и сделано, только если loop()20 секунд, то как выведет дисплей?
Ошибся, сделано не у вас, у maksim.
Делать по этому же принципу, только дисплей должен выводить информацию регулярно с минимально допустимым интервалом.
и еще, вы упомянули "меню". Конкретизируйте, на каком этапе для вас становится критичной частота вывода на экран?
Как вообще делается меню на устройстве, мб я координально что то делаю не так?
Сейчас вот так, но если программа в loop() будет длинной, и долгой в исполнении , то общение с экраном будет через большие промежутки времени,что не есть хорошо.
001
#include <Wire.h>
002
#include <LiquidCrystal_I2C.h>
003
byte
intPin = 0;
004
byte
ledPin = 13;
005
volatile
int
x = 0;
006
volatile
int
y = 0;
007
volatile
int
A = 10;
008
boolean LED=
true
;
009
boolean klick = 0;
010
LiquidCrystal_I2C lcd(0x27, 16, 2);
011
012
void
setup
()
013
{
014
attachInterrupt(intPin,pause,RISING);
015
pinMode(ledPin, OUTPUT);
016
pinMode(7, INPUT);
017
pinMode(9, INPUT);
018
Serial
.begin(9600);
019
// initialize the LCD
020
lcd.begin();
021
lcd.backlight();
022
lcd.setCursor(4,0);
023
lcd.print(
"WELCOME!"
);
024
025
}
026
027
028
void
pause()
029
{
030
int
i=0;
031
while
(i <70) {i++; }
032
////////////////////////////////////////////////////////////////////////
033
if
((digitalRead(7)==LOW)&&(digitalRead(9)==HIGH))
// OK
034
{
if
((A==10)||(A==20)) A++;
035
else
036
if
((A==11)||(A==21)) A--;
037
Serial
.println(A);
038
}
039
if
((digitalRead(7)==HIGH)&&(digitalRead(9)==LOW))
// -
040
{
041
if
(A==20) {A=10;}
042
if
(A==11){ x--;}
043
if
(A==21){ y--;}
044
Serial
.println(A);
045
}
046
if
((digitalRead(7)==HIGH)&&(digitalRead(9)==HIGH))
// +
047
{
048
if
(A==10) {A=20;}
049
if
(A==11){ x++;}
050
if
(A==21){ y++;}
051
Serial
.println(A);
052
}
053
klick = 1;
054
055
}
056
057
void
button(){
058
if
(klick == 1)
059
{
060
if
(A==10)
061
{ lcd.clear();
062
lcd.print(
"Main Menu"
);
063
lcd.setCursor(13,0);
064
lcd.print(
">1<"
);
065
lcd.setCursor(0,1);
066
lcd.print(
"Speed"
);
067
068
}
069
if
(A==20)
070
{ lcd.clear();
071
lcd.print(
"Main Menu"
);
072
lcd.setCursor(13,0);
073
lcd.print(
">2<"
);
074
lcd.setCursor(0,1);
075
lcd.print(
"Animation"
);
076
}
077
if
(A==11)
078
{ lcd.clear();
079
lcd.print(
"Speed="
);
080
lcd.setCursor(7,0);
081
lcd.print(x);
082
lcd.setCursor(4,1);
083
lcd.print(
"- OK +"
);
084
}
085
if
(A==21)
086
{ lcd.clear();
087
lcd.print(
"Animation#"
);
088
lcd.setCursor(11,0);
089
lcd.print(y);
090
lcd.setCursor(4,1);
091
lcd.print(
"- OK +"
);
092
}
093
klick = 0;
094
}
095
}
096
void
loop
()
097
{
098
button();
099
100
}
Честно говоря, вы там начали делать жуткие вещи, мало что загнали в цикл, так еще и печатать оттуда пытаетесь. Пример правильного прерывания вам дал maksim, там необходимый минимум.
По уму, вам надо в прерывании определять сработку кнопки, а все остальное вне его.
Да , я могу наделать ужасных вещей) только начал разбираться в этом.
Да вроде нету у меня цикла в прерывании...
Так тоже не правильно?
001
#include <Wire.h>
002
#include <LiquidCrystal_I2C.h>
003
byte
intPin = 0;
// Номер прерывания, которое будет вызыватся.Контакт которому соответствует прерывание 2.
004
byte
ledPin = 13;
// Светодиод
005
volatile
int
x = 0;
// volotile означает возможность внезапного, для основной программы, изменения переменной.
006
// В данном случае изменение произойдет в прерывании
007
volatile
int
y = 0;
008
volatile
int
A = 10;
009
volatile
int
B = 0;
010
boolean klick = 0;
011
// Set the LCD address to 0x27 for a 16 chars and 2 line display
012
LiquidCrystal_I2C lcd(0x27, 16, 2);
013
014
// Основные параметры платы.
015
void
setup
()
016
{
017
attachInterrupt(intPin,pause,RISING);
// Параметры прерывания.
018
pinMode(ledPin, OUTPUT);
019
pinMode(7, INPUT);
020
pinMode(9, INPUT);
021
Serial
.begin(9600);
022
// initialize the LCD
023
lcd.begin();
024
lcd.backlight();
025
lcd.setCursor(4,0);
026
lcd.print(
"WELCOME!"
);
027
028
}
029
030
// Функция которая будет выполнятся при нажатии на кнопку.
031
void
pause()
032
{
033
//Определеине какая кнопка была нажата
034
if
((digitalRead(7)==HIGH)&&(digitalRead(9)==LOW)) B=1;
// -
035
if
((digitalRead(7)==LOW)&&(digitalRead(9)==HIGH)) B=2;
// OK
036
if
((digitalRead(7)==HIGH)&&(digitalRead(9)==HIGH))B=3;
// +
037
klick = 1;
038
039
}
040
// Основная программа.
041
void
button(){
042
043
if
(klick == 1)
044
{
045
// Определения в каком месте меню нахожусь
046
if
(B==1)
047
{
048
if
(A==20) {A=10;}
049
if
(A==11){ x--;}
050
if
(A==21){ y--;}
051
}
052
if
(B==2)
053
{
if
((A==10)||(A==20)) A++;
054
else
055
if
((A==11)||(A==21)) A--;
056
}
057
if
(B==3)
058
{
059
if
(A==10) {A=20;}
060
if
(A==11){ x++;}
061
if
(A==21){ y++;}
062
}
063
//Вывод на дисплей пункт меню, в котором нахожусь
064
if
(A==10)
065
{ lcd.clear();
066
lcd.print(
"Main Menu"
);
067
lcd.setCursor(13,0);
068
lcd.print(
">1<"
);
069
lcd.setCursor(0,1);
070
lcd.print(
"Speed"
);
071
072
}
073
if
(A==20)
074
{ lcd.clear();
075
lcd.print(
"Main Menu"
);
076
lcd.setCursor(13,0);
077
lcd.print(
">2<"
);
078
lcd.setCursor(0,1);
079
lcd.print(
"Animation"
);
080
}
081
if
(A==11)
082
{ lcd.clear();
083
lcd.print(
"Speed="
);
084
lcd.setCursor(7,0);
085
lcd.print(x);
086
lcd.setCursor(4,1);
087
lcd.print(
"- OK +"
);
088
}
089
if
(A==21)
090
{ lcd.clear();
091
lcd.print(
"Animation#"
);
092
lcd.setCursor(11,0);
093
lcd.print(y);
094
lcd.setCursor(4,1);
095
lcd.print(
"- OK +"
);
096
}
097
klick = 0;
098
}
099
}
100
void
loop
()
101
{
102
button();
103
//...
104
}
Для наглядности, по такому принципу организовано перемещение по меню.
А что у вас делает строка 33?
033
int
i=0;
while
(i <70) {i++; }
В целом лучше, но if-ы тоже не есть хорошо.
И еще, вы с кнопками на прерываниях заморочились для тренировки или есть некий сакральный смысл?
*33 строчка, это я нашел на этом форуме, так советовали с дребезгом бороться, но так как у меня уже стоит тригер шмитта, это уже не нужно.
*А как же без ифов определить какая из кнопок нажата?
*И как возможно без прерывания? Если у меня в loop( ) будут выполняться какие-то действия, то нажатия на кнопки контроллер не "увидит".
*33 строчка, это я нашел на этом форуме, так советовали с дребезгом бороться, но так как у меня уже стоит тригер шмитта, это уже не нужно.
*А как же без ифов определить какая из кнопок нажата?
*А как возможно без прерывания? Если у меня в loop( ) будут выполняться какие-то действия, то нажатия на кнопки контроллер не "увидит".
При нормальном loop() кнопки будут определятся без проблем. Прерывания обычно используют для быстротекущих процессов, нажатие кнопки к ним не относится. Не используйте delay(), входите в функции обработки по мере надобности (тайминги) и цикл будет проходить быстро.
Сейчас по вашей логике получается, что при каждом проходе loop() вы запрыгиваете в меню. Зачем? Меню это отдельная функция и должна вызыватся по какому то действию (пара кнопок нажато, длинное нажатие и т.д.). Если кнопки будут использоватся только для меню, то и исходите из этого. loop() отдельно, меню отдельно. Когда работаете с меню, loop() все равно стоит. Многозадачность это конечно круто, но вряд ли реализуемо.