mire
January 15, 2017, 1:02pm
1
Hallo Zusammen,
momentan beschäftige ich mich mit mehreren Tastern die auf einen Interrupt Pin angeschlossen sind. Dazu hab ich eine Schaltung mit 3 Tastern und 3 Dioden nach einer Anleitung gelötet (hier der Link) . 3 Eingänge (Pin 24-26) und der Interrupt 0 an Pin 2. Bei allen Pins ist der Pull-up-Widerstand aktiviert.
Die Schaltung scheint auch zu funktionieren. Jetzt möchte ich aber möglichst elegant abfragen welcher Taster gedrückt wurde und die Tasten später noch entprellen. Dazu habe ich folgenden Code geschrieben:
const int button[3]={24, 25, 26};
char bName[5];
void setup() {
attachInterrupt(0, pressedBottom, HIGH );
digitalWrite(2, HIGH);
Serial.begin(9600);
pinMode(button, INPUT);
digitalWrite(button, HIGH);
}
void loop() {
}
void pressedBottom()
{
switch (button[0]) {
case 24:
bName[2]="Play";
break;
case 25:
bName[2]="back";
break;
case 26:
bName[2]="next";
break;
}
Serial.println(bName);
}
Kann mir jemand sagen ob dieser Ansatz richitg ist?
Gruß Michael
combie
January 15, 2017, 1:09pm
2
Nein, ist er nicht.
Es fehlen z.B. die zugehörigen digitalRead().
Auch sind serielle Ausgaben in einer ISR eine tödliche Falle.
Und überhaupt, ist das so ziemlich die verrückteste Tastenabfrage, welche mir bisher unter gekommen ist.
Mein Tipp: Ganz schnell wieder vergessen.
Hallo,
"verrückt" ersetze ich mit "total abgefahren" im negativen Sinne. Mehr Aufwand mit weniger Nutzen.
Die Tasten hängen schon je an einem Pin und dann noch einen Interrupt. Geiler gehts nicht.
Das Problem ist, der Erfinder hat nur an Interrupts gedacht und kam wahrscheinlich gedanklich nicht der weg.
In den meisten Fällen wird für Tastenabfragen kein Interrupt benötigt. Nennt sich Polling.
Blockierfrei programmieren und das paßt.
Wenn du gleich was passendes haben möchtest, probiere die "Bounce2" Library und gehe die Bsp. durch
mire
January 15, 2017, 4:01pm
4
Danke für die schnellen Antworten. Ich schätze mal das mit dem Interrupt lass ich mal lieber und probiere morgen die Bounce2 Library aus.
mire
January 25, 2017, 10:30am
5
hallo, da bin ich wieder mit meinen Tastern.
hab mich die letzten Tage mit der Bounce2 Libary beschäftigt und bin jetzt fast an meinem Ziehl.
Nur der Code ist recht umfangreich geworden:
#include <Bounce2.h>
#define BUTTON_PIN_1 22
#define BUTTON_PIN_2 24
#define BUTTON_PIN_3 26
#define BUTTON_PIN_4 28
// Instantiate a Bounce objects
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();
Bounce debouncer4 = Bounce();
unsigned long buttonPressTimeStamp;
int ledState, buttonState;
void setup() {
Serial.begin(9600);
initButtons();
}
void initButtons(){
// Setup the first button with an internal pull-up :
pinMode(BUTTON_PIN_1,INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
debouncer1.attach(BUTTON_PIN_1);
debouncer1.interval(50); // interval in ms
// Setup the second button with an internal pull-up :
pinMode(BUTTON_PIN_2,INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
debouncer2.attach(BUTTON_PIN_2);
debouncer2.interval(50); // interval in ms
// Setup the second button with an internal pull-up :
pinMode(BUTTON_PIN_3,INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
debouncer3.attach(BUTTON_PIN_3);
debouncer3.interval(50); // interval in ms
pinMode(BUTTON_PIN_4,INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
debouncer4.attach(BUTTON_PIN_4);
debouncer4.interval(50); // interval in ms
}
void loop() {
pressedButton(); //Abfrage Bedienknöpfe
long upTime=millis()-buttonPressTimeStamp;
if ( debouncer1.fell() || debouncer2.fell() || debouncer3.fell()|| debouncer4.fell()) {;
//Serial.println( upTime);
buttonPressTimeStamp = millis();
}
// if (upTime == 4000 ) Serial.println("turn OFF"); //Aktion bein nicht benutzen
}
void pressedButton(){
boolean changed = debouncer1.update() || debouncer2.update() || debouncer3.update()|| debouncer4.update();
int value1 = debouncer1.read();
int value2 = debouncer2.read();
int value3 = debouncer3.read();
int value4 = debouncer4.read();
if ( changed ) {
//erster Knopf auswerten
if ( value1 == HIGH) {
ledState = LOW;
buttonState = 0;
Serial.println("Auswahl released (state 0)");
} else {
ledState = HIGH;
buttonState = 1;
Serial.println("Auswahl pressed (state 1)");
buttonPressTimeStamp = millis();
}
}
if ( buttonState == 1 ) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
if ( ledState == HIGH ) ledState = LOW;
else if ( ledState == LOW ) ledState = HIGH;
Serial.println("Retriggering button");
}
}
//zweiter Knopf auswerten
if ( changed ) {
//erster Knopf auswerten
if ( value2 == HIGH) {
ledState = LOW;
buttonState = 0;
Serial.println("Play/Pause released (state 0)");
} else {
ledState = HIGH;
buttonState = 1;
Serial.println("Play/Pause pressed (state 1)");
buttonPressTimeStamp = millis();
}
}
if ( buttonState == 1 ) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
if ( ledState == HIGH ) ledState = LOW;
else if ( ledState == LOW ) ledState = HIGH;
Serial.println("Retriggering button");
}
}
//dritter Knopf auswerten
if ( changed ) {
//erster Knopf auswerten
if ( value3 == HIGH) {
ledState = LOW;
buttonState = 0;
Serial.println("Vor released (state 0)");
} else {
ledState = HIGH;
buttonState = 1;
Serial.println("Vor pressed (state 1)");
buttonPressTimeStamp = millis();
}
}
if ( buttonState == 1 ) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
if ( ledState == HIGH ) ledState = LOW;
else if ( ledState == LOW ) ledState = HIGH;
Serial.println("Retriggering button");
}
}
//vierter Knopf auswerten
if ( changed ) {
//erster Knopf auswerten
if ( value4 == HIGH) {
ledState = LOW;
buttonState = 0;
Serial.println("zurück released (state 0)");
} else {
ledState = HIGH;
buttonState = 1;
Serial.println("zurück pressed (state 1)");
buttonPressTimeStamp = millis();
}
}
if ( buttonState == 1 ) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
if ( ledState == HIGH ) ledState = LOW;
else if ( ledState == LOW ) ledState = HIGH;
Serial.println("Retriggering button");
}
}
}
Das ist bestimmt sehr umständlich geschrieben. Kann mir jemand Tips geben wie man den Code vereinacht?
combie
January 25, 2017, 10:48am
6
Mehrfache Codeduplizierung ist immer fehlerträchtig.
Und Arbeitsintensiv.
Mein Tipp:
Arrays und Schleifen.
mire
January 25, 2017, 12:14pm
7
wie könnte denn so eine Array aussehen?
Ungetestet.
#include <Bounce2.h>
const char tName1[] PROGMEM = "Auswahl";
const char tName2[] PROGMEM = "Play/Pause";
const char tName3[] PROGMEM = "Vor";
const char tName4[] PROGMEM = "Zurueck";
PGM_P const name_table[] PROGMEM = {
tName1,
tName2,
tName3,
tName4
};
const byte pinArray[4] = { 22, 24, 26, 28 };
Bounce Taste[4];
unsigned long buttonPressTimeStamp;
byte ledState, buttonState;
void setup() {
Serial.begin(9600);
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
Taste[i].attach(pinArray[i], INPUT_PULLUP);
Taste[i].interval(50);
}
}
void loop() {
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
if (Taste[i].update()) {
bool state = Taste[i].read();
Serial.print((__FlashStringHelper*)pgm_read_word(&(name_table[i])));
ledState = buttonState = !state;
if (state) {
Serial.println(F(" released (state 0)"));
} else {
Serial.println(F(" pressed (state 1)"));
buttonPressTimeStamp = millis();
}
}
}
if (buttonState) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
ledState = !ledState;
Serial.println(F("Retriggering button"));
}
}
long upTime = millis() - buttonPressTimeStamp;
if ( Taste[0].fell() || Taste[1].fell() || Taste[2].fell() || Taste[3].fell()) {
//Serial.println( upTime);
buttonPressTimeStamp = millis();
}
}
Der Sketch verwendet 2.560 Bytes (8%) des Programmspeicherplatzes. Das Maximum sind 30.720 Bytes.
Globale Variablen verwenden 228 Bytes (11%) des dynamischen Speichers, 1.820 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.
Das Original
Der Sketch verwendet 3.398 Bytes (11%) des Programmspeicherplatzes. Das Maximum sind 30.720 Bytes.
Globale Variablen verwenden 456 Bytes (22%) des dynamischen Speichers, 1.592 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.
mire
January 25, 2017, 12:30pm
9
wow, danke für den kompakten code.
kannst du mir dazu noch etwas erklären?
die Stelle:
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
hierzählst du von 0 bis (4/?)
oder hier:
ledState = buttonState = !state;
was bedeutet diese Zeile mit 2 = ?
sizeof(ArrayObject)/sizeof(ArrayObject[0])
ist ein üblicher Ausdruck um die Anzahl der Arrayelemente zu ermitteln
(Gesamtlänge des Arrays / Länge des ersten Arrayelements).
ledState = buttonState = !state;
Die Auswertung erfolgt von rechts nach links.
Zuweisungen haben den zugewiesenen Wert als "Rückgabewert".
ledState = (buttonState = !state);
Ist vielleicht deutlicher, aber ich bin schreifaul.
combie
January 25, 2017, 12:49pm
11
Eine andere Variante
(stark gekürzt)
#include <Bounce2.h>
struct Button
{
byte pin;
Bounce debouncer;
};
const byte AnzahlButton = 4;
Button MeineButton[AnzahlButton] =
{
{22,Bounce(),},
{24,Bounce(),},
{26,Bounce(),},
{28,Bounce(),},
};
void setup()
{
Serial.begin(9600);
initButtons();
}
void initButtons()
{
for(int i = 0;i<AnzahlButton;i++)
{
pinMode(MeineButton[i].pin,INPUT_PULLUP);
MeineButton[i].debouncer.attach(MeineButton[i].pin);
MeineButton[i].debouncer.interval(50);
}
}
void updateButtons()
{
for(int i = 0;i<AnzahlButton;i++)
MeineButton[i].debouncer.update();
}
void loop()
{
updateButtons();
}
mire
January 25, 2017, 3:40pm
12
ich hab den Code etwas erweitert um Funktionen auf die Tasten zu bringen.
#include <Bounce2.h>
const char tName1[] PROGMEM = "Auswahl";
const char tName2[] PROGMEM = "Play/Pause";
const char tName3[] PROGMEM = "Vor";
const char tName4[] PROGMEM = "Zurueck";
PGM_P const name_table[] PROGMEM = {
tName1,
tName2,
tName3,
tName4
};
const byte pinArray[4] = { 22, 24, 26, 28 };
Bounce Taste[4];
unsigned long buttonPressTimeStamp;
byte ledState, buttonState;
bool retrigger = false;
void setup() {
Serial.begin(9600);
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
Taste[i].attach(pinArray[i], INPUT_PULLUP);
Taste[i].interval(50);
}
}
void loop() {
pressedButton();
long upTime=millis()-buttonPressTimeStamp;
//if (upTime == 4000 ) Serial.println("turn OFF"); //Aktion bein nicht benutzen
}
void pressedButton(){
byte buttonNum = 5;
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
if (Taste[i].update()) {
bool state = Taste[i].read();
//Serial.print((__FlashStringHelper*)pgm_read_word(&(name_table[i])));
ledState = buttonState = !state;
if (state) {
//Serial.println(F(" released (state 0)"));
buttonNum = i;
} else {
//Serial.println(F(" pressed (state 1)"));
buttonPressTimeStamp = millis();
}
switch (buttonNum){
case 0: auswahl();
break;
case 1: play();
break;
case 2: next();
break;
case 3: last();
break;
}
}
}
if (buttonState) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
ledState = !ledState;
retrigger = true;
//Serial.println(F("Retriggering button"));
}
else retrigger = false;
}
long upTime = millis() - buttonPressTimeStamp;
if ( Taste[0].fell() || Taste[1].fell() || Taste[2].fell() || Taste[3].fell()) {
buttonPressTimeStamp = millis();
}
}
void auswahl(){
Serial.println("Auswahl");
}
void play(){
Serial.println("Play/Pause");
}
void next(){
if (retrigger= true){
Serial.print("schnell ");
}
Serial.println("Vor");
}
void last(){
if (retrigger = true){
Serial.print("schnell ");
}
Serial.println("Zurück");
}
aber wie bekomm ich es hin das beim lange drücken eine andere Funktion ausgeführt wird?
Indem du für jede Taste den Zeitpunkt der Drückens festhältst (bei .fell()),
die Aktion aber erst startest wenn die Taste wieder losgelassen wird (bei .rose()).
Du kannst dann eine Aktion für verschiedene Tastendruck-Längen auswählen.
Zeitpunkt(rose) - Zeitpunkt(fell)l = Dauer.
mire
January 25, 2017, 4:20pm
14
ich verstehe diese for-schleife noch nicht so ganz:
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
if (Taste[i].update()) {
bool state = Taste[i].read();
//Serial.print((__FlashStringHelper*)pgm_read_word(&(name_table[i])));
ledState = buttonState = !state;
if (state) {
//Serial.println(F(" released (state 0)"));
buttonNum = i;
} else {
//Serial.println(F(" pressed (state 1)"));
buttonPressTimeStamp = millis();
}
}
was macht if (state)?
hier kann ich nicht die gedrückte taste erhalten?
mire:
was macht if (state)?
wertet den aktuellen Tastenzustand aus.
In diesem Fall nur bei einem Statechange (if(...update())), ist also fast ein fell/rose.
Etwas wie buttonPressTimeStamp sollte für jede Taste existieren,
dann kannst du im anderen Teil des if's entscheiden ob es ein langer oder kurzer Druck war.
mire
January 25, 2017, 4:48pm
16
dieser Teil erkennt ja ob eine Taste lange gedrückt wird aber nicht welche Taste.
if (buttonState) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
ledState = !ledState;
retrigger = true;
//Serial.println(F("Retriggering button"));
if (buttonNum = 2) schnellVor();
if (buttonNum = 3) schnellrw();
}
else retrigger = false;
}
Wenn ich im oberen Teil die gedrückte Taste erfahre und im unteren Teil ob sie lange gedrückt ist würde es ja funktionieren. oder?
mire:
Wenn ich im oberen Teil die gedrückte Taste erfahre und im unteren Teil ob sie lange gedrückt ist würde es ja funktionieren. oder?
Oder.
Das von dir Gezeigte ist nur die alte sinnlose "wenn die Abstände zwischen Tasten 500ms überschreiten, drucke 'Retriggering button'" Aktion aus deinem Originalkode.
Ich habe dir genau beschrieben wie man es machen könnte.
mire
January 26, 2017, 8:17pm
18
nun hab ich die Auswertung der Knöpfe so wie ich es brauche.
Nach einigen Versuchen sieht der Code nun so aus:
#include <Bounce2.h>
const byte pinArray[4] = { 22, 24, 26, 28 };
Bounce Taste[4];
unsigned long buttonPressTimeStamp;
byte ledState, buttonState;
bool retrigger;
byte lastButton;
void setup() {
Serial.begin(9600);
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
Taste[i].attach(pinArray[i], INPUT_PULLUP);
Taste[i].interval(50);
}
}
void loop() {
pressedButton();
long upTime=millis()-buttonPressTimeStamp;
//if (upTime == 4000 ) Serial.println("turn OFF"); //Aktion bein nicht benutzen
}
void pressedButton(){
for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
if (Taste[i].update()) {
lastButton=i;
bool state = Taste[i].read();
ledState = buttonState = !state;
if (state && !retrigger) {
switch (i){
case 0: {
auswahl();
break;
}
case 1: {
play();
break;
}
case 2: {
next();
break;
}
case 3: {
last();
break;
}
}
} else {
buttonPressTimeStamp = millis();
retrigger=false;
}
}
}
if (buttonState) {
if ( millis() - buttonPressTimeStamp >= 500 ) {
buttonPressTimeStamp = millis();
ledState = !ledState;
retrigger = true;
switch (lastButton){
case 2: {
schnellVor();
break;
}
case 3: {
schnellRw();
break;
}
}
}
}
long upTime = millis() - buttonPressTimeStamp;
if ( Taste[0].fell() || Taste[1].fell() || Taste[2].fell() || Taste[3].fell()) {
buttonPressTimeStamp = millis();
}
}
void auswahl(){
Serial.println("Auswahl");
}
void play(){
Serial.println("Play/Pause");
}
void next(){
Serial.println("Vor");
}
void last(){
Serial.println("Zurueck");
}
void schnellVor(){
Serial.println("schnell vor");
}
void schnellRw(){
Serial.println("schnell zurück");
}
danke fur Unterstüzung