Einsteiger benötigt Hilfe

Außerdem werden Rücksprungadressen in den Stack geschrieben, die bei einem Herausspringen aus einer Schleife mittels goto nicht gelöscht werden und so den Stack zum Überlauf bringen. Das macht den Sketch instabil.

Kinder, Uwe ist ein toller Moderator, aber alles darf man ihm auch nicht glauben.

Mit einem goto kann man nicht aus einer Funktion herausspringen (oder hinein) und so den Stack "zum Überlauf bringen". So einen Mist würde der avrgcc Compiler nicht zulassen. Wo goto syntaktisch zulässig ist, funktioniert es auch. Und es funktioniert auch 1000 Mal, d.h. nach einer halben Sekunde noch.

Aber außer den Sonderfällen continue; break; return; sollte man wirklich ohne Sprünge auskommen und eher an Funktionen denken, wenn man die gleiche Aktion an verschiedenen Stellen im Code braucht.


Falls das missverständlich war: Natürlich kann man Code schreiben, der den RAM zum Überlauf bringt, ohne dass der Compiler es merken kann.
Z.B. ein String Objekt verwenden :wink:

ups

ich hoffe aber bei 99,5% der Fälle liege ich aber richtig :wink: :wink: :wink:
Grüße Uwe

habe mitgeschrieben, uwe, 99,63267%, ein insgesamt tragbares ergebnis...

Danke Stefan, da bin ich ja beruhigt. :cold_sweat: :cold_sweat: :wink: :wink:

Ja, das war auch mein intuitives Gefühl:
99,5 % Treffer ist zu wenig bei Uwe.

Und Danke, dass ich hier den Rechthaber spielen darf. Zuhause gibt's immer Streit, wer der größere Rechthaber ist
:roll_eyes:

und wir vertrauen jedem Post von dir, Uwe!
Wir bauen auf dich!

Dirk

Also, ich habe jetzt ein wenig rum probiert und folgendes kam dabei heraus:

int fin[]  = {0,1,2,3,4,5,6,7,8,9,10,11};
int chan[] = {A0, A1, A2, A3};
int led    = 13;

void setup() 
{
  for(int i = 0 ; i <=11 ; i++)
  {
    pinMode(fin[i], INPUT_PULLUP);
    pinMode(chan[i], INPUT_PULLUP);
  }
  pinMode(led, OUTPUT);
  Keyboard.begin();
  Serial.begin(9600);
}

#define CHARBUTTONS 12
#define MODIFIERBUTTONS 4

char charTable[MODIFIERBUTTONS+1][CHARBUTTONS]={
    {'a','b','c','d','e','f','g','h','i','j','k','l'},
    {'m','n','o','p','q','r','s','t','u','v','w','x'},
    {'y','z','!','%','&','/','(',')','=','?','.',','},
    {'1','2','3','4','5','6','7','8','9','0','+','-'}
    };


int readCharButton()
{
  for(int j = 0 ; j<=11 ; j++)
  {
    if(digitalRead(fin[j]) == LOW)
    {
      return j;
    }
    else
    {
      return -1;
    }
  }
}


int readModifierButton()
{
  for(int i = 0 ; i <= 3 ; i++)
  {
    if(digitalRead(chan[i]) == LOW)
    {
      return i;
    }
    else
    {
      return 0;
    }
  }
}

    
void fireButton(int charBtn, int modifierBtn)
{
  Keyboard.press(charTable[modifierBtn][charBtn]);
  Serial.println(charTable[modifierBtn][charBtn]); 
}

void loop()
{
  int charButton,modifierButton;
  charButton=readCharButton();
  if (charButton>=0)
  {
    modifierButton=readModifierButton();
    fireButton(charButton,modifierButton);
  }
  else
  {
    Keyboard.releaseAll();
  }
}

Mir selbst fallen am laufenden Band Fehler auf und ich weiß, es ist nicht sonderlich gut. Ich habe da nur ein Problem: die einzige belegte "Taste", scheint der Pin 0 zu sein, denn egal was ich sonst ground'e, es passiert nichts. Auch nicht bei den ModifierTasten. Es ist grade ca. 23.20 und mir fällt einfach nicht auf wo der Fehler ist. Ist es ein einfacher, fast schon doofer Fehler, der einem quasi mit Neonroter Farbe in Gesicht springt? Mir fällt der Fehler einfach nicht auf..
Und sorry, das ich die ganze Zeit Nerve :sweat_smile:

