Auswahltaster für Programmabschnitt

Hallo!

Ich will mit einem Arduino verschiedene PC Programme steuern. Da diese aber nicht die selben Befehle benutzen brauch ich für jedes Programm extra Steuerbefehle. Ich müsste also irgenwie auwählen können welches Programm ich steuern will. Oder ander gesagt, ich müsste auswählen können welchen Teil der Programmierung ich gerade verwenden will.

z.b.
ich drücke Taster 1, dann leuchtet LED 1 und das Programm berücksichtigt nur den Abschnitt der Programmierung, welcher zu Programm 1 gehört.
oder
Drückt man Taster 2, leuchtet LED 2 und es wird nur der Programmabschnitt benutzt, welcher für Programm 2 zuständig ist.

Hab irgendwann mal mit programmierbaren Taschenrechnern rumgespielt, da gab es eine goto Funktion, hab aber gelesen das man sowas vermeiden soll.

Ich finde es da immer am besten, das Programm "auf Deutsch" zu programmieren, und dann spaeter die Details hinzuzufuegen:

#define MAX_PROGRAMME 3

uint8_t aktuellesProgramm = 0;

void setup()
{
}

void loop()
{
    if (taster1Gedrueckt())
    {
        sendeSteuerbefehl(aktuellesProgramm);
    }

    if (taster2Gedrueckt())
    {
        ++aktuellesProgramm;
        if (aktuellesProgramm > MAX_PROGRAMME)
            aktuellesProgramm = 0;
    }
}

void sendeSteuerbefehl(uint8_t programm)
{
    switch (programm)
    {
        case 0:
            // Sende befehl fuer programm 0
            break;
        case 1:
            // Sende befehl fuer programm 1
            break;

        // usw.
    }
}

Noch schöner geht das mit enums:

 enum programme { PROGRAMM1, PROGRAMM2 };

void loop()
{
    if (taster1Gedrueckt())
    {
        sendeSteuerbefehl(PROGRAMM1);
    }
    else if (taster2Gedrueckt())
    {
         sendeSteuerbefehl(PROGRAMM2);
    }
}

void sendeSteuerbefehl(uint8_t programm)
{
    switch (programm)
    {
        case PROGRAMM1:
            // Sende befehl fuer programm 0
            break;
        case PROGRAMM2:
            // Sende befehl fuer programm 1
            break;

        // usw.
    }
}

Man kann natürlich auch für jedes Programm eine Methode schreiben und diese direkt aufrufen wenn ein Taster gedrückt wird.

Serenifly:
Noch schöner geht das mit enums:

Er moechte mit Taster 2 das Programm wechseln.
Enums machen "++programm" schwer....
#define's machen das programm mehr lesbar.

Aber wir lenken hier vom Thema ab :slight_smile:

Da steht nicht explizit da, dass er mit den Tastern Programme praktisch als Plus/Minus schalten will. Ich habe das als "Ein Taster pro Programm" gelesen. Kann man aber so oder so sehen :slight_smile:

Man kann aber auch enums über einen kleinen Umweg inkrementieren:

typedef enum { PROGRAMM1, PROGRAMM2 } programme;
programme aktuellesProgramm = PROGRAMM1;

aktuellesProgramm = (programme)(aktuellesProgramm + 1);

Thhherapy:
z.b.
ich drücke Taster 1, dann leuchtet LED 1 und das Programm berücksichtigt nur den Abschnitt der Programmierung, welcher zu Programm 1 gehört.
oder
Drückt man Taster 2, leuchtet LED 2 und es wird nur der Programmabschnitt benutzt, welcher für Programm 2 zuständig ist.

Warum willst Du es kompliziert machen und "Taster" verwenden?

Warum nicht einfach mit Kippschaltern, die zwei stabile Schaltlagen haben?
Sagen wir Schalter hoch = 1 und Schalter runter = 0

Dann machst Du eine große Hauptloop, in der die Stellung der Kippschalter abgefragt wird, und je nachdem rufst Du dann Deine verschiedenen Unterprogramme auf. Mit zwei Kippschaltern hast Du insgesamt vier Schaltmöglichkeiten:

Pseudo-Programmablauf:

// Pins für 2 Kippschalter
#define S1 4
#define S2 5

void setup()
{
  pinMode(S1,INPUT);
  pinMode(S2,INPUT);
}

void loop00()
{}

void loop01()
{}

void loop10()
{}

void loop11()
{}

