Arduino Leonardo Schalter

Hallo zusammen,

ich habe vor einige externe Schalter und Buttons für ein Projekt zu verwenden.
Nun habe ich schon ein Script geschrieben. Mit diesem kann ich schon wunderbar die Buttons benutzen (erledigt mit Keyboard.write). Jedoch habe ich bei den Schaltern (0 | 1) noch einige Probleme....

Wenn ich den Schalter runter drücke, also auf 1, dann sendet er wie gewollt den Buchstaben Y, jedoch aber immer hintereinander (Spam).... Ich möchte aber das er nur 1x diesen Buchstaben sendet. Das könnte man natürlich machen, indem man die Delay hochsetzt - aber das ist ja auch net so elegant. Wenn ich den Schalter hochdrücke, soll er außerdem auch wieder das Y senden.

Hat jemand eine Lösung für mein Problem, welche Sketches, gerne auch Templates, ich verwenden soll?

Würde mich über Antworten freuen!
VG Elias

Immer wieder gerne:

char lastChar = {'\0'};
char aktualChar;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
}

void loop()
{
  if (lastChar != aktualChar)
  {
// Mach hier was mit aktualChar
    lastChar = aktualChar;
  }
}

edit:
Variante 2 - nicht erst auf den Buchstaben warten, sondern vorher schon auf den Pin:

const byte pin = 2;
bool lastPinZustand;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(pin, INPUT_PULLUP)
  lastPinZustand=digitalRead(pin);
  
}

void loop()
{
  if (digitalRead(pin) != lastPinZustand)
  {
    lastPinZustand=!lastPinZustand;
    // Hier sende ein Y
  }
}

Na denne - mach was draus :slight_smile:

1 Like

Hab die 2. Variante ausprobiert, klappt perfekt :))
Ich danke dir vielmals!

1 Like

Das nennt sich Flankenerkennung.
Grüße Uwe

Und darum ist es eigentlich nicht mal richtig.
@rindskopf1
Um zu vermeiden, das zwei gesendet werden:

void loop()
{
  if (digitalRead(pin) != lastPinZustand)
  {
    lastPinZustand = !lastPinZustand;
    if (!lastPinZustand)
    {
      // HIER senden...
    }
  }
}

Ich hab einfach die Delay etwas höher gesagt, jetzt sendet er auch genau 1, und nicht 3 o.ä.

Ich mit meinen Wurstfingern würde wahrscheinlich nicht schnell genug loslassen. Darum sehe ich ein längeres delay() als keine praktikable Lösung.

Grüße Uwe

Stimmt auch, aber der Schalter hakt eigentlich relativ schnell ein :smiley:
@my_xy_projekt @uwefed
Wenn ich jetzt dieses System noch an weiteren Schaltern anwenden möchte, wo müsste ich dann noch was ändern, evtl. an diesem const byte pin = 2; ?...
Oder kann ich einfach CopyPaste und halt nur im Void loop die einzelnen Pins und Tastaturbefehle ändern?

Du könntest die MoToButtons Klasse meiner MobaTools verwenden. Die ist genau dafür gemacht und verwaltet bis zu 32 Taster/Schalter in einer Instanz. Da kannst Du ganz einfach den Moment des Drückens und Loslassens erkennen und entsprechend einmalige Aktionen auslösen.
Im Beispiel PrintStates2.ino werden da jeweils beim Drücken/Loslassen Texte auf dem seriellen Monitor ausgegeben. WIe lange die Taste gedrückt wird ist dabei egal. Das ist ja sowas ähnliches wie Du brauchst.
Entweder Du kopierst dir die MoToButtons.h in dein Sketchverzeichnis und bindest sie mit
#include "MoToButtons.h"
ein. Oder Du installierst die MobaTools komplett über den Bibliotheksmanager. Auch wenn Du sie komplett installierst, wird nur das in deinen Sketch eingebunden, was Du auch verwendest.

P.S.:

Delay() brauchst Du dabei nicht, und solltest Du auch nicht verwenden.

Kannst machen - pin ändern und ne neue Zustandsvariable für den Merker.
Oder das weiterverwenden was Du hast.

const byte pin[] = {2, 3, 4};
bool lastPinZustand[sizeof(pin)]; // das sizeof geht so nur, weil pin die Größe byte hat
const char buchstabe[sizeof(pin)] = {'X', 'Y', 'Z'};

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  for (byte b = 0; b < sizeof(pin); b++)
  {
    pinMode(pin[b], INPUT_PULLUP);
    lastPinZustand[b] = digitalRead(pin[b]);
  }
}

void loop()
{
  for (byte b = 0; b < sizeof(pin); b++)
  {
    if (!digitalRead(pin[b]) != lastPinZustand[b])
    {
      lastPinZustand[b] = !lastPinZustand[b];
      if (!lastPinZustand[b])
      {
        Serial.println(buchstabe[b]);
      }
    }
  }
}