int readCharButton()
{
  for(int j = 0 ; j<=11 ; j++)
  {
    if(digitalRead(fin[j]) == LOW)
    {
      return j;
    }
    else
    {
      return -1;
    }
  }}

Du kontrollierst das erste Pin und springst dann auf jeden Fall mit 0 oder -1 heraus. Die for Schleife wird nicht durchlaufen.
Du mußt die ganze for Schleife durchlaufen lassen und nur im Fall, daß keine Taste gedrückt ist, mit -1 zurückspringen.

Diese Code findet bei mehreren gedrückten Tasten nur die am niedrigrsten Pin angeschlossenen.

int readCharButton()
{
  for(int j = 0 ; j<=11 ; j++)
  {
    if(digitalRead(fin[j]) == LOW)
    {
      return j;
    }
  }
return -1;
}

Grüße Uwe

Bei der Funktion int readModifierButton() hast Du das gleiche Problem. Bei solchen Fehlern hilft es meistens, wenn man versucht Schritt für Schritt die problematische Funktion durchzugehen und alle einzelnen Programmschritte nachzuvollziehen, dann merkt man häufig shon, wo der Fehler liegt.

int readModifierButton()
{
  for(int i = 0 ; i <= 3 ; i++)
  {
    if(digitalRead(chan[i]) == LOW)
    {
      return i;
    }
    else
    {
      return 0;
    }
  }
}
int readModifierButton()
{
  for(int i = 0 ; i <= 3 ; i++)
  {
    if(digitalRead(chan[i]) == LOW)
    {
      return i;
    }
  }
  return 0;

}

Ah, also, ich muss glaube ich noch mal einmal kurz sagen, wie die ModifierButton funktionieren sollen :smiley: Also, drückt man einmal drauf, werden andere Buchstaben geschrieben, ABER mann muss die Tasten nicht festhalten, sondern einmaliges Drücken genügt ^^

Das ist doch kein Problem. Du verwendest einfach eine Variable "chan_state". Jedesmal wenn einer der "chan"-Button erkannt wurde, dann setzt Du den Wert entsprechend des erkannten Buttons. chan_state = 1 für den ersten, chan_state=2 für den 2. usw.
Wenn Du nun eine gedrückte "normale" Taste erkannt hast, verwendest Du einfach den aktuellen Wert von chan_state als Index für das Array char charTable um die entsprechende Zeile mit den Zeichen auszuwählen.

Thorben:
Ah, also, ich muss glaube ich noch mal einmal kurz sagen, wie die ModifierButton funktionieren sollen :smiley: Also, drückt man einmal drauf, werden andere Buchstaben geschrieben, ABER mann muss die Tasten nicht festhalten, sondern einmaliges Drücken genügt ^^

Also die Funktion Deiner Modifier-Buttons soll mehr so funktionieren wie die Großbuchstaben-Feststelltaste (CapsLock) auf einer Tastatur und nicht so wie die Großbuchstaben-Umschalttaste (Shift): Einmal drücken: Modifier-Funktion einschalten. Nochmal drücken: Modifier-Funktion ausschalten?

Dann mußt Du Dir einfach merken, ob einer der Modifier-Buttons eine gerade oder eine ungerade Anzahl von malen gedrückt wurde.

Und welcher der Modifier-Buttons soll dann gelten? Alle gleichzeitig?

Mit vier Modifier-Buttons gibt es 24 Möglichkeiten, wie die Schaltzustände sein können, d.h. ein Buchstabe könnte damit auf 16 Arten modifiziert werden. Soll das so sein?

Oder soll nur mittels der zuletzt bewegten Taste modifiziert werden? Dann müßtest Du Dir nicht nur merken, welche Taste gerade gesetzt oder nicht gesetzt ist, sondern auch, welcher Modifier-Button als letztes betätigt wurde.

