Switch...Case Help

Hey, there.

I'm working on animating a toy that my brother is prototyping. It will have only three features: it will play a designated noise from an MP3 module, be illuminated with an LED module, and will rotate about its axis via a motor. The order of operations are as described below:

There is only one, single NO momentary switch that the user will press. Other hardware is:

*MP3 Module - DY-SV8F,
*LED Module - inductively-powered LED Module (works on same premise as Qi wireless charging for your cell phone), and
*1 - 3 RPM DC Motor.

Each press of this momentary switch will do the following:

First Press:
*Play Track 1 on MP3 Module; Track 1 shall play ONCE (approximately 11 seconds).
*Turn on LED Module; LED Module shall turn on and remain lit.

Second Press:
*Play Track 2 on MP3 Module; Track 2 shall play in a continuous loop.
*LED Module remains lit; Turn on Motor; LED Module shall remain lit; Motor shall turn on and remain on.

Third Press:
*Track 2 on MP3 Module shall stop. No sound from MP3 module for this state.
*LED Module shall remain lit.
*Motor shall remain on.

Fourth Press:
*Play Track 3 on MP3 Module; Track 3 shall play ONCE.
*At the conclusion of Track 3 (approximately 9 seconds), turn off LED Module and Motor.

Here are the issues I'm having with my code:

*When I first plug in my hardware, everything is silent and patiently waiting for the first button press, which is the desired state.

*When I press the button the first time, Track 1 plays and the LED module turns on. The issue is that Track 1 on the MP3 module plays in a continuous loop. It should be noted that the code is written to do this, so it is doing exactly what it's programmed to do. I need help telling the code to only play the track once. For this particular MP3 module, the operating state is rather simple - when the pin for Track 1 is held LOW, it plays the track and will continue to play it in an infinite loop. To stop the track, you must drive the pin for Track 1 HIGH.

*When I press the button a second time, the LEDs turn off, the Motor turns on, and it plays track 1 on the MP3 player just once.

*When I press the button a third time, the motor and LED modules turn off, and Track 1 plays in a looping fashion.

*When I press the button a fourth time, nothing happens.

*When I press the button a fifth time, the Motor and LED modules turn on, and Track 1 plays in a looping fashion.

Code below:

#include "SoftwareSerial.h"

const int ledPin = 7;
const int motorPin = 8;
const int trackOnePin = 9;
const int trackTwoPin = 10;
const int trackThreePin = 11;
const int buttonPin = 12;

int buttonPushCounter = 0; //new
int buttonState = HIGH; //using built-in pullup resistor.
int lastButtonState = LOW;
int ledState = LOW; //initializes the LED module to OFF.
int motorState = LOW; //initializes the motor to OFF.
int trackOneState = HIGH; //initializes track one on the MP3 module to OFF.
int trackTwoState = HIGH; //initializes track two on the MP3 module to OFF.
int trackThreeState = HIGH; //initializes track three on the MP3 module to OFF.

unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  // put your setup code here, to run once:

  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(trackOnePin, OUTPUT);
  pinMode(trackTwoPin, OUTPUT);
  pinMode(trackThreePin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motorPin, OUTPUT);

  //Writes the inialized states based on the declarations above. Maybe these lines aren't needed?
  digitalWrite(trackOnePin, trackOneState);
  digitalWrite(trackTwoPin, trackTwoState);
  digitalWrite(trackThreePin, trackThreeState);
  digitalWrite(ledPin, ledState);
  digitalWrite(motorPin, motorState);

}