void loop()
{
  if (digitalRead(S1)==0 && digitalRead(S2)==0) loop00();
  if (digitalRead(S1)==0 && digitalRead(S2)==1) loop01();
  if (digitalRead(S1)==1 && digitalRead(S2)==0) loop10();
  if (digitalRead(S1)==1 && digitalRead(S2)==1) loop11();
}

Wenn die Schalter 0 und 0 liefern, wird immer die loop00 aufgerufen.
Wenn die Schalter 0 und 1 liefern, wird immer die loop01 aufgerufen.
Und so weiter. 2 Kippschalter steuern 4 Programme, 3 Kippschalter 8 Programme, 4 Kippschalter 16 Programme etc., alles je nach Stellung der Kippschalter.

Mit Tastern, die beim Betätigen wieder in die Ausgangslage zurückfedern, kann man vergleichbares programmieren.
Das ist aber für Anfänger nicht ganz so einfach zu programmieren, weil Du Statusänderungen an den Tasten verwalten mußt.

Oh Danke, sind ja schon ein paar Antworten da.

Es soll schon 1 Taster pro Programm werden. Ich denke maximal 4 Programme, also 4 Taster.
Mit Schalter wärs sicher einfacher, aber mit Taster ist es besser zu bedienen und sieht auch viel besser aus. :slight_smile:

Als Anfänger muß ich mir eure Vorschläge aber erst mal duch den Kopf gehen lassen und rumprobieren, ist ja nicht so einfach...

Du kannst auch das von jurs für Taster abwandeln. Das ist am einfachsten.

Die Taster nacheinander abfragen und dann für jeden Taster eine eigene Methode aufrufen. Entprellen der Taster nicht vergessen.

Thhherapy:
Es soll schon 1 Taster pro Programm werden.

Ah, zum Glück hat sich der Hersteller meines Satelliten-Receivers nicht dasselbe überlegt, sonst hätte ich hier für einen SAT-Receiver mit 4000 Programmen wahrscheinlich eine Fernbedienung mit 4000 Tasten auf dem Tisch liegen.

Anderes Codebeispiel (Code UNGETESTET):

// INPUTTYPE kann auf INPUT oder INPUT_PULLUP gesetzt werden
// Mit INPUT_PULLUP werden die internen PullUp-Widerstände aktiviert
#define INPUTTYPE INPUT_PULLUP

byte taster[]={4,5,6,7};
byte leds[]={8,9,10,11};

void setup()
{
  for (int i=0;i<4;i++)
  {
    pinMode(taster[i],INPUTTYPE);
    pinMode(leds[i],OUTPUT);
  }
  setProgram(0); // Erstes Programm einstellen
}

void setProgram(byte b)
// Schaltet die LED des zugeordneten Programms ein
// Parameter b: zu setzendes Programm
{
  for (int i=0;i<4;i++)
  {
    if (i==b)  // bei gesetztem Programm LED ein
      digitalWrite(leds[i],HIGH);
    else  // sonst LED aus
      digitalWrite(leds[i],LOW);
  }
}

void handleButton()
// Funktion setzt die LED, die der zuletzt gedrückten Taste zugeordnet ist
{
  for (int i=0;i<4;i++)
  {
    byte pressed=digitalRead(taster[i]);
    if (INPUTTYPE==INPUT_PULLUP) pressed=!pressed; // vertauschte Logik
    if (pressed) setProgram(i);
  }  
}

void loop0()
{}

void loop1()
{}

void loop2()
{}

void loop3()
{}

void loop()
{
  byte program=0;
  for (int i=0;i<4;i++)
  { // das gerade gesetzte Programm aus der gerade leuchtenden LED abfragen
    if (digitalRead(leds[i])) program=i;
  }  
  switch(program)
  {
    case 0: loop0();break;
    case 1: loop1();break;
    case 2: loop2();break;
    case 3: loop3();break;
  }
}

Ich habe den Code gleich für die Aktivierung der internen PullUp-Widerstände vorgesehen, dann brauchst Du keine externen PullDown-Widerstände an den Tastern. Und LEDs werden auch bereits geschaltet.

Sei lieber froh das dir dein Sat-Hersteller nicht 12 Kippschalter eingebaut hat. :smiley:

Mit einem Taster 4 LED duchschalten würde auch funktionieren, egal.
Danke, werd das mal durchprobieren.

Thhherapy:
Danke, werd das mal durchprobieren.

