Switch Case Switch nicht

Nachdem mein Problem mit den return bei en Funktionen relativ leicht zu lösen war, dachte ich "Jetzt gehts vorwärts"....scheiße wars.

ich habe diesen Code.


#include <Adafruit_MCP23X17.h>
#include <SoftwareSerial.h>
#define encoderPinA A1 // CLK pin of Rotary Enocoder
#define encoderPinB A2 // DT pin of Rotary Enocoder
#define TX 3
#define RX 2
int encoderPinALast = LOW;
int encoderPinANow = LOW;



SoftwareSerial mySerial (RX,TX);

Adafruit_MCP23X17 mcp;
byte MCPADR=0x20;

byte PoM=0;
byte PoMt=0;
byte val=0;
bool Send=false;
bool ButtonCall=false;

byte IDB=0;
byte IDC=0;
byte Moist=0;
byte MoistMin=0;
byte MoistMax=0;
byte Hum=0;
byte HumMin=0;
byte HumMax=0;


 void setup() { 
   pinMode (RX,INPUT);
   pinMode (TX,OUTPUT);
   pinMode (encoderPinA,INPUT_PULLUP);
   pinMode (encoderPinB,INPUT_PULLUP);
   mySerial.begin(9600);
   Serial.begin (9600);
    Serial.println("PROGRAMMER TEST");
   if (!mcp.begin_I2C()) {
    Serial.println("Error.");
    while (1);{ Serial.print("Hänge Fest");
      }
    }

for(int i=0;i<16;i++){
  Serial.println("Before mcp.pinmode");
    mcp.pinMode(i, OUTPUT);
    Serial.print("PinMode OUTPUT FOR PIN");  Serial.println(i);
  }
 }
 void loop() { 
switch(PoM){
case 0:{
          
          if(PoMt<1){PoMt=9;}
          if(PoMt>9){PoMt=1;}
          PoMt=+encode(PoMt);
          MenuLED(PoMt);
          Serial.print("MENU== ");Serial.println(PoM);
          Serial.print("MENUt= ");Serial.println(PoMt);
          Serial.print("BytesReady: ");Serial.println(mySerial.available());
          Serial.print("READ: ");Serial.println(mySerial.read());
          Serial.print("ButtonState: ");Serial.println(ButtonDown());
          if(ButtonDown()){
                            
                            mySerial.write(PoM);
                            PoM=PoMt; 
                            
          }//IF ButtonDown
  }//case0
;break;
case 1:{
          
          if(val<0){val=7;}
          if(val>7){val=0;}
          if(mySerial.available()) { 
                                    Serial.println("Have Some Data for IDB");
                                    IDB=mySerial.read();
                                    SevenSegment(IDB);
                                    val=IDB;}
          if(ButtonDown());{

                            }
          
          val=+encode(val);
          Serial.print("IDB ");Serial.println(val);
          SevenSegment(val);          
    }//PoM==1
;break;
case 2:{
          while(ButtonDown){}
          if(mySerial.available()) {
                                    Serial.println("Have Some Data for IDC");
                                    IDC=mySerial.read();
                                    Serial.println(IDC);
                                    SevenSegment(IDC); }

          if(ButtonDown());{
                            
                            }
    }//PoM==1
      ;break;
  }//Switch
}//LOOP
 


int MenuLED(int i){
switch(i){
case  0:digitalWrite(9,LOW);digitalWrite(10,LOW);digitalWrite(11,LOW);digitalWrite(12,LOW);digitalWrite(13,LOW);break;


case  1:digitalWrite(9,HIGH);digitalWrite(10,LOW);digitalWrite(11,LOW);digitalWrite(12,HIGH);digitalWrite(13,LOW);break;
case  2:digitalWrite(9,HIGH);digitalWrite(10,LOW);digitalWrite(11,LOW);digitalWrite(12,LOW);digitalWrite(13,HIGH);break;

case  3:digitalWrite(9,LOW);digitalWrite(10,HIGH);digitalWrite(11,LOW);digitalWrite(12,LOW);digitalWrite(13,LOW);break;
case  4:digitalWrite(9,LOW);digitalWrite(10,HIGH);digitalWrite(11,LOW);digitalWrite(12,HIGH);digitalWrite(13,LOW);break;
case  5:digitalWrite(9,LOW);digitalWrite(10,HIGH);digitalWrite(11,LOW);digitalWrite(12,LOW);digitalWrite(13,HIGH);break;

case  6:digitalWrite(9,LOW);digitalWrite(10,LOW);digitalWrite(11,HIGH);digitalWrite(12,LOW);digitalWrite(13,LOW);break;
case  7:digitalWrite(9,LOW);digitalWrite(10,LOW);digitalWrite(11,HIGH);digitalWrite(12,HIGH);digitalWrite(13,LOW);break;
case  8:digitalWrite(9,LOW);digitalWrite(10,LOW);digitalWrite(11,HIGH);digitalWrite(12,LOW);digitalWrite(13,HIGH);break;
}
}//MENULED