void loop() {
  // put your main code here, to run repeatedly:

  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW && buttonPushCounter<5) { //If the button has been pressed AND the buttonPushCounter is less than 5, then increment the buttonPushCounter by one.
        buttonPushCounter++;
      } //I was thinking that an ELSE argument might be helpful - I tried to put an else argument that would reset the buttonPushCounter back to zero, but this obviously didn't work,
      //since when I WASN'T pushing the button, it was restarting the count to zero everytime the loop looked at this decision.
    }
  }

  switch (buttonPushCounter) {
    case 1: //When buttonPushCounter = 1. I'm still learning how to use Switch...Case, so I'm not sure if I'm just doing this wrong, or if there is a better way. Anyways...
      if (trackOneState = HIGH) { //If track one is not playing, then:
        ledState = !ledState; //Toggles (turns on) LED module, and
        trackOneState = !trackOneState; //Toggles (plays) track one, and
        digitalWrite(ledPin, ledState); //Writes the state of the LED module, and
        digitalWrite(trackOnePin, trackOneState); //Writes the state of Track One.
        break; //Breaks out so that when the code whips around again, and it sees that we are still in Case 1, it will go to "else," and
      } else { //breaks out again until the counter increments. Switch...Case logic continues in similar fashion when the counter increments.
        break;
      }
    case 2:
      if (trackTwoState = HIGH) {
        trackOneState = !trackOneState;
        motorState = !motorState;
        trackTwoState = !trackTwoState;
        digitalWrite(trackOnePin, trackOneState);
        digitalWrite(motorPin, motorState);
        digitalWrite(trackTwoPin, trackTwoState);
        break;
      } else {
        break;
      }
    case 3:
      if (trackTwoState = LOW) {
        trackTwoState = !trackTwoState;
        digitalWrite(trackTwoPin, trackTwoState);
        break;
      } else {
        break;
      }
    case 4:
      if (trackThreeState = HIGH) {
        trackThreeState = !trackThreeState;
        delay(9000);
        motorState = !motorState;
        ledState = !ledState;
        digitalWrite(trackThreePin, trackThreeState);
        digitalWrite(motorPin, motorState);
        digitalWrite(ledPin, ledState);
        break;
      } else {
        break;
      }
    default: //I don't know why I restated these conditions, but I thought that since the code is whipping around in this loop, it made sense to me to ensure that the states of the variables were explicitly set.
      ledState = LOW; //led module off
      motorState = LOW; //motor off
      trackOneState = HIGH; //track 00001 off
      trackTwoState = HIGH; //track 00002 off
      trackThreeState = HIGH; //track 00003 off
      digitalWrite(ledPin, ledState);
      digitalWrite(motorPin, motorState);
      digitalWrite(trackOnePin, trackOneState);
      digitalWrite(trackTwoPin, trackTwoState);
      digitalWrite(trackThreePin, trackThreeState);
      buttonPushCounter = 0; //I moved the "initialize the counter back to zero" logic here, as this is (in my mind) what my default condition should be...reset the counter to zero if we have any value other than 1-4.
  }

  lastButtonState = reading;
}

This sets the state to HIGH. That is almost never what you want to do in an if statement. You want to compare the value with HIGH. That takes ==

You seem to have made that same mistake in several places.

Can be replaced by:

  }
  break;
1 Like

what prevents this being executed each iteration of loop()? shouldn't it be inside the reading != lastButtonState condition

why is there both buttonState and lastButtonState

why is trackOneState == HIGH in case 1 when it is always set HIGH in the default case?

if this is correct, so why not simply

    switch (buttonPushCounter) {
    case 1:
        digitalWrite(ledPin,      HIGH);
        digitalWrite(trackOnePin, LOW);
        break;

    ....

    default:
        digitalWrite(ledPin,        LOW);
        digitalWrite(motorPin,      LOW);
        digitalWrite(trackOnePin,   HIGH);
        digitalWrite(trackTwoPin,   HIGH);
        digitalWrite(trackThreePin, HIGH);
        buttonPushCounter = 0;

wouldn't this be clearer?

    int reading = digitalRead(buttonPin);
    if (reading != lastButtonState) {
        lastButtonState = reading;
        delay (20);
        if (reading == LOW)
            buttonPushCounter++;
    }

Have you looked at this library?

Each one of your answers were a big help, and for that I thank you all!

I can’t believe I was using “=“ instead of “==“ for comparing pins to HIGH and LOW…I guess I had been looking at this for so long I was blind to this simple mistake.

This was my first time trying to use SWITCH…CASE, so I’ve learned that I was making it way more complicated than necessary. I’ve learned that it is actually quite elegant compared to a host of nested IF statements, but I never expected it to be so simple either.

I tried to edit the sketch I uploaded previously for your review, but it was still riddled with bugs, so I started a whole new sketch and wrote it with each of your suggestions. This new code works perfectly, and it’s much simpler than what I started with.

One thing I did as a “cheat” for playing the mp3 files only once is I created a 1-sec mp3 file that was just dead air (Track 00004). Since this particular mp3 module is configured to only play one mp3 file at a time, I’m using this file to interrupt the file I only want to play once. This was done primarily because of schedule. This is a proof of concept, and not a “final product,” so it doesn’t need to be perfect.

Once I get the hardware fully integrated and the code finalized, I’ll upload the working code for anyone who might be interested.

Thanks again!

I've spent some considerable time today reviewing this link and it does not appear to be working. I've copied some of the example sketches into a fresh new IDE and it won't compile.

There seem to be some comments that are leaving me with the impression that this library is no longer being supported and might not be compatible with IDE 2.2.1.

If you could help with this, I'd surely appreciate it.

I don't know anything about the library but its link.  It just turned up in a search and I thought it might be useful.  You could try searching for other DY-xxx libraries.

Did that, too, but no joy.

In any case, I just tested my workaround on my hardware and it works as expected and meets all of the designer’s specifications.

Thanks again for everyone’s help!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.