Also, kurze Erklärung. Man muss sich das wie folgt vorstellen: An dem Daumen befindet sich eine Kupferplatte, ebenso wie drei weitere an jedem anderem Finger. Eine Jeweils an den Spitzen vom Zeige- bis zum Kleinem Finger. Berührt man mit einer Kupferplatte, die Daumen-Kupferplatte, so schreibt man einen Buchstaben. So kann man 12 Buchstaben schreiben oder Tasten drücken oder was auch immer.die Aufgabenstellung sagt allerdings klar das es 20 oder mehr Tasten sein müssen. Dazu habe ich mir gedacht, an jedem der Finger eine weiter Kupferplatte zu basteln die, sobald man sie drückt, werden auf den 12 Platten andere Tasten gedrückt. Berührt man z.B: also direkt nach dem Start mit den Fingerspitzen den Daumen, so drückt man a, b, c und d. Drückt man jetzt die chan-Taste A1 z.B. so schreibt man mit den gleichen Fingern e, f, g und h. So kann man damit bis zu 48 Tasten drücken oder Buchstaben drücken oder sonst was tuhen. Das drücken von shift oder Strg oder sonstigen Sondertasten ist in den 12-"Normalen"-Fingertasten beinhaltet (oh gott, das klingt komisch..). So soll das funktionieren.

@mkl0815
Exakt diese Idee kam mir auch heute :smiley:
Das kommt davon wenn man versucht um 23.00 Uhr einen Programmcode zu schreiben :disappointed_relieved: :slight_smile:

So, ich habe jetzt einen funktionierende Programmcode :slight_smile:

int fin[]  = {0,1,2,3,4,5,6,7,8,9,10,11};
int chan[] = {A0, A1, A2, A3};
int led    = 13;
int chan_state = 0;

void setup() 
{
  for(int i = 0 ; i <=11 ; i++)
  {
    pinMode(fin[i], INPUT_PULLUP);
    pinMode(chan[i], INPUT_PULLUP);
  }
  pinMode(led, OUTPUT);
  Keyboard.begin();
  Serial.begin(9600);
}

#define CHARBUTTONS 12
#define MODIFIERBUTTONS 4


char charTable[MODIFIERBUTTONS+1][CHARBUTTONS]={
    {'a','b','c','d','e','f','g','h','i','j','k','l'},
    {'m','n','o','p','q','r','s','t','u','v','w','x'},
    {'y','z','!','%','&','/','(',')','=','?','.',','},
    {'1','2','3','4','5','6','7','8','9','0','+','-'}
    };


int readCharButton()
{
  for(int j = 0 ; j<=11 ; j++)
  {
    if(digitalRead(fin[j]) == LOW)
    {
      return j;
    }
  }
  return -1;
}


int readModifierButton()
{
  for(int i = 0 ; i <= 3 ; i++)
  {
    if(digitalRead(chan[i]) == LOW)
    {
      chan_state = i;
    }
  }
  return chan_state;
}

    
void fireButton(int charBtn, int modifierBtn)
{
  Keyboard.press(charTable[modifierBtn][charBtn]);
  Serial.println(charTable[modifierBtn][charBtn]); 
}

void loop()
{
  int charButton,modifierButton;
  charButton=readCharButton();
  modifierButton=readModifierButton();
  if (charButton>=0)
  {
    fireButton(charButton,modifierButton);
  }
  else
  {
    Keyboard.releaseAll();
  }
}

vielen Dank für eure Hilfe!

Thorben:
So, ich habe jetzt einen funktionierende Programmcode :slight_smile:

Gratulation!

Jetzt mit Struktur und mit Funktion!

Einige kleine Anmerkungen zu Deinem Code noch:

RAM-Speicher sparen:
Nachdem Du mit den vier Tasten keine fünf Modifier-Zustände abfragst (kein Modifier, oder eine der vier Modifier-Tasten) sondern nur vier (immer die zuletzt betätigte Modifier-Taste) reicht es natürlich, die charTable kleiner zu definieren, das "+1" im ersten Index wird nicht mehr benötigt:
char charTable[MODIFIERBUTTONS][CHARBUTTONS]

Schleifenzähler:
Bei hochzählenden Schleifen schreiben C-Programmierer die Schleifenbedingung üblicherweise mit "<" und dann steht dahinter genau die Zahl, wie oft die Schleife ausgeführt wird.

Statt:
for(int i = 0 ; i <=11 ; i++) ==> wird 12 mal ausgeführt, aber die 12 steht nicht da

Üblicher Programmierstandard:
for(int i = 0 ; i <12 ; i++) ==> Schleife wird 12 mal ausgeführt, und die Zahl 12 steht da

Nochmal der Schleifenzähler:
Mit define-Statements sind im Programm die Anzahl der Tasten festgelegt worden:
#define CHARBUTTONS 12
#define MODIFIERBUTTONS 4

