Arduino switch-case werkt niet?

Er is iets in mijn code dat ik niet begrijp.
Ik gebruik een arduino mega 2560 met een 433MHz ontvanger en een controller die ik via UART probeer te besturen. De ontvanger zit aan D2, de controller op D18 en D19.
De besturing probeer ik te doen met een switch - case.
Wat zich nu voordoet is dat er alleen gereageerd wordt op de bovenste case, niet op de rest. Wanneer ik bijvoorbeeld de tweede case bovenaan zet, reageert hij alleen daar op. Hij komt niet in de overige cases, dit heb ik gecontroleerd met de led.

Het lijkt erop dat ik de eerste case niet goed afsluit waardoor hij de tweede of derde niet wil uitvoeren wanneer ik daarom vraag. Naar wat ik heb gezocht, zou het wel op deze manier moeten werken. Onderstaand de volledige code, kan iemand mij in de goede richting sturen?

c code:


#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial1.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on interrupt 0 => that is pin #D2
}

void loop() {
  if (mySwitch.available()) 
    {
    Serial.print(mySwitch.getReceivedValue());
    unsigned long int ab = mySwitch.getReceivedValue();
    switch (ab)
    {
      case 4543491: mySwitch.disableReceive();
                    char start[8]={0x7E, 0xFF, 0x06, 0x22, 0x00, 0x1E, 0x01, 0xEF}; //start 1
                    Serial1.write((char*) start, 8);    //send command
                    break;
      case 4543500: mySwitch.disableReceive();
                    char stop[8]={0x7E, 0xFF, 0x06, 0x16, 0x00, 0x00, 0x00, 0xEF}; //stop all
                    Serial1.write((char*) stop, 8);    //send command
                    digitalWrite(LED_BUILTIN, HIGH);  // turn the check LED on
                    break;
      case 4543536: mySwitch.disableReceive();
                    char second[8]={0x7E, 0xFF, 0x06, 0x03, 0x00, 0x1E, 0x02, 0xEF}; //start 2
                    Serial1.write((char*) second, 8);    //send command
                    break;
    }
    delay(500);   //delay to avoid repeating te same code.
    digitalWrite(LED_BUILTIN, LOW);   // turn the check LED off 
    mySwitch.resetAvailable();
    mySwitch.enableReceive(0);
  }
}

