Hello everyone. I'm working on the final details of my son's Megatron costume and I'm hitting a snag.
I am creating a sketch for Arduino UNO, ws8211 and DY-SV5W. The sketch should trigger two different cases. Case 1 is a strip of LEDs in a pattern playing while audio track 1 plays. case 1 will be triggered by a toggle switch and will repeat until the toggle is ungrounded. Case 2 is a second led pattern and audio track 2. Case 2 will be triggered by a momentarily grounded switch. Case 2 can be triggered if the toggle switch is in either position. If the momentary switch interrupts case1 while toggle is switched on, case 1 will resume after case 2 completes the audio track. if case 2 is triggered when case 1 is switched off, case 2 case 2 cannot be triggered.
However, Here’s what happens. When the Toggle is on, I can only get audio track 1 to play once, and will not repeat. I cannot get audio track two to play with the toggle on, but when I ground the momentary switch while the toggle is grounded, it resets case 1. When the toggle is off, I can trigger case 2 by grounding the toggle, which will cause the audio only to play, but cannot get the light pattern 2 to play. I only want case 2 to be able to play and interrupt case 1 when case 1 is active.
Think megaton's blaster. he "arms" it with the toggle, and then "fires" with the trigger. Then it should return to ready, armed state.
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
#define LED_PIN 6
#define NUM_LEDS 30 // Adjust to the number of LEDs in your strip
#define DFPLAYER_RX 10
#define DFPLAYER_TX 11
// Button pins
#define TOGGLE_SWITCH_PIN 4
#define MOMENTARY_BUTTON_PIN 3
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
SoftwareSerial mySerial(DFPLAYER_RX, DFPLAYER_TX);
enum CaseState {
CASE_NONE,
CASE_1,
CASE_2
};
CaseState currentCase = CASE_NONE;
bool isToggleOn = false;
bool isPlayingTrack2 = false;
byte commandLength;
byte command[6];
int checkSum = 0;
//my variables for demo sketch
int trackNum = 1;
int playStatus; //0 playing 1 stopped 2 waiting to start next track
unsigned long lastCheckTime;
unsigned long currentMillis;
int busyPinstate;
int triggerPin = 2;//trigger pin
void playTrack(int soundTrack) {
//select track
Serial.print("soundTrack: ");
Serial.println(soundTrack);
command[0] = 0xAA;//first byte says it's a command
command[1] = 0x07;
command[2] = 0x02;
command[3] = highByte(soundTrack);//snh...track HIGH bit
command[4] = lowByte(soundTrack);//SNL... track low bit
checkSum = 0;
for (int q = 0; q < 5; q++) {
checkSum += command[q];
}
command[5] = lowByte(checkSum);//SM check bit... low bit of the sum of all previous values
commandLength = 6;
sendCommand();
}
//plays whatever track has been paused or 1st track if nothing selected
//May need to be selected after putting into random mode
void play() {
command[0] = 0xAA;//first byte says it's a command
command[1] = 0x02;
command[2] = 0x00;
command[3] = 0xAC;
commandLength = 4;
sendCommand();
}
//selects random mode
void randomMode() {
command[0] = 0xAA;//first byte says it's a command
command[1] = 0x18;
command[2] = 0x01;
command[3] = 0x03;//random
checkSum = 0;
for (int q = 0; q < 4; q++) {
checkSum += command[q];
}
command[4] = lowByte(checkSum);//SM check bit... low bit of the sum of all previous values
commandLength = 5;
sendCommand();
//play() needs to be selected if you want the random tracks to start playing instantly
play();
}
//sets the device volume...0 - 30
void playbackVolume(int vol) {
if (vol > 30) { //check within limits
vol = 30;
}
command[0] = 0xAA;//first byte says it's a command
command[1] = 0x13;
command[2] = 0x01;
command[3] = vol;//volume
checkSum = 0;
for (int q = 0; q < 4; q++) {
checkSum += command[q];
}
command[4] = lowByte(checkSum);//SM check bit... low bit of the sum of all previous values
commandLength = 5;
sendCommand();
}
//sends the command to the DY-SV5W
void sendCommand() {
int q;
for (q = 0; q < commandLength; q++) {
mySerial.write(command[q]);
Serial.print(command[q], HEX);
}
Serial.println("End");
}
void setup() {
strip.begin();
strip.show(); // Initialize all pixels to 'off'
mySerial.begin(9600); // Initialize DY-SV5W
sendCommand(0x3F, 0); // Reset the module
delay(1000); // Wait for the module to reset
// Set button pins as input
pinMode(TOGGLE_SWITCH_PIN, INPUT_PULLUP);
pinMode(MOMENTARY_BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
// Check toggle switch state
if (digitalRead(TOGGLE_SWITCH_PIN) == LOW) {
if (!isToggleOn) {
isToggleOn = true;
startCase1(); // Start case 1
}
} else {
if (isToggleOn) {
isToggleOn = false;
stopCase1(); // Stop case 1
}
}
// Check momentary button state
if (digitalRead(MOMENTARY_BUTTON_PIN)== LOW) {
if (currentCase != CASE_2) {
startCase2(); // Start case 2
delay(300); // Debounce delay
}
}
// Check if case 2 has finished playing
if (isPlayingTrack2 && !mySerial.available()) {
if (isToggleOn) {
startCase1(); // Resume case 1 if toggle is on
} else {
stopCase1(); // Stop case 1 if toggle is off
}
currentCase = CASE_NONE; // Reset current case
isPlayingTrack2 = false; // Reset track 2 state
}
}
// Start case 1 (track 1 and pattern 1)
void startCase1() {
currentCase = CASE_1;
playTrack(1); // Play audio track 1
lightPatternOne(); // Start light pattern one
}
// Stop case 1
void stopCase1() {
stopTrack(); // Stop playback
strip.clear(); // Clear LED strip
strip.show();
}
// Start case 2 (track 2 and pattern 2)
void startCase2() {
isPlayingTrack2 = true;
stopTrack(); // Stop case 1 if it's playing
playTrack(5); // Play audio track 2
lightPatternTwo(); // Start light pattern two
currentCase = CASE_2; // Set current case to 2
}
// Function to play a specific track
void playTrack(uint8_t track) {
sendCommand(0x03, track); // Play specified track
}
// Function to stop the current track
void stopTrack() {
sendCommand(0x16, 0); // Stop playback
}
// Light pattern one (rainbow effect)
void lightPatternOne() {
static unsigned long lastUpdate = 0;
static int j = 0;
// Run the rainbow effect
if (millis() - lastUpdate > 20) { // Update every 20 ms
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i + j) & 255));
}
strip.show();
j++;
lastUpdate = millis();
}
}
// Light pattern two (breathing effect)
void lightPatternTwo() {
static unsigned long lastUpdate = 0;
static int brightness = 0;
static int fadeAmount = 5;
// Run the breathing effect
if (millis() - lastUpdate > 30) { // Update every 30 ms
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(brightness, 0, 0)); // Red breathing effect
}
strip.show();
brightness += fadeAmount;
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount; // Reverse the direction
}
lastUpdate = millis();
}
}
// Function to generate color from wheel
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
// Function to send commands to the DFPlayer
void sendCommand(uint8_t command, uint8_t param) {
mySerial.write(0x7E); // Start byte
mySerial.write(0xFF); // Version
mySerial.write(command); // Command
mySerial.write(param); // Parameter
mySerial.write(0xEF); // End byte
}