int SevenSegment(int i){
  int a;
  int b;
  if(i<10){a=0;b=i;}
  else if(i<20){a=1;b=i-10;}
   else if(i<30){a=2;b=i-20;}
    else if(i<40){a=3;b=i-30;}
     else if(i<50){a=4;b=i-40;}
      else if(i<60){a=5;b=i-50;}
       else if(i<70){a=6;b=i-60;}
        else if(i<80){a=7;b=i-70;}
         else if(i<90){a=8;b=i-80;}
          else if(i<100){a=9;b=i-90;}
switch(b){
case 0:mcp.digitalWrite(1,0);mcp.digitalWrite(2,0);mcp.digitalWrite(3,0);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,1);break;
case 1:mcp.digitalWrite(1,1);mcp.digitalWrite(2,1);mcp.digitalWrite(3,1);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,1);mcp.digitalWrite(7,1);break;
case 2:mcp.digitalWrite(1,1);mcp.digitalWrite(2,0);mcp.digitalWrite(3,0);mcp.digitalWrite(4,1);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,0);break;
case 3:mcp.digitalWrite(1,1);mcp.digitalWrite(2,1);mcp.digitalWrite(3,0);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,0);break;
case 4:mcp.digitalWrite(1,0);mcp.digitalWrite(2,1);mcp.digitalWrite(3,1);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,1);mcp.digitalWrite(7,0);break;
case 5:mcp.digitalWrite(1,0);mcp.digitalWrite(2,1);mcp.digitalWrite(3,0);mcp.digitalWrite(4,0);mcp.digitalWrite(5,1);mcp.digitalWrite(6,0);mcp.digitalWrite(7,0);break;
case 6:mcp.digitalWrite(1,1);mcp.digitalWrite(2,0);mcp.digitalWrite(3,0);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,0);break;
case 7:mcp.digitalWrite(1,1);mcp.digitalWrite(2,1);mcp.digitalWrite(3,1);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,1);break;
case 8:mcp.digitalWrite(1,0);mcp.digitalWrite(2,0);mcp.digitalWrite(3,0);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,0);break;
case 9:mcp.digitalWrite(1,0);mcp.digitalWrite(2,1);mcp.digitalWrite(3,0);mcp.digitalWrite(4,0);mcp.digitalWrite(5,0);mcp.digitalWrite(6,0);mcp.digitalWrite(7,0);break;

}
switch(a){
case 0:mcp.digitalWrite(8,0);mcp.digitalWrite(9,0);mcp.digitalWrite(10,0);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,1);break;
case 1:mcp.digitalWrite(8,1);mcp.digitalWrite(9,1);mcp.digitalWrite(10,1);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,1);mcp.digitalWrite(14,1);break;
case 2:mcp.digitalWrite(8,1);mcp.digitalWrite(9,0);mcp.digitalWrite(10,0);mcp.digitalWrite(11,1);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,0);break;
case 3:mcp.digitalWrite(8,1);mcp.digitalWrite(9,1);mcp.digitalWrite(10,0);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,0);break;
case 4:mcp.digitalWrite(8,0);mcp.digitalWrite(9,1);mcp.digitalWrite(10,1);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,1);mcp.digitalWrite(14,0);break;
case 5:mcp.digitalWrite(8,0);mcp.digitalWrite(9,1);mcp.digitalWrite(10,0);mcp.digitalWrite(11,0);mcp.digitalWrite(12,1);mcp.digitalWrite(13,0);mcp.digitalWrite(14,0);break;
case 6:mcp.digitalWrite(8,1);mcp.digitalWrite(9,0);mcp.digitalWrite(10,0);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,0);break;
case 7:mcp.digitalWrite(8,1);mcp.digitalWrite(9,1);mcp.digitalWrite(10,1);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,1);break;
case 8:mcp.digitalWrite(8,0);mcp.digitalWrite(9,0);mcp.digitalWrite(10,0);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,0);break;
case 9:mcp.digitalWrite(8,0);mcp.digitalWrite(9,1);mcp.digitalWrite(10,0);mcp.digitalWrite(11,0);mcp.digitalWrite(12,0);mcp.digitalWrite(13,0);mcp.digitalWrite(14,0);break;
}

}//SevenSegment