Mhh jetzt spuckt er mir ne Fehlermeldung beim fett Markierten aus.. invalid types 'int[byte {aka unsigned char}]' for array subscript


#include <Keyboard.h>
int TUR1=11;
int TUR2=12;
int SCHALT1=9;
int SCHALT2=7;
const byte pin[] = {2, 3, 4};
bool lastPinZustand[sizeof(pin)]; // das sizeof geht so nur, weil pin die Größe byte hat

void setup ()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
   for (byte b = 0; b < sizeof(pin); b++)
  {
    pinMode(SCHALT1[b], INPUT_PULLUP);
    lastPinZustand[b] = digitalRead(SCHALT1[b]);
  }
  {
    pinMode(SCHALT2[b], INPUT_PULLUP);
    lastPinZustand[b] = digitalRead(SCHALT2[b]);
  }
  pinMode(TUR1, INPUT);
  pinMode(TUR2, INPUT);
}

void loop()
{
    Keyboard.begin();
  if (digitalRead(TUR1) == HIGH)
  {  Keyboard.write('/');
    delay(400);
  }
  if (digitalRead(TUR2) == HIGH) 
  {  Keyboard.write ('*');
    delay(400);
  }
  for (byte b = 0; b < sizeof(pin); b++)
  {
    if (!digitalRead(SCHALT1[b]) != lastPinZustand[b])
    {
      lastPinZustand[b] = !lastPinZustand[b];
      if (!lastPinZustand[b])
      {
        Serial.println(buchstabe[b]);
      }
    }
  }
    for (byte b = 0; b < sizeof(pin); b++)
  {
    **if (!digitalRead(SCHALT2[b]) != lastPinZustand[b])**
    {
      lastPinZustand[b] = !lastPinZustand[b];
      if (!lastPinZustand[b])
      {
        Serial.println(buchstabe[c]);
      }
    }
  }
}

  Keyboard.end(); // (YYYYYY-(+´(-(---´((--((--(-(-(---((((---(((((((-(((--(-(---(-(-(-((-
}

Beim 2. Mal spuckt er mir jetzt ne Fehlermeldung aus mit invalid types 'int[byte {aka unsigned char}]' for arry subscript:

  for (byte b = 0; b < sizeof(pin); b++)
  {
    if (!digitalRead(SCHALT1[b]) != lastPinZustand[b])
    {
      lastPinZustand[b] = !lastPinZustand[b];
      if (!lastPinZustand[b])
      {
        Serial.println(buchstabe[b]);
      }
    }
  }
    for (byte b = 0; b < sizeof(pin); b++)
  {
    **if (!digitalRead(SCHALT2[b]) != lastPinZustand[b])**
    {
      lastPinZustand[b] = !lastPinZustand[b];
      if (!lastPinZustand[b])
      {
        Serial.println(buchstabe[c]);
      }
    }
  }
}

Dann ist eine Variableanders definiert, als Du sie verwendest.
Dazu muss ich wissen,wie Du die initialisiert hast.

Zeig mal alles bis zum setup().

Hallo
Hier kommt ein Beispiel mit OOP.
Die Informationen über den Knopf und Buchstabe sind einfach in einem struct/array angelegt. Weitere Kombinationen aus Knöpfen und Buchstaben lassen sich hier durch COPY/PASTE in das array hinzufügen ohne den weitern Code anzufassen.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  https://forum.arduino.cc/t/arduino-leonardo-schalter/941345/12
*/
#define ProjectName "Arduino Leonardo Schalter"
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
struct TIME {               // has the following members
  unsigned long duration;   // memory for interval time
  unsigned long stamp;      // memory for actual time
};
struct BUTTON2LETTER {
  byte pin;                   // portPin o---|button|---GND
  char char_;                 // letter
  TIME scan;                  // information for debouncing
  int statusQuo;              // last buttonState
} button2letters[] {          // add buttons and letters & co as you like
  {A0, 'H', 20, 0, false},
  {A1, 'A', 20, 0, false},
  {A2, 'L', 20, 0, false},
  {A3, 'O', 20, 0, false},
};
// -------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  for (auto button2letter : button2letters) pinMode(button2letter.pin, INPUT_PULLUP);
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  for (auto &button2letter : button2letters) {
    if (currentTime - button2letter.scan.stamp >= button2letter.scan.duration) {
      button2letter.scan.stamp = currentTime;
      int stateNew = !digitalRead(button2letter.pin);
      if (button2letter.statusQuo != stateNew) {
        button2letter.statusQuo = stateNew;
        if (stateNew) Serial.print(button2letter.char_);
      }
    }
  }
}

Ich wünsche einen geschmeidigen Rutsch ins Neue Jahr und viel Spass beim Programmieren in C++.

p.s. Getestet mit einem Arduino UNO