Üblicherweise codet man dann überall wo im Programm auf die 12 CHARBUTTONS und die 4 MODIFIERBUTTONS Bezug genommen wird, zum Beispiel in Zählschleifen, nicht durch erneute Angabe der Zahl, sondern durch Angabe des definierten Platzhalters:
Statt:
for(int i = 0 ; i <12 ; i++)
Besser
for(int i = 0 ; i <CHARBUTTONS ; i++)
Und statt:
for(int i = 0 ; i < 4 ; i++)
Besser:
for(int i = 0 ; i < MODIFIERBUTTONS ; i++)

Das mag auf den ersten Blick nur zu einem mehr "sprechenden Code" führen, der auch ohne großartige Kommentierung selbsterklärend ist, wieso und weshalb irgendwo eine Konstante steht.

Aber es hat auch große Vorteile, wenn der Code irgendwann später einmal geändert werden soll, sagen wir mal angenommen: Irgenwann möchtest Du ein genau solches Programm machen, aber es soll dann für 15 CHARBUTTONS und 3 MODIFIERBUTTONS sein. Dann wäre es von großem Vorteil, wenn Du praktisch nur oben die Werte in den #define Statements ändern mußt, und automatisch sind auch alle Schleifenendbedingungen und so weiter ebenfalls auf die neuen Werte angepaßt.

Kommentare:
In Programme, die länger als eine Bildschirmseite sind, dürfen auch gerne einige Kommentarzeilen eingefügt werden, die erklären, was der Code macht. Insbesondere bei komplexen Programmen und Funktionen ist es hilfreich, wenn Kommentare vorhanden sind, falls man den Code später noch einmal zur Hand nimmt und nachvollziehen möchte, was man da ehemals programmiert hat.

Aber das fällt natürlich unter ein "Schönheit der Arbeit" Programm und ist für das Funktionieren nicht entscheidend.

Na dann noch viel Erfolg mit Deinem Projekt!

Vielen Dank nochmal, aber mal eine andere Frage. Wenn ich mit QT einen Knopf programmiere, verhält er sich exakt genauso wie ich es möchte. Hier habe ich gemerkt, das wenn ich zwei der Kupferlitzen aneinander halte, sie bei einmaliger Berührung, zwischen 1 und bis zu 10 mal die Taste drückt. Google spuckt dabei als Ergebnis aus, das die Kupferlitze nachschwingt. Selbige Suchmaschine spuckt als Ergebnis dagegen den "debounce"-"Befehl" aus und ich habe versucht das auf meinen vorher programmierten Code anzuwenden, das funktioniert allerdings absolut gar nicht, dürfte ich eure Aufmerksamkeit noch einmal in Anspruch nehmen und fragen was es damit genau auf sich hat?

Thorben:
Hier habe ich gemerkt, das wenn ich zwei der Kupferlitzen aneinander halte, sie bei einmaliger Berührung, zwischen 1 und bis zu 10 mal die Taste drückt. Google spuckt dabei als Ergebnis aus, das die Kupferlitze nachschwingt.

Kontaktprellen.

Da mußt Du softwaretechnisch den Button "entprellen", oder wie man auf Neudeutsch sagt, "debouncen", damit extrem kurzfristige Pegeländerungen nicht als mehrere Tastendrücke interpretiert werden.

Die Kupferlitze schwingt nicht nach sondern die Kontaktflächen (wie auch in den meisten Tastern) berühren sich beim Schließen und hüpfen aber ein paarmal bevor sie aufeinander liegen bleiben. Daher gibt es elektrisch einige Rechtecksignale die von schnellen Digitalschaltungen Bzw schnelle Abfrage im Sketch als mehrer Tastendrücke interpretiert werden.
Grüße Uwe

Nur als Kontrolle das ich das jetzt richtig verstanden habe:
Den Debounce müsste ich bei dem Code in die "int readCharButton()" und die "int redModifierButton()" einbauen, oder? In etwa so?:

long lastDebounceTime = 0;
long debounceDelay = 45; // 45 Millisekunden sollten als Debounce genügen
int lastButtonState = HIGH;
int buttonState =;


int readCharButton()
{
  for(int j = 0 ; j<=11 ; j++)
  {
    if(digitalRead(fin[j]) != lastButtonState)
    {
      lastDebounceTime = millis();
      return j;
      if((millis() - lastDebounceTime) > debounceDelay)
      {
        buttonState = digitalRead(fin[j]);
      }
    }
  }
  return -1;
}