Wie mir beim nochmaligen Überfliegen des geposteten Codes gerade auffällt, habe ich zwar eine Funktion "handleButton()" geschrieben, aber diese wird nirgends aufgerufen. Der Aufruf gehört irgendwo in die loop-Funktion rein, z.B. am Anfang oder am Ende der loop():
handleButton();

Ok, werd ich noch einfügen.
Hab schon etwas rumprobiert, aber noch nicht zum laufen gebracht.
Bin grad am "entschlüsseln" von dem Code.

void setProgram(byte b)

versteh ich noch nicht so ganz.
Was sagt das aus?
b soll dann gleich i sein, aber wo wird die Größe von b angegeben?

Beim Aufruf der Funktion:

setProgram(i)

Da wird dann i nach b kopiert

Thhherapy:
Bin grad am "entschlüsseln" von dem Code.

Die Funktion "handleButton()" geht alle vier Buttons mit Laufindex i durch.
Wenn eine Taste gedrückt ist, wird "setProgram(i)" aufgerufen.

In der Funktion setProgram ist der übergebene Parameter als "b" benannt. Das ist eine Kopie des Parameters i, der beim Funktionsaufruf an die Funktion übergeben wurde.

Die Funktion setProgram(byte b) geht nun alle vier LEDs durch, wenn die Nummer des übergebenen Buttons mit der Nummer der LED identisch ist, wird die LED eingeschaltet. Andernfalls ausgeschaltet.

Und in der loop werden nun reihum alle LEDs ausgelesen, ob sie ein- oder ausgeschaltet sind: Und entsprechend der eingeschalteten LED wird nun entweder loop0, loop1, loop2 oder loop3 immer wieder aufgerufen.

So dass Du nun vier verschiedene Loop-Funktionen hast, die immer wieder aufgerufen werden, abhängig davon, welche LED leuchtet. Und welche LED leuchtet ist davon abhängig, welcher Button zuletzt gedrückt wurde.

Thhherapy:
noch nicht zum laufen gebracht.

Je nachdem, ob Du die Buttons mit PullDown- oder PullUp-Widerständen angeschlossen hast, mußt Du im Programm entweder
#define INPUTTYPE INPUT
oder
#define INPUTTYPE INPUT_PULLUP
setzen, damit die Buttons bei der Abfrage das erwartete Ergebnis zurückliefern.

Es tut sich was!

Aber erst als ich duch rumprobieren die Taster Massegeschalten gemacht habe.
War das Absicht? Sowas bin ich nicht gewohnt. :slight_smile:

Mir ist jetzt aufgefallen das das umschalten ja nur dann funktioniert, wenn der gerade aktive Loop am Ende ist und von vorne beginnt. (ist irgendwie logisch wo ich jetzt darüber nachdenke)
Ich weis noch nicht genau ob das bei dem was ich vorhab relevant ist.
Könnte man sowas noch umgehen?

Thhherapy:
Aber erst als ich duch rumprobieren die Taster Massegeschalten gemacht habe.
War das Absicht? Sowas bin ich nicht gewohnt. :slight_smile:

Ja klar ist das Absicht. Ich bin ne faule Socke und habe keine Lust, externe PullDown-Widerstände an Buttons zu verschalten. Stattdessen schließe ich einen Button ohne externen Widerstand nur an GND und seinen Pin an und aktiviere mit INPUT_PULLUP den im Atmega eingebauten internen PullUp-Widerstand. Dadurch vertauscht sich die Programmlogik und ein gedrückter Button wird LOW, während ein nicht gedrückter Button HIGH liefert.

Der Sketch selbst ist aber für beides vorbereitet und Du brauchst nur INPUTTYPE im Sketch ändern.

Thhherapy:
Mir ist jetzt aufgefallen das das umschalten ja nur dann funktioniert, wenn der gerade aktive Loop am Ende ist und von vorne beginnt. (ist irgendwie logisch wo ich jetzt darüber nachdenke)
Ich weis noch nicht genau ob das bei dem was ich vorhab relevant ist.
Könnte man sowas noch umgehen?

Dass irgendwie dann eine loop0 zur Hälfte, eine loop1 zu zwei Drittel, eine loop2 zu ein fünftel und eine loop3 zu ein siebtel abgearbeitet ist und dann wird umgeschaltet?

Vergiß es oder frage in der betroffenen loop selber ab, ob noch die "richtige" LED für diese loop leuchtet und wenn nicht, verlasse die loop mit "return"!