bool ButtonDown(){
  bool val=false;
  if(digitalRead(A0)==1){
  Serial.println("ButtonDown");
val=true;

  while(digitalRead(A0)){}
  }
  
  return val;
  
}//VOID BUTTONDOWN


int encode(int encoderPos){
  encoderPinANow = digitalRead(encoderPinA);
  if ((encoderPinALast == HIGH) && (encoderPinANow == LOW)) {
    if (digitalRead(encoderPinB) == HIGH) {
      encoderPos++;
    } else {
      encoderPos--;
    }
  }
  encoderPinALast = encoderPinANow;
  return(encoderPos);
}//ENCODE

Dieser soll ein Menü steuern

im case 0 soll er sich einen Menüpunkt aussuchen (PoMt(PointOfMenuTemporary) und mit der Taste soll der Menüpunkt gesetzt werden (PoM(PointOfMenu)

das wäre dieser Part

case 0:{
          
          if(PoMt<1){PoMt=9;}
          if(PoMt>9){PoMt=1;}
          PoMt=+encode(PoMt);
          MenuLED(PoMt);
          Serial.print("MENU== ");Serial.println(PoM);
          Serial.print("MENUt= ");Serial.println(PoMt);
          Serial.print("BytesReady: ");Serial.println(mySerial.available());
          Serial.print("READ: ");Serial.println(mySerial.read());
          Serial.print("ButtonState: ");Serial.println(ButtonDown());
          if(ButtonDown()){
                            
                            mySerial.write(PoM);
                            PoM=PoMt;                 
          }//IF ButtonDown
  }//case0
;break;

nun habe ich das Problem das aus irgend einem Grund der Switch nach dem drücken der Taste im Case0 verbleibt und mir folgendes ausgibt

20:59:49.631 -> ButtonState: ButtonDown
20:59:49.664 -> 1
20:59:49.664 -> MENU== 0
20:59:49.664 -> MENUt= 1
20:59:49.664 -> BytesReady: 0
20:59:49.696 -> READ: -1

und das obwohl da ja eig steht

if(ButtonDown()){
                            
                            mySerial.write(PoM);
                            PoM=PoMt; 
                            
          }//IF ButtonDown

Evtl. solltest Du vor der Auswertung von PoM im Switch/Case dieser Variablen erst mal einen sinnvollen Wert zuweisen.

Ansonsten lass Dir vor dem Switch/Case immer den Wert von PoM auf die Serielle Konsole ausgeben.

Gruß Tommy

Mein Compiler ist mit dem Code nicht ganz zufrieden.

val ist ein byte und kann daher nie negativ werden.

int MenuLED(int i){

Die Funktion gibt keinen Wert zurück.

int SevenSegment(int i){

Die Funktion gibt keinen Wert zurück.

a und b in SevenSegment könnten ohne Initialisierung verwendet werden.

1 Like

Das stimmt natürlich das sind void Funktionen.

a und b haben ne 0 spendiert bekommen

die bytes wurden in int8_t umgeändert

Ich hab grad noch das hier im compiler gefunden

/Users/Documents/Arduino/SensorProgrammer2/SensorProgrammer2.ino: In function 'void loop()':
/Users/Documents/Arduino/SensorProgrammer2/SensorProgrammer2.ino:94:17: warning: the address of 'bool ButtonDown()' will never be NULL [-Waddress]
           while(ButtonDown){}

bezieht sich wohl auf diese Funktion

bool ButtonDown(){
  bool BD=false;//lege variable an und setze diese false
  if(digitalRead(A0)==1){ //Guck ob der button gedrückt wurde
  Serial.println("ButtonDown");
  BD=true;//wenn ja dann setze variable true
  while(digitalRead(A0)==1){}//warte bis der Button losgelassen wird
  }
  return BD;//return ob der button gedrückt wurde(nach loslassen)
}//Bool BUTTONDOWN

Wenn der Fall i = 100 oder größer eintritt, wird a und b kein Wert zugewiesen, weil keine der Bedingungen zutrifft.
Beim switch(b) bzw. weiter unten switch(a) arbeitest Du dann mit einer nicht initialisierten Variablen b.

Grundsätzlich:
Wenn innerhalb einer Funktion eine (lokale) Variable angelegt wird, ist deren Inhalt unbestimmt. Globale Variablen wie z.B. das byte PoM werden auf 0 initialisiert.

Edit: Ja, ButtonDown ist immer ungleich Null, weil es (vereinfacht) die Adresse im Programmspeicher ist, an der die Funktion anfängt. Wahrscheinlich willst Du die Funktion aufrufen - dann fehlen die Klammern: while(ButtonDown()).

1 Like

Das verstehe ich nicht ganz. Der wert von PoM ist ja als default 0 definiert über das

int PoM=0;

damit sollte PoM doch einen sinnvollen wert haben.

In der If Funktion

if(ButtonDown()){
                            
                            mySerial.write(PoM);
                            PoM=PoMt; 
                            
          }//IF ButtonDown

Soll ja PoM gesetzt werden undzwar bekommt es den Wert PoMt.
PoMt ist auch default 0 und variiert zwischen 0 und 9 was ja sinnvolle werte sind.
Im Serialprint wird mir auch angezeigt das PoMt sinnvolle werte hat

11:57:53.313 -> MENUt= 3
11:57:54.313 -> MENUt= 5
11:57:54.380 -> MENUt= 4

und das das IF gecalled wird bekomm ich auch gesagt da in der ButtonDown Funktion ein Print"ButtonDown" drin ist.

11:59:31.268 -> ButtonState: ButtonDown

die Frage die sich stellt ist, warum wird PoM nicht überschrieben.

Ich glaube das Problem gefunden zu haben

bool ButtonDown(){
  bool BD=false;
  if(digitalRead(A0)==1){
  Serial.println("ButtonDown");
  BD=true;
  }
while(digitalRead(A0)==1){}
  return BD;
}//VOID BUTTONDOWN

die Zeile

while(digitalRead(A0)==1){}

sollte verhindern das bei gedrücktem Button das ButtonDonwn "Event" mehrfach gecalled wird.
aber das muss ans ende vom if und er Main sonst verharrt er dort und führt den if teil nicht aus. (zumindest wenn ich das lösche geht es, ich weis nicht ob meine Beurteilung des beobachteten richtig ist)

1 Like

Moin @Mathrim,

wenn Du genau hinschaust, siehst Du, dass hinter "ButtonDown" im while-Statement die beiden Klammern fehlen. Damit prüft der Code, ob die Adresse von ButtonDown Null ist und nicht den Rückgabewert.

Es müsste so heißen:

while( ButtonDown() ){}

Gruß
ec2021

P.S.: Der folgende Code

  a = round(i/10);
  b = i - a*10;

sollte das gleiche Ergebnis liefern wie:

if(i<10){a=0;b=i;}
  else if(i<20){a=1;b=i-10;}
   else if(i<30){a=2;b=i-20;}
    else if(i<40){a=3;b=i-30;}
     else if(i<50){a=4;b=i-40;}
      else if(i<60){a=5;b=i-50;}
       else if(i<70){a=6;b=i-60;}
        else if(i<80){a=7;b=i-70;}
         else if(i<90){a=8;b=i-80;}
          else if(i<100){a=9;b=i-90;}
1 Like

Das ist ziemlich egal. Das Verhalten ist auf jeden Fall, dass die Funktion ButtonDown() entweder sofort mit false zurückkommt oder solange hängt bis Pin A0 wieder LOW ist und dann true liefert.

Ob du dies in ein while ( ButtonDown() ) { /* einmal pro Tastendruck */ } oder ein if packst, ist egal. ( Entprellen von Tastern geht so nicht )

Hallo
Willst du entprellen oder eine Flanke erkennen?

Entprellen kannst du auf die schnelle , etwas schmutzige Art mit einem delay(10) im loop versuchsweise.

Um eine Flanke zu erkennen, Wechsel des Zustandes , benötigst du eine zusätzliche bool variable die sich den letzten Zustand merkt. Etwa so
Wenn gedrückt und beim letzten mal noch nicht gedruckt war dann mach was.

Es gibt libs dafür die machen beides gleichzeitig.

naja Ziehlstellung ist, das der Taster wenn er gedrückt wird nur einmal auslöst bis er wieder losgelassen wird.

Das Problem ist, das so wie ich das mache

bool BS=true;  

bool ButtonDown(){
  bool BD=false;

  if(digitalRead(A0)==0&&BS==true){  
  
  Serial.println("ButtonDown");
  BD=true;
  BS=false;  
  }
  if(digitalRead(A0)==0){BS=true;
   Serial.println("ButtonUp");}
  
  return BD;
}//VOID BUTTONDOWN

es nicht funktioniert da irgendwie der Button zwischendurch als UP erkannt wird.

also wenn ich en Button drücke sieht das so aus im Print


15:18:51.995 -> ButtonDown
15:18:51.995 -> ButtonUp

15:18:52.027 -> ButtonDown
15:18:52.059 -> ButtonUp

15:18:52.123 -> ButtonDown
15:18:52.123 -> ButtonUp

das ist die ausgaben bei einem Tastendruck

mein Aufbau sieht so aus

also ButtonUp ist High und Button Down ist low

Hallo
entprellen musst Du ja nicht mehr , das hast Du ja mit der externen Beschaltung gemacht, also kannst Du auf das entprellen und den internen Pullup verzichten

dann schau dir da mal an,

const byte pin = 2;
bool jetzt; // aktueller Status
bool eben;; // letzter status

void setup() {
  // put your setup code here, to run once:
  pinMode(pin, INPUT_PULLUP); // Interner Pullup ein
// pinMode(pin,INPUT);   // bei externem Pullup
  Serial.begin(115200);

}

void loop() {
  
  jetzt = !digitalRead(pin); // Eingan einlesen
  if (jetzt == true && eben == false) { // taster würde gedrückt
    eben = true; // Zustand merken
    Serial.println("Taster wurde gedrückt");
  }
  if (jetzt == false) eben = false; //reset merker
  
  delay(10); //entprellen
}

Hallo,
wenn du das jetzt in eine function machen willst dann könnte das so aussehen. Wichtig in dem Fall die Variable "eben". Da gibt es zwei Möglichkeiten entweder global definieren oder als static in der function. Mehrfach kannst Du die function aber so nicht nutzen. Dazu müsstest Du eine classe und eine Instanz von der Methode buttondown anlegen.

Beispiel als function
const byte pin = 2;

void setup() {
  // put your setup code here, to run once:
  pinMode(pin, INPUT_PULLUP);
  Serial.begin(115200);
}

void loop() {

  if (buttondown(pin)) {
    Serial.println("Taster wurde gedrückt");
  }

  delay(10); //entprellen
}

bool buttondown(const byte p) { // function buttondown

  bool flag = false;
  static bool eben = false;
  bool jetzt = false;

  jetzt = !digitalRead(p);
  flag = false;

  if (jetzt == true && eben == false) {
    eben = true;
    flag = true;
  }

  if (jetzt == false) {
    eben = false;
  }
  return flag;
}
1 Like

Weil eben ja immer den vorherigen Wert speichert, würde ich das ersetzen durch

  if (jetzt && !eben) {
    flag = true;
  }
  eben = jetzt;
2 Likes

Hallo,
danke für den guten Hinweis stimmt natürlich :wink:

Ich habe das ganze nochmal Komplet umgebaut. Der Code beinhaltet nun überhaupt keine Debounce Funktion mehr und ich habe Hardwareseitig einen SSN74LS14N 6-Fach Schmitt Trigger eingebaut. Nun ist das Ganze super Clean und holpert auch nicht mehr.

Die Schaltung jeweils an encoder A und B und einen für den Button und alles ist super.

Das ist zwar eine alte, bewährte Methode die auch gut funktioniert.
Nur warum zusätzliche Hardware, wenn man alles einfach mit dem Controller im Code erledigen kann ?

naja wir behandeln gerade OPV und da kam der Schmitt Trigger mit vor und da wollt ich das einfach mal probieren. nd ich habe jetzt an Software Lösungen so viel zeit verloren und mit dem ding war es eher so

  1. Einbauen
  2. Fertig

Das war mal ne nette Abwechslung

Jeder AVR hat Schmitt Trigger Eingänge.
Es ist also kein SSN74LS14N nötig.

Zeigt Dir mein Beispiel aus der Praxis einen Grund?
Die Böhm Orgeln haben mit den Jahren Erweiterungen erfahren einen Teil der Bedintaster und ein Drehgeber werden per Sofware entprellt. Mit den Jahren (Jahr) gibt diese Funktion aber nicht mehr richtig die Tastendrücke aus. (Prellen) Alle anderen Tasten zur Bedienung tun auch noch nach Jahrzenten ihren Dienst.
Wie löst man dieses Problem? Ganz einfach nachträglich diese Taster und den Drehgeber entprellen :joy:

Kontakte putzen.
Oder die Entprellzeiten im Vorhinein groß genug wählen.