Hallo Community, bei der Programmierung habe ich folgende ungelöste Aufgabenstellung.
Ich möchte mit vier Taster zehn Funktionen schalten. Das Problem beginnt dann, wenn eine Tastenkombination von zwei Tasten eine Funktion auslösen soll bei welcher die Einzeltasten bereits mit einer Funktion verknüpft bzw. belegt ist.
Aus beigefügter Tabelle ist ersichtlich, dass Button 2 bei zwei von vier Funktionen beteiligt ist.
Versuche ich Ereignis no.6 zu aktivieren, wird z.B. gleichzeitig auch Ereignis no.2 aktiviert.
Dabei werden die Ereignisse nicht oder wechselweise ausgeführt. Gibt es überhaupt eine Möglichkeit, diese Aufgabe via Programm zu lösen?
Vielleicht hat ja jemand einen Lösungsvorschlag. Vielen Dank vorab!
Ja, natürlich. Das wäre jetzt nicht das erste System, das mit mit Mehrfachtastendrücken umgehen muss.
Tipps:
Tastendrücke bearbeite ich am liebsten durch Erkennung der Flankenwechsel "nicht aktiv" nach "aktiv" und zurück (PRESSED und RELEASED Events).
Bei Mehrfachtasten muss man sich darauf einstellen, dass kein Benutzer die exakt gleichzeitig drückt.
Die Aktion, die auf die Taste hin ausgeführt werden soll, lege ich meist auf den RELEASED-Event - das hilft auch beim Behandeln von langen Tastendrücken.
So - und jetzt kommst Du mit dem was Du schon hast!
Du musst dir die Zeit des ersten Erkennens merken, und dann x ms prüfen, on ein weiterer Taster kommt. Er wenn die Wartezeit ohne Änderung abgelaufen ist, die Aktion auslösen.
Hallo Tommy56,
momentan ist das für mich ein abgegrenztes Problem für die Steuerung von Relais.
In der Tabelle ist das simple, aber hardwaremäßig doch ein Problem für mich.
Gruß
Gerhard
Es ist wie beim Führerschein, ich fahre einen PKW und habe theoretisch das Recht auch 7,5t zu fahren. Ich brauch einfach Zeit, mich mit der Programmiersprache und den einzelnen Bedeutungen sowie Auswirkungen auseinanderzusetzen. Ich will das auch nachvollziehen können. Habt bitte Geduld mit mir. Danke!
Gruß
Gerhard
Der Lerneffekt ist aber größer, wenn auf das aufgebaut wird, was vorhanden ist.
Vielleicht hilft Dir ja ein wenig Bettlektüre.
Nur bis zur Hälfte. Danach gehts schon ans eingemachte.
Und Du musst es nicht auswendig lernen. Nur wissen, was drin steht.
Vielen, vielen Dank, my_xy_projekt für diese Bettlektüre! Habe das Skript kurz überflogen und habe einen guten Eindruck von dieser Zusammenfassung. Also, es gibt nun sehr viel zu tun....
Gruß
Gerhard
Moin, my_xy_projekt,
habe die letzte deiner Varianten etwas intensiver betrachtet und mir etwas Hardware (je 4x Taster und Leds) aufgebaut. Danach habe ich den Code für die Ausgabe an den Leds aktuallisiert.
// Forensketch
// https://forum.arduino.cc/
#include <Streaming.h> // https://github.com/janelia-arduino/Streaming
//#define DEBUG // Wenn aktiviert, werden Zwischenwerte ausgegeben
#ifdef DEBUG
#define DBG_PRINTLN(...) Serial << __VA_ARGS__ << endl
#else
#define DBG_PRINTLN(...)
#endif
constexpr byte buttons {4};
constexpr bool pressed {LOW};
constexpr uint32_t debounceTime {50};
byte step;
byte buttonState;
byte lastState;
struct BUTTON
{
const byte pin;
uint32_t pressTime;
};
BUTTON button[buttons]
{{2, 0}, {3, 0}, {4, 0}, {5, 0}};
const int ledPin1 = 8; // the number of the LED pin
const int ledPin2 = 9; // the number of the LED pin
const int ledPin5 = 10; // the number of the LED pin
int ledState1 = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED
int ledState5 = LOW; // ledState used to set the LED
void setup()
{
Serial.begin(115200);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin5, OUTPUT);
#if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2650)) // https://github.com/arduino/Arduino/issues/10764
delay(300);
#endif
Serial << (F("\r\nStart...\r\n")) << endl;
DBG_PRINTLN(__FILE__);
DBG_PRINTLN( __TIMESTAMP__);
for (byte b = 0; b < buttons; b++)
{
pinMode(button[b].pin, INPUT_PULLUP);
}
}
void loop()
{
readButtons();
checkButtons();
}
void checkButtons()
{
if (buttonState != lastState)
{
Serial << F("Taste ");
switch (buttonState)
{
case B00000001:
Serial << "1";
ledState1 = HIGH; // ledState used to set the LED
digitalWrite(ledPin1, ledState1);
delay(50);
ledState1 = LOW; // ledState used to set the LED
digitalWrite(ledPin1, ledState1);
break;
case B00000010:
Serial << "2";
ledState2 = HIGH; // ledState used to set the LED
digitalWrite(ledPin2, ledState2);
delay(50);
ledState2 = LOW; // ledState used to set the LED
digitalWrite(ledPin2, ledState2);
break;
case B00000100:
Serial << "3";
break;
case B00001000:
Serial << "4";
break;
case B00000011:
Serial << "1 & 2";
ledState5 = HIGH; // ledState used to set the LED
digitalWrite(ledPin5, ledState5);
delay(50);
ledState5 = LOW; // ledState used to set the LED
digitalWrite(ledPin5, ledState5);
break;
case B00000101:
Serial << "1 & 3";
break;
case B00001001:
Serial << "1 & 4";
break;
case B00000110:
Serial << "2 & 3";
break;
case B00001010:
Serial << "2 & 4";
break;
case B00001100:
Serial << "3 & 4";
break;
}
Serial << " gedrückt" << endl;
lastState = buttonState;
}
}
void readButtons()
{
for (byte b = 0; b < buttons; b++)
{
if (!digitalRead(button[b].pin))
{
button[b].pressTime = millis();
bitSet(buttonState, b);
}
else if (millis() - button[b].pressTime > debounceTime)
{
bitClear(buttonState, b);
}
}
}
Hier wird meine Aufgabenstellung deutlich!
Wenn "Taste 1" & " Taste 2" gedrückt wird, können die Leds "1", "2" und "5" aufleuchten.
Es soll in diesem Fall nur Led "5" aufleuchten.
Led "1" und "2" dürfen nicht angesprochen werden.
Für diese Aufgabenstellung suche ich eine Lösung!
Gruß
Gerhard
Wenn die Tasten manuell gedrückt werden, dann wirst du vor einer gemeinsamen Auswertung eine Wartezeit abwarten müssten um sicherzustellen dass die Usereingabe abgeschlossen ist.
Ein Mensch wird es nicht in der gleichen Millisekunde schaffen zwei Taster zu drücken.
(Also das was @wwerner ähnlich vor 3 Tagen schon geschrieben hat.).
Hallo @noiasca,
also, die Tasten werden aktuell mechanisch betätigt. Wenn die "Tasten" elektrisch betätigt werden, dann erfolgt dies ja auch sequentiell, oder täusche ich mich da! Es geht dann nur schneller. Momentan überlege ich, ob man die nicht aktiven, einzelnen Ports nicht geplant auf "INPUT" oder "OUTPUT" zieht.
verstehst du jetzt das Problem?
So erreichst du keine Prüfung auf zwei Tasten.
edit: das wäre eine Variante die auf die Kombination von weiteren Tastendrücke wartet:
/*
Mehrfachbelegung von 4 Buttons
https://forum.arduino.cc/t/mehrfachbelegung-von-4-buttons/1353643/18
2025-02-16 by noiasca
*/
#include <Streaming.h> // https://github.com/janelia-arduino/Streaming
#include "button.h"
Button button[] {A0, A1, A2, A3}; // create 4 active LOW buttons
constexpr uint32_t syncDelay {200}; // time waited to get several button presses
byte buttonState; // current result of button presses
uint32_t lastPress; // when was the last press of any button
constexpr byte buttons {sizeof(button) / sizeof(button[0])}; // get the number of buttons
void setup() {
Serial.begin(115200);
#if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2650)) // https://github.com/arduino/Arduino/issues/10764
delay(300);
#endif
Serial << (F("\r\nStart...\r\n")) << endl;
for (auto &b : button) {
b.begin();
}
}
void loop() {
readButtons();
checkButtons();
}
void checkButtons() {
if (buttonState && millis() - lastPress > syncDelay) {
Serial << F("Taste(n) ") << _BIN(buttonState) << " gedrückt" << endl;
switch (buttonState) {
case 0b00000001: // "1"
break;
case 0b0000010: // "2";
break;
case 0b0000100: // "3";
break;
case 0b00001000: // "4";
break;
case 0b00000011: // "1 & 2";
break;
case B00000101: // "1 & 3";
break;
case B00001001: // "1 & 4";
break;
case B00000110: // "2 & 3";
break;
case B00001010: // "2 & 4";
break;
case B00001100: // "3 & 4";
break;
}
buttonState = 0;
}
}
void readButtons() {
for (size_t b = 0; b < buttons; b++) {
if (button[b].wasPressed()) {
//Serial <<F("SinglePress") << b << endl;
lastPress = millis();
bitSet(buttonState, b);
}
}
}
//
und die button.h in einem weiteren Tab:
/*
a class to debounce a button
the program is based on "state change detection" and converted to OOP to make it reusable
2024-11-09 by noiasca
*/
class Button { // a simple class for buttons based on the "Debounce" example
const uint8_t buttonPin; // the GPIO / pin for the button
static constexpr byte debounceDelay = 30; // the debounce time; Static because we only need one value for all buttons
const bool active; // is the pin active HIGH or active LOW (will also activate the pullups!)
bool lastButtonState = HIGH; // the previous reading from the input pin
uint32_t lastDebounceTime = 0; // the last time the output pin was toggled
public:
/**
\brief constructor for a button
The constructor takes the GPIO as parameter.
If you omit the second parameter, the class will activate the internal pullup resistor
and the button should connect to GND.
If you set the second parameter to HIGH, the button is active HIGH.
The button should connect to VCC.
The internal pullups will not be used but you will need an external pulldown resistor.
\param buttonPin the GPIO for the button
\param active LOW (default) - if button connects to GND, HIGH if button connects to VCC
*/
Button(uint8_t buttonPin, bool active = LOW) : buttonPin(buttonPin), active(active) {}
/**
\brief set the pin to the proper state
Call this function in your setup().
The pinMode will be set according to your constructor.
*/
void begin() {
if (active == LOW)
pinMode(buttonPin, INPUT_PULLUP);
else
pinMode(buttonPin, INPUT);
}
/**
\brief indicate if button was pressed since last call
@return HIGH if button was pressed since last call - debounce
*/
bool wasPressed() {
bool buttonState = LOW; // for the current reading from the input pin
byte reading = LOW; // "translated" state of button LOW = released, HIGH = pressed, despite the electrical state of the input pint
if (digitalRead(buttonPin) == active) reading = HIGH; // overwrite the current button state (independent from active LOW or active HIGH)
if ((millis() - lastDebounceTime) > debounceDelay) { // If the switch changed, AFTER any pressing or noise
if (reading != lastButtonState && lastButtonState == LOW) { // If there was a change and and last state was LOW (= released)
buttonState = HIGH;
}
lastDebounceTime = millis();
lastButtonState = reading;
}
return buttonState;
}
};
//