Eine "normal" programmierte loop-Funktion läuft mehrere tausend mal pro Sekunde durch, sagen wir mal viertausend mal pro Sekunde. Dann erfolgt eine Umschaltung spätestens eine viertausendstel Sekunde, nachdem Du die Taste gedrückt hast.

Sag nicht, eine viertausendstel Sekunde ist zu lang als Umschaltdauer!

Wenn Deine loop nicht so oft läuft, dann liegt das vermutlich daran, dass Du mit "delay()" programmierst.
Gewöhne Dir halt das Programmieren mit delay() ab, das ist für ALLE interaktiven Programme absolut notwendig, wenn diese schnell auf Interaktionen reagieren solllen, z.B. auf gedrückte Buttons.

Ach so, mit Pullup wird der automatisch invertiert. Ist eigentlich klar wenn ich so darüber nachdenke.
Ich sollte wohl doch bei den analogen Schaltungen bleiben....

Ja, ich hab zum testen ein einfaches Blink-Programm reingeschrieben, da war eben dieses delay dabei.
Wieder was gelernt.

Das Programm läuft übrigens so wie ich es mir vorgestellt habe, habs ausprobiert.
Danke, du hast mir sehr geholfen!

hab doch noch ein Problem....

Hab den eigentlichen Programmcode zum testen nur in einen Loop geschrieben (in den andern loops was anderes) und da hat es funktioniert, wenn ich ihn auch in die anderen schreibe funktioniert es nicht.

Im Loop steht z.B.:

void loop0()
{
  if (irrecv.decode(&results))    // have we received an IR signal?
  {                              // Serial.println(results.value, HEX);  UN Comment to see raw values
    translateIR(); 
    irrecv.resume();              // receive the next value
  } 
 
}
void translateIR()             // takes action based on IR code received                            
                               // describing KEYES Remote IR codes 
{
  switch(results.value)
  {
  case 0x9B83842D: Keyboard.write('1');    break;         // 1
  case 0x30CD5BE2: Keyboard.write('2');    break;         // 2
  case 0xD051C300: Keyboard.write('3');    break;         // 3
  case 0x613F0C2D: Keyboard.write('4');    break;         // 4
  case 0xC17C1F16: Keyboard.write('5');    break;         // 5
  case 0x91799AD5: Keyboard.write('6');    break;         // 6
  case 0x30137BB8: Keyboard.write('7');    break;         // 7
  case 0x22C5F96C: Keyboard.write('8');    break;         // 8
  case 0x722B04B6: Keyboard.write('9');    break;         // 9
  }
  delay(20);          
}

Das liegt ja sicher daran das der loop aus ist und "void translateIR()" anfängt. Was ja irgendwas eigenes zu sein scheint.
So viel kenn ich mich leider noch nicht aus.
Kann man das irgendwie richtig reinschreiben oder hab ich so generell ein Problem?

Thhherapy:
Hab den eigentlichen Programmcode zum testen nur in einen Loop geschrieben (in den andern loops was anderes) und da hat es funktioniert, wenn ich ihn auch in die anderen schreibe funktioniert es nicht.

Vermeide "es", das nicht funktioniert (was immer das auch sein mag) und Du bist auf gutem Wege!

Habs hinbekommen, schön langsam kapier ich das ganze.

Gibts eigentlich keinen Befehl um eine LED nur kurz aufblinken zu lassen? Anscheinend nicht, sonnst hätt ich was gefunden.
Mit Einschalten, Pause und Ausschalten ist ja auch irgendwie blöd.

Hier der fertige Code mit Sendebeispielen, villeicht hilfs noch jemanden.

#define INPUTTYPE INPUT_PULLUP
#include "IRremote.h"

byte taster[]={4,5,6};
byte leds[]={8,9,10};
int led = 13;
int receiver = 11;                 // receiver input pin

IRrecv irrecv(receiver);           // create instance of 'irrecv'
decode_results results;            // create instance of 'decode_results'

void setup()
{
  for (int i=0;i<3;i++)
  {
    pinMode(taster[i],INPUTTYPE);
    pinMode(leds[i],OUTPUT);
    pinMode(led, OUTPUT);
  }
  setProgram(0);                      // Erstes Programm einstellen

  irrecv.enableIRIn();           // startet den Receiver
  Keyboard.begin();              // startet Keybord


}

void setProgram(byte b)
                                                    // Schaltet die LED des zugeordneten Programms ein
                                                      // Parameter b: zu setzendes Programm
{
  for (int i=0;i<3;i++)
  {
    if (i==b)                                       // bei gesetztem Programm LED ein
      digitalWrite(leds[i],HIGH);
    else                                                  // sonst LED aus
      digitalWrite(leds[i],LOW);
  }
}

