Over the last couple of weeks, with help from this forum, I've put together a sketch using an Arduino Uno, which i’ll swap out later for the smaller Nano. The sketch controls Leds and their sequence using states, a small servo motor & sound effects controlled by 2 momentary buttons.
*stage1, (i put this in "else" as its the default action) When neither button is pressed, the sketch will return the the servo to the parked position, it plays sound 01 and sequences the slow speed version of the LEDs
*stage2, (i put this in "else if") When buttonA becomes pressed the servo moves to 1st position, plays sound 02 and sequences the medium speed version of the LEDs and does this until the button is released, at which point returns to stage1
*stage3, (i put this in "if") When buttonB becomes pressed the servo moves to 2nd position, plays sound 03 and sequences the fast speed version of the LEDs and does this until the button is released, at which point returns to stage1
The sketch worked perfectly with "if...else if...else" statements & i then decided i needed to add in a millis controlled delay so when i released either button the current actions would continue for 2 seconds. I found the following code and tested it to make sure it worked with the servo & leds before adding to my sketch
[code]
//Global Variables
const byte BUTTON = 2; // our button pin
const byte LED = 13; // LED (built-in on Uno)
unsigned long buttonPushedMillis; // when button was released
unsigned long ledTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 0; // wait to turn on LED
unsigned long turnOffDelay = 2000; // turn off LED after this time
bool ledReady = false; // flag for when button is let go
bool ledState = false; // for LED is on or not.
void setup() {
pinMode(BUTTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
}
void loop() {
// get the time at the start of this loop()
unsigned long currentMillis = millis();
// check the button
if (digitalRead(BUTTON) == LOW) {
// update the time when button was pushed
buttonPushedMillis = currentMillis;
ledReady = true;
}
// make sure this code isn't checked until after button has been let go
if (ledReady) {
//this is typical millis code here:
if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
// okay, enough time has passed since the button was let go.
digitalWrite(LED, HIGH);
// setup our next "state"
ledState = true;
// save when the LED turned on
ledTurnedOnAt = currentMillis;
// wait for next button press
ledReady = false;
}
}
// see if we are watching for the time to turn off LED
if (ledState) {
// okay, led on, check for now long
if ((unsigned long)(currentMillis - ledTurnedOnAt) >= turnOffDelay) {
ledState = false;
digitalWrite(LED, LOW);
}
}
}
[/code]
I set "turnOnDelay = 0;" as i want it start the action instantly & "turnOffDelay = 2000; " to 2 secs.
The combined code worked perfectly for the "if" & "else" statements but the "else if" statement had issues with the servo moving into position for a few seconds then trying to rest, on a constant cycle, the led sequence was freezing up for seconds at time. I checked to see if my {} were in the correct place and they all seemed to be.
Luckily i tried changing "else if" to "if" and that has solved the issue, the sketch works perfectly with that simple change from "if...else if...else" to "if...if...else"
Can anyone shed any light on what i missed in the code to make "else if" behave in that way
Here is the working code.
[code]
/*
REQUIRED Libraries to make this sketch work:
MP3Flash16Pv2 Library https://github.com/r0ndL/MP3Flash16Pv2
BY8x0116P Library https://github.com/r0ndL/BY8x0116Pv2
Important Note for if...elseif...else statements
if (condition) {
code to be executed if this condition is true;
} else if (condition) {
code to be executed if first condition is false and this condition is true;
} else {
code to be executed if all conditions are false;
}
NOTE!!!!! FOR THIS SKETCH I HAD TO CHANGE "else if" to "if" to make stage 2 work!!!!!!
*/
//--------------SET AUDIO OPTIONS FOR BY8301------------------------
// NOTE: This sketch currently supports 3 different sound modules (MP3-FLASH-16P, BY8001-16P, BY8301-16P)
#define AUDIO1 2 // 1=MP3-FLASH-16P
// 2=BY8001-16P or BY8301-16P
// INCLUDE LIBS AND DECLARE VARIABLES...
#include "AltSoftSerial.h"
AltSoftSerial MP3Serial; // SoftwareSerial port assignments (RX, TX) to communicate with sound module
#if (AUDIO1==2)
//settings for BY8001-16P or BY8301-16P module...
#include "BY8x0116Pv2.h"
BY8x0116Pv2 myPlayer(MP3Serial); // Use SoftwareSerial as the serial port
#else
//settings for MP3-FLASH-16P...
#include "MP3Flash16Pv2.h"
MP3Flash16Pv2 myPlayer(MP3Serial); // Use SoftwareSerial as the serial port
#endif
// ARDUINO PIN ASSIGNMENTS to connect to by8301...
// Default Pin Assignments - BASIC WIRING in NOTES/MANUAL FOR BY8301
#define PIN_sound_BUSY A3 //Connect to BUSY pin on sound module
// ADDITIONAL SOUND OPTIONS...
#define number_of_sounds 3
//----------------------------------------------------------------------------------------------------
//-----------BY8301 PLAYBACK CONTROL----------------------------------------------------
void PlayTrack(int TrackToPlay)
{
static int TrackPlaying = -1;
if (TrackPlaying != TrackToPlay)
{ // Not playing the required track
myPlayer.stopPlay(); // Stop what you're doing, if anything
myPlayer.playFile(TrackToPlay, 10); // Play requested track, VOLUME 10 (OUT OF 30)
TrackPlaying = TrackToPlay; // Note the track now playing
}
else if (!myPlayer.isBusy()) // Track number is right but is it still playing?
{
myPlayer.playFile(TrackToPlay, 10); // No, so play it again, VOLUME 10 (OUT OF 30)
}
}
//----------------------------------------------------------------------------------------------------
//--------------------SERVO-------------------------------------
#include<ServoTimer2.h>
ServoTimer2 myservo; // create servo object to control servo CONNECT UNO TX PIN 9, RX PIN 8
//--------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// RED LEDS wired to buttonA & B press
int ledPinRA = A0; // the number of the LED pin
int ledPinRB = A1; // the number of the LED pin
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// buttonA & B with Pin No
int buttonApin = 2; //ButtonA
int buttonBpin = 4; //ButtonB
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
int pos = 0; // set initial servo position to 0
int buttonAstate = 0; // variable for reading pushbutton status
int buttonBstate = 0; // variable for reading pushbutton status
//----------------------------------------------------------------------------------------------------
//--------www.baldengineer.com millis button delay-----------
unsigned long buttonPushedMillis; // when button was released
unsigned long ledTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 0; // wait to turn on LED AFTER PRESSING BUTTON 1000=1SEC
unsigned long turnOffDelay = 2000; // turn off LED after this time ONCE BUTTON IS RELEASED 1000=1SEC
bool ledReady = false; // flag for when button is let go
bool ledState = false; // for LED is on or not.
//-----------------------------------------------------------
//----------------------------STATE CONTROL FOR LED SEQUENCE & SPEEDS---------------------------------------
/*
by noiasca https://forum.arduino.cc/index.php?topic=666044
*/
//----SPEEDS-----
const uint16_t intervalSLOW[] {1000, 1000, 1000, 1000, 1000, 1000, 1000, 100}; // time to wait in each intervall
const uint16_t intervalMEDIUM[] {400, 400, 400, 400, 400, 400, 400, 100};
const uint16_t intervalFAST[] {100, 100, 100, 100, 100, 100, 100, 100};
//----LED PIN No.-----
const byte ledPinA = 5;
const byte ledPinB = 6;
const byte ledPinC = 7;
const byte ledPinD = A4;
const byte ledPinE = A5;
const byte ledPinF = 10;
const byte ledPinG = 11;
void handleLedsSLOW()
{
static uint32_t previousMillis = 0;
static byte state = 7;
if (millis() - previousMillis >= intervalSLOW[state])
{
// it's time for next state
state++;
state = state % 8;
Serial.print(F("state=")); Serial.println(state);
// act according state
switch (state)
{
case 0:
digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 1:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 2:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 3:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 4:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 5:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, LOW);
break;
case 6:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, HIGH);
break;
case 7:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
}
previousMillis = millis();
}
}
void handleLedsMEDIUM()
{
static uint32_t previousMillis = 0;
static byte state = 7;
if (millis() - previousMillis >= intervalMEDIUM[state])
{
// it's time for next state
state++;
state = state % 8;
Serial.print(F("state=")); Serial.println(state);
// act according state
switch (state)
{
case 0:
digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 1:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 2:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 3:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 4:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 5:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, LOW);
break;
case 6:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, HIGH);
break;
case 7:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
}
previousMillis = millis();
}
}
void handleLedsFAST()
{
static uint32_t previousMillis = 0;
static byte state = 7;
if (millis() - previousMillis >= intervalFAST[state])
{
// it's time for next state
state++;
state = state % 8;
Serial.print(F("state=")); Serial.println(state);
// act according state
switch (state)
{
case 0:
digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 1:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 2:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 3:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 4:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
case 5:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, LOW);
break;
case 6:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, HIGH);
break;
case 7:
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
break;
}
previousMillis = millis();
}
}
void setup() {
myservo.attach(3); // SERVO pin
Serial.begin(9600);
pinMode(3, OUTPUT); // initialize the SERVO pin as an output
pinMode(buttonApin, INPUT_PULLUP); // initialize the button A pin as an input
pinMode(buttonBpin, INPUT_PULLUP); // initialize the button B pin as an input
pinMode(ledPinA, OUTPUT); // initialize the LED1 pin as an output
pinMode(ledPinB, OUTPUT); // initialize the LED2 pin as an output
pinMode(ledPinC, OUTPUT); // initialize the LED3 pin as an output
pinMode(ledPinD, OUTPUT); // initialize the LED4 pin as an output
pinMode(ledPinE, OUTPUT); // initialize the LED5 pin as an output
pinMode(ledPinF, OUTPUT); // initialize the LED6 pin as an output
pinMode(ledPinG, OUTPUT); // initialize the LED7 pin as an output
pinMode(12, OUTPUT); // pin 12 as output for SLIDE switch 2No.LEDS
pinMode(ledPinRA, OUTPUT); // initialize the LED pin as an output
pinMode(ledPinRB, OUTPUT); // initialize the LED pin as an output
MP3Serial.begin(9600);
myPlayer.init(PIN_sound_BUSY); // Init the player with the MP3 BUSY pin connected to Arduino pin defined
}
void loop() {
//--------www.baldengineer.com millis button delay-----------
unsigned long currentMillis = millis(); // get the time at the start of this loop()
//-----------------------------------------------------------
digitalWrite(12, HIGH); // sets the digital pin 12 on
buttonAstate = digitalRead(buttonApin); // read the state of button A value
buttonBstate = digitalRead(buttonBpin); // read the state of button B value
//-------------------------Stage 3-----------------------------------------------------------
if (buttonBstate == LOW) { // check if button B is pressed, if (condition) {code to be executed if this condition is true;}
//--------www.baldengineer.com millis button delay-----------
buttonPushedMillis = currentMillis; // update the time when button was pushed
ledReady = true;
}
// make sure this code isn't checked until after button has been let go
if (ledReady) { //this is typical millis code here:
if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
// okay, enough time has passed since the button was let go.
// Put in all the actions you want to perform below, remember to close them out at ledState = false;
//-----------------------------------------------------------
myservo.write(1442); // if it is rotate servo to 83 degrees
PlayTrack(3); // PLAY TRACK3
handleLedsFAST(); // checks if something is todo with the LEDs
digitalWrite(ledPinRB, HIGH);//BUTTON B IS PRESSED SO MANUALLY LIGHT LED:
digitalWrite(ledPinRA, LOW); //BUTTON A IS NOT PRESSED SO DO NOT MANUALLY LIGHT LED:
//--------www.baldengineer.com millis button delay-----------
// setup our next "state"
ledState = true;
ledTurnedOnAt = currentMillis; // save when the LED turned on
// wait for next button press
ledReady = false;
}
}
// see if we are watching for the time to turn off LED
if (ledState) {
// okay, led on, check for now long
if ((unsigned long)(currentMillis - ledTurnedOnAt) >= turnOffDelay) {
ledState = false;
// Put in all the actions you want to close them out below
//-----------------------------------------------------------
myservo.write(750); // servo position
PlayTrack(1); // PLAY TRACK1
handleLedsSLOW(); // checks if something is todo with the LEDs
digitalWrite(ledPinRA, LOW); //BUTTON A NOT PRESSED SO DO NOT MANUALLY LIGHT LED
digitalWrite(ledPinRB, LOW); //BUTTON B NOT PRESSED SO DO NOT MANUALLY LIGHT LED
}
}
//-------------------------Stage 2-----------------------------------------------------------
if (buttonAstate == LOW) { // check if button A is pressed, elseif (condition) {code to be executed if first condition is false and this condition is true;} changed to "if" as "else if" caused issues
//--------www.baldengineer.com millis button delay-----------
buttonPushedMillis = currentMillis; // update the time when button was pushed
ledReady = true;
}
// make sure this code isn't checked until after button has been let go
if (ledReady) { //this is typical millis code here:
if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOnDelay) {
// okay, enough time has passed since the button was let go.
// Put in all the actions you want to perform below, remember to close them out at ledState = false;
//-----------------------------------------------------------
myservo.write(1042); // if it is rotate servo to 35 degrees
PlayTrack(2); // PLAY TRACK2
handleLedsMEDIUM(); // checks if something is todo with the LEDs
digitalWrite(ledPinRA, HIGH); //BUTTON A IS PRESSED SO MANUALLY LIGHT LED:
digitalWrite(ledPinRB, LOW); //BUTTON B IS NOT PRESSED SO DO NOT MANUALLY LIGHT LED:
//--------www.baldengineer.com millis button delay-----------
// setup our next "state"
ledState = true;
ledTurnedOnAt = currentMillis; // save when the LED turned on
// wait for next button press
ledReady = false;
}
}
// see if we are watching for the time to turn off LED
if (ledState) {
// okay, led on, check for now long
if ((unsigned long)(currentMillis - ledTurnedOnAt) >= turnOffDelay) {
ledState = false;
// Put in all the actions you want to close them out below
//-----------------------------------------------------------
myservo.write(750); // servo position
PlayTrack(1); // PLAY TRACK1
handleLedsSLOW(); // checks if something is todo with the LEDs
digitalWrite(ledPinRA, LOW); //BUTTON A NOT PRESSED SO DO NOT MANUALLY LIGHT LED
digitalWrite(ledPinRB, LOW); //BUTTON B NOT PRESSED SO DO NOT MANUALLY LIGHT LED
}
}
//-------------------------Stage 1-----------------------------------------------------------
else { // This is the stage that will play by default else {code to be executed if all conditions are false;}
myservo.write(750); // servo position
PlayTrack(1); // PLAY TRACK1
handleLedsSLOW(); // checks if something is todo with the LEDs
digitalWrite(ledPinRA, LOW); //BUTTON A NOT PRESSED SO DO NOT MANUALLY LIGHT LED
digitalWrite(ledPinRB, LOW); //BUTTON B NOT PRESSED SO DO NOT MANUALLY LIGHT LED
}
delay(50); // waits for a 20th of a second, should help with any button bounce
}
[/code]