Ich weis echt nicht, warum ihr alle so gern das Rad neu erfindet. Für diese ganze Problematik gibt's doch wahrlich genug fertige Lösungen. Wem meine Lib nicht gefällt, der findet reichlich Alternativen.
Mit den Arduinos kann man so tolle Sachen machen. Warum sich immer wieder mit den schon längst gelösten Basic's beschäftigen? Ihr verwendet doch auch digitalWrite um einen Pin zu setzen, und hantiert nicht mit den Ports direkt rum. Das gilt in meinen Augen genau so für die Taster/Schalter und Zeitaufgaben Problematik. Da gibt's überall fertige Lösungen für.
Aber jeder wie er mag. Ich kann nichts daran finden die 1000+1ste Lösung für diese Problem zu finden :stuck_out_tongue_winking_eye:

Das wird nichts. Du hast oben jeden Pin einzeln angelegt und versuchst unten ein Array von Pins zu benutzen :wink:

#include <Keyboard.h>
const byte schalt[] = {7, 9, 11, 12};
bool lastPinZustand[sizeof(schalt)]; // das sizeof geht so nur, weil pin die Größe byte hat
const char buchstabe[sizeof(schalt)] = {'X', 'Y', '/', '*'};

void setup ()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  for (byte b = 0; b < 2; b++)
  {
    lastPinZustand[b] = digitalRead(schalt[b]);
  }
  pinMode(schalt[0], INPUT_PULLUP);
  pinMode(schalt[1], INPUT_PULLUP);
  pinMode(schalt[2], INPUT);
  pinMode(schalt[3], INPUT);
}

void loop()
{
  Keyboard.begin();
  for (byte b = 0; b < sizeof(schalt); b++)
  {
    if (!digitalRead(schalt[b]) != lastPinZustand[b])
    {
      lastPinZustand[b] = !lastPinZustand[b];
      if (!lastPinZustand[b])
      {
        Keyboard.write(buchstabe[b]);
        Serial.println(buchstabe[b]);
      }
    }
  }
  Keyboard.end();
}

Ahh jetzt hab ich das System (hoffe ich mal halbwegs) verstanden..
Ich habe das Script mal so übernommen - jetzt sind wir aber wieder teilweise am #1 Post von mir angekommen :smiley: Er sendet wieder 2 oder mehr Befehle bei einem Drücker.

Soll ich einfach die Delay wieder höher setzen?

Ja,
weil die Tasten prellen.

Las mir mal nen Moment.
Ich komm hier wieder her...

So. Ich erklär mal, warum ein delay kontraproduktiv ist:
egal wie Du es machst, wenn Du ein delay startest, nachdem Du einen Input abgefragt hast, bist Du für diese Zeit blind und kannst die anderen Pins nicht abfragen.
nehmen wir mal an, Du hast ein delay von 100 ms - die hab ich jetzt gesetzt - und an den ersten 3 Pin findet eine Abfrage statt - dann bist Du am vierten Pin erst nach 300+x ms.
Das sind Welten....

ich habe jetzt auch 100ms genommen. Aber ich warte nur für den jeweiligen Pin.
Kommt also zwischendurch ein anderer Pin - Kein Problem, ich laufe immer wieder alle Abfragen durch....

#include <Keyboard.h>
const byte schalt[] = {7, 9, 11, 12};
bool lastPinZustand[sizeof(schalt)]; // das sizeof geht so nur, weil pin die Größe byte hat
const char buchstabe[sizeof(schalt)] = {'X', 'Y', '/', '*'};
const uint32_t bounceTime = 100;
uint32_t bounceMerker[sizeof(schalt)] = {0};

void setup ()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  for (byte b = 0; b < 2; b++)
  {
    lastPinZustand[b] = digitalRead(schalt[b]);
  }
  pinMode(schalt[0], INPUT_PULLUP);
  pinMode(schalt[1], INPUT_PULLUP);
  pinMode(schalt[2], INPUT);
  pinMode(schalt[3], INPUT);
}

void loop()
{
  Keyboard.begin();
  uint32_t myMillis = millis();
  for (byte b = 0; b < sizeof(schalt); b++)
  {
    if (myMillis - bounceMerker[b] >= bounceTime)
    {
      if (!digitalRead(schalt[b]) != lastPinZustand[b])
      {
        lastPinZustand[b] = !lastPinZustand[b];
        bounceMerker[b] = myMillis;
        if (!lastPinZustand[b])
        {
          Keyboard.write(buchstabe[b]);
          Serial.println(buchstabe[b]);
        }
      }
    }
  }
  Keyboard.end();
}

Entprellen - gehört zu den Basics mit einer Unzahl von fertigen Lösungen ...

Stimmt ist mir auch aufgefallen, wollte 2 Schalter gleichzeitig betätigen - ging nur einer.
Aber danke fürs Script.
Jetzt sendet er jedoch kein Befehl mehr, wenn ich von eingeschaltet zu ausgeschaltet drücke (1 -> 0) ..... xD -.-