void handleButton()
                                                   // Funktion setzt die LED, die der zuletzt gedrückten Taste zugeordnet ist
{
  for (int i=0;i<3;i++)
  {
    byte pressed=digitalRead(taster[i]);
    if (INPUTTYPE==INPUT_PULLUP) pressed=!pressed;                      // vertauschte Logik
    if (pressed) setProgram(i);
  }  
}

void loop0()
{
  if (irrecv.decode(&results))    // Wenn ein Signal empfangen wird
  {
    translateIR();                // führt Funktion translateIR aus
    irrecv.resume();              // warte auf nächstes Signal
    digitalWrite(led, HIGH);      // Statusled leuchtet kurz auf
    delay(20);
    digitalWrite(led, LOW);
  } 
}


void loop1()
{
  if (irrecv.decode(&results))    // Wenn ein Signal empfangen wird
  {
    translateIR1();               // führt Funktion translateIR1 aus
    irrecv.resume();              // warte auf nächstes Signal
    digitalWrite(led, HIGH);      // Statusled leuchtet kurz auf
    delay(20);
    digitalWrite(led, LOW);
  }             
}


void loop2()
{
  if (irrecv.decode(&results))    // Wenn ein Signal empfangen wird
  {
    translateIR2();               // führt Funktion translateIR2 aus
    irrecv.resume();              // warte auf nächstes Signal
    digitalWrite(led, HIGH);      // Statusled leuchtet kurz auf
    delay(20);
    digitalWrite(led, LOW);
  }   
}


void loop()
{
  handleButton();
  byte program=0;
  for (int i=0;i<3;i++)
  {                                                    // das gerade gesetzte Programm aus der gerade leuchtenden LED abfragen
    if (digitalRead(leds[i])) program=i;
  }  
  switch(program)                                     // Loopauswahl
  {
    case 0: loop0();break;
    case 1: loop1();break;
    case 2: loop2();break;
  }

  
}


void translateIR()                                          // Tastenauswahl für erstes Programm
{
  switch(results.value)
  {
  case 0x9B83842D: Keyboard.write('1');    break;         // 1
  case 0x30CD5BE2: Keyboard.write('2');    break;         // 2
  case 0xD051C300: Keyboard.write('3');    break;         // 3
  case 0x613F0C2D: Keyboard.write('4');    break;         // 4
  case 0xC17C1F16: Keyboard.write('5');    break;         // 5
  case 0x91799AD5: Keyboard.write('6');    break;         // 6
  case 0x30137BB8: Keyboard.write('7');    break;         // 7
  case 0x22C5F96C: Keyboard.write('8');    break;         // 8
  case 0x722B04B6: Keyboard.write('9');    break;         // 9
  }
  delay(20);
}


void translateIR1()                                         // Tastenauswahl für zweites Programm
{
  switch(results.value)
  {
  case 0x9B83842D: Keyboard.write('a');    break;         // 1
  case 0x30CD5BE2: Keyboard.write('b');    break;         // 2
  case 0xD051C300: Keyboard.write('c');    break;         // 3
  case 0x613F0C2D: Keyboard.write('d');    break;         // 4
  case 0xC17C1F16: Keyboard.write('e');    break;         // 5
  case 0x91799AD5: Keyboard.write('f');    break;         // 6
  case 0x30137BB8: Keyboard.write('g');    break;         // 7
  case 0x22C5F96C: Keyboard.write('h');    break;         // 8
  case 0x722B04B6: Keyboard.write('i');    break;         // 9
  }
  delay(20);
}


void translateIR2()                                         // Tastenauswahl für drittes Programm
{
  switch(results.value)
  {
  case 0x9B83842D: Keyboard.write('j');    break;         // 1
  case 0x30CD5BE2: Keyboard.write('k');    break;         // 2
  case 0xD051C300: Keyboard.write('l');    break;         // 3
  case 0x613F0C2D: Keyboard.write('m');    break;         // 4
  case 0xC17C1F16: Keyboard.write('n');    break;         // 5
  case 0x91799AD5: Keyboard.write('o');    break;         // 6
  case 0x30137BB8: Keyboard.write('p');    break;         // 7
  case 0x22C5F96C: Keyboard.write('q');    break;         // 8
  case 0x722B04B6: Keyboard.write('r');    break;         // 9
  }
  delay(20);
}