[Bericht gewijzigd door Henry S. op 14 augustus 2023 20:02:14 (0%)

Every machine is a smoke machine if you operate it wrong enough

Switch case kan alleen met int of char.

Heb je alle compiler warnings wel aanstaan?
File->Preferences->Compiler warnings= ALL

- Je doet twee keer getReceivedValue(). Kan dat?, m.a.w. krijg je dan twee keer de laatste received value, of wacht ie de tweede keer op een nieuwe value?

je kunt ook Serial.print na de declaratie van ab doen, en ab printen.

Als je dat doet, zie je dan wel de waarde van de tweede of derde case op de seriele monitor verschijnen?

Je switch lijkt verder OK. Je zou een default (met foutmelding) kunnen toevoegen maar dat is niet verplicht.

@575: TS doet een switch met int. Unsigned long int, maar dat mag gewoon.

PE9SMS

Special Member

Hmmm. Moeten er geen { } om de code in een case als je er variabelen in declareert?

This signature is intentionally left blank.
Jeroen

Moderator

Op 14 augustus 2023 14:58:14 schreef PE9SMS:
Hmmm. Moeten er geen { } om de code in een case als je er variabelen in declareert?

Nee.

High met Henk

Special Member

Maak altijd een error handler in de default case..

Weet je wat er gebeurt
Hier zou ik dus ab printen..

[Bericht gewijzigd door High met Henk op 14 augustus 2023 15:29:03 (16%)

E = MC^2, dus de magnetische compatibiliteit doet kwadratisch mee???

Het lijkt erop dat ik de eerste case niet goed afsluit waardoor hij de tweede of derde niet wil uitvoeren wanneer ik daarom vraag.

Je case bestaan uit 3 hele specifiek getallen, als die getallen niet uit unsigned long int ab = mySwitch.getReceivedValue(); komen maar net een afwijkende waarde, dan zal de switch case ook correct uit gevoerde worden maar slaat hij ze alle 3 over.

Advies om dus voor nu even steeds de waarde van unsigned long int ab = mySwitch.getReceivedValue(); naar de seriele monitor te sturen

of aan je switch een default: toe te voegen die omgaat met als de waarde afwijkt.

Mensen zijn soms net als een gelijkrichter, ze willen graag hun gelijk hebben.

Bedankt voor de reacties!

@575 nee, die had ik niet allemaal aan staan, nu wel. Bedankt!
@blurp Het vreemde is dat hij de bovenste case dus wel pakt..
@hmh, De ontvangen waarde print ik al, ik zal ab ook nog toevoegen. Toch voert hij de inhoud van de case niet uit, alleen van de bovenste.
@benleentje: klopt, het zijn vreemde waardes, dit zijn de codes van een pt2622 afstandsbediening. De codes komen overeen met de case. De ontvangen waarde print ik al, ik zal ab ook nog toevoegen.

Edit: de inhoud van ab is identiek aan mySwitch.getReceivedValue(). Daar zit het probleem dus niet in.

Every machine is a smoke machine if you operate it wrong enough

Char start[8] etc in de case is denk ik het probleem. Zet dat eens bovenin de functie.

Ik begrijp nog niet helemaal waarom, maar wanneer ik { } toevoeg bij iedere case werkt het wel.

code:

      case 4543491: {mySwitch.disableReceive();
                    char start[8]={0x7E, 0xFF, 0x06, 0x22, 0x00, 0x1E, 0x01, 0xEF}; //start 1
                    Serial1.write((char*) start, 8);    //send command
                    break;}
      case 4543500: {mySwitch.disableReceive();
                    char stop[8]={0x7E, 0xFF, 0x06, 0x16, 0x00, 0x00, 0x00, 0xEF}; //stop all
                    Serial1.write((char*) stop, 8);    //send command
                    digitalWrite(LED_BUILTIN, HIGH);  // turn the check LED on
                    break;}
      case 4543536: {mySwitch.disableReceive();
                    char second[8]={0x7E, 0xFF, 0x06, 0x03, 0x00, 0x1E, 0x02, 0xEF}; //start 2
                    Serial1.write((char*) second, 8);    //send command
                    break;}
Every machine is a smoke machine if you operate it wrong enough
High met Henk

Special Member

@MAH: dat doe je niet:

c code:


  Serial.print(mySwitch.getReceivedValue());
    unsigned long int ab = mySwitch.getReceivedValue();
    switch (ab)

ik zou dit HEEL bewust zo doen:

c code:


    unsigned long int ab = mySwitch.getReceivedValue();
    Serial.print(ab);  
    switch (ab)

even tervergelijk als ik op een lijnvolger het volgende deed:

c code:


    switch (PINB & 0b00000111)
    {
       case 0:
            println("0");
            break;

       case 1:
            println("1");
            break;

       case 2:
            println("2");
            break;

       case 3:
            println("3");
            break;

       case 4:
            println("4");
            break;

       case 5:
            println("5");
            break;

       case 6:
            println("6");
            break;

       case 7:
            println("7");
            break;

       default:
            println("error");
    }

en dit leverde toch soms een error op omdat tijdens het checken de waarde veranderde: onder de motorkap deed hij namelijk hetzelfde als een IF ELSE THEN...

E = MC^2, dus de magnetische compatibiliteit doet kwadratisch mee???

De ontvangen waarde print ik al, ik zal ab ook nog toevoegen. Toch voert hij de inhoud van de case niet uit, alleen van de bovenste.

Ik zou toch goed kijken naar die AB waarde/ Kan het geen afronding zijn omdat je naar unsigned long int gaat?

En wat als je er een een long int van maakt dus even zonder unsigned erbij?

Compiler zien soms verschillen in getallen zoals een unsigned long int en long int die wij als logisch ervaren. Maar het kan ook iets zijn wat met de switch case zelf te maken heeft.
Volgens mij is een getal zoals je die in je case: zet van het signed type en niet wat je denkt unsigned.

Wat je ook kan proberen is de volgorde van die 3 getallen te veranderen dus even van groot naar klein. Voert hij dan nog steeds enkel de bovenste uit

Mensen zijn soms net als een gelijkrichter, ze willen graag hun gelijk hebben.

Op 14 augustus 2023 17:34:25 schreef MAH:
Ik begrijp nog niet helemaal waarom, maar wanneer ik { } toevoeg bij iedere case werkt het wel.

Daar zijn een paar mogelijke verklaringen voor:
- Het werkt ook zonder de {}, maar je hebt ook iets anders veranderd
- Het werkte altijd al, maar er ging iets mis in je test
- Er zit een enorme onondekte bug in je C compiler.

Ik zou in jouw geval het programma als volgt maken:

c code:



#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial1.begin(9600);
  mySwitch.enableReceive(0);  // Receiver on interrupt 0 => that is pin #D2
}

void loop() {
  if (mySwitch.available()) 
    {
    unsigned long int ab = mySwitch.getReceivedValue();
    Serial.print("switch op basis van: ");
    Serial.print(ab);
    switch (ab)
    {
      case 4543491: 
                    Serial.print("Case 4543461");
                    mySwitch.disableReceive();
                    char start[8]={0x7E, 0xFF, 0x06, 0x22, 0x00, 0x1E, 0x01, 0xEF}; //start 1
                    Serial1.write((char*) start, 8);    //send command
                    break;
      case 4543500: 
                    Serial.print("Case 4543500");
                    mySwitch.disableReceive();
                    char stop[8]={0x7E, 0xFF, 0x06, 0x16, 0x00, 0x00, 0x00, 0xEF}; //stop all
                    Serial1.write((char*) stop, 8);    //send command
                    digitalWrite(LED_BUILTIN, HIGH);  // turn the check LED on
                    break;
      case 4543536: 
                    Serial.print("Case 4543536");
                    mySwitch.disableReceive();
                    char second[8]={0x7E, 0xFF, 0x06, 0x03, 0x00, 0x1E, 0x02, 0xEF}; //start 2
                    Serial1.write((char*) second, 8);    //send command
                    break;
       default:
                    Serial.print("Error: Unhandled code");
                    break;
    }
    delay(500);   //delay to avoid repeating te same code.
    digitalWrite(LED_BUILTIN, LOW);   // turn the check LED off 
    mySwitch.resetAvailable();
    mySwitch.enableReceive(0);
  }
}
leime

Golden Member

Eerder noemde PE9SMS het al. Bij het gebruik van declaraties binnen een case moet je {} gebruiken.

Op 14 augustus 2023 17:34:25 schreef MAH:
Ik begrijp nog niet helemaal waarom, maar wanneer ik { } toevoeg bij iedere case werkt het wel.

Daarom werkt het daarmee dus wel.

Het is daarbij wel belangrijk dat je die variabele in iedere case declareert. Je mag geen "pad door het switch-case statement" hebben waarbij je die variabele niet definieert. Daarom zie ik zelf niet echt een reden om je declaratie daar te doen en zou m dus buiten de switch-case halen. (Maar ik ben geen top programmeur)

Ik zou óf één "lege" character array declareren voor je switch.

c code:

Char Bericht[8]

In je cases doe je dan:

c code:

case 4543491: 
              bericht={0x7E, 0xFF, 0x06, 0x22, 0x00, 0x1E, 0x01, 0xEF}; //start 1
              Serial1.write((char*) bericht, 8);    //send command
              break;

Wat je denk ik ook kan doen is de drie variabelen start, stop en second globaal declareren en dan alleen die sturen. Maar ik vermoed dat je de case misschien nog wel wil gaan uitbreiden. Ik twijfel welke code efficiënter is qua geheugen. (Nogmaals, ik ben geen top programmeur)

c code:

Global Char start[8]={0x7E, 0xFF, 0x06, 0x22, 0x00, 0x1E, 0x01, 0xEF};

In je cases doe je dan:

c code:

case 4543491: 
              Serial1.write((char*) start, 8);    //send command
              break;

Ik zit hier niet achter een c++ compiler, dus of eea direct compileert weet ik niet.

Op 14 augustus 2023 23:59:50 schreef leime:
Het is daarbij wel belangrijk dat je die variabele in iedere case declareert. Je mag geen "pad door het switch-case statement" hebben waarbij je die variabele niet definieert.

Waarom? Als je die declaratie binnen een { } doet is dat toch de scope van die variabele?

Alsnog vind ik het oorspronkelijke gedrag verbazend.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Op 14 augustus 2023 14:58:14 schreef PE9SMS:
Hmmm. Moeten er geen { } om de code in een case als je er variabelen in declareert?

Alleen als de verschillende cases dezelfde variabele(naam) gebruiken.

TS gebruikt verschillende namen. Het is misschien niet mooi maar wel legaal C.

Ik heb op godbolt een aantal compilers geprobeerd. gcc, clang en msvc vinden het allemaal prima zonder {}. (gcc met -Wall -pedantic voor maximale zeurderigheid)

Sommige oude microcontroller compilers (SDCC, CC65) protesteren op declaraties die niet aan het begin van het blok staan. (GCC met -std=c90 ook)

Daar helpen {} niet, want TS zijn blok begint met een mySwitch.disableRecieve() functie-aanroep. Bovendien komt er dan geen executable uit, dus kon TS ook niet het beschreven gedrag krijgen ;-)

leime

Golden Member

Op 15 augustus 2023 00:10:18 schreef SparkyGSX:
[...]
Waarom? Als je die declaratie binnen een { } doet is dat toch de scope van die variabele?

Dat zou ik ook denken ja. Maar dit stond expliciet vermeld in de referentie die ik er gisteravond bij had gepakt.

@blurp: Dat klinkt inderdaad wel logisch zo. Godbolt kende ik nog niet, direct even gebookmarkt! Bedankt.

PE9SMS

Special Member

Ben ook al eens tegen dit gedrag aangelopen, vandaar dat er een belletje ging rinkelen. Dat was ook avr-gcc, het lijkt dus wel iets specieks voor deze compiler te zijn. Ook even getest met x86 gcc (TDM-GCC 9.2), en die doet het prima zonder de { }.

This signature is intentionally left blank.

Bedankt allemaal!

Op 14 augustus 2023 23:59:50 schreef leime:
<<>>

Wat je denk ik ook kan doen is de drie variabelen start, stop en second globaal declareren en dan alleen die sturen. Maar ik vermoed dat je de case misschien nog wel wil gaan uitbreiden. Ik twijfel welke code efficiënter is qua geheugen. (Nogmaals, ik ben geen top programmeur)

c code:

Global Char start[8]={0x7E, 0xFF, 0x06, 0x22, 0x00, 0x1E, 0x01, 0xEF};

In je cases doe je dan:

c code:

case 4543491: 
              Serial1.write((char*) start, 8);    //send command
              break;

Ik zit hier niet achter een c++ compiler, dus of eea direct compileert weet ik niet.

Ik denk dat het inderdaad beter is om de variabelen globaal te plaatsen en zal de code binnenkort aanpassen. Het is ook wel handig om ze later opnieuw te kunnen gebruiken zonder ze opnieuw te declareren.
De switch case wordt inderdaad uitgebreid tot 16 inputs en een uitgebreider menu.

@ PE9SMS: bedankt, dat was de oplossing dus!

Every machine is a smoke machine if you operate it wrong enough