/*************************************************** DemPlayer - A Mini MP3 Player For Arduino Alzheimer / Dementia Player - A simple MP3 player with only two controls. Easy for anyone with various levels of dementia to control. VOLUME TUNING (SONG SELECT) To Turn On: Turn either knob. To Turn Off; Press either knob. Will turn off automatically after approx. 2 hours. Caretaker can adjust "tone/equalizer" for the best sound, depending on the headphones used. Caretaker can set mode from sequential to random song shuffle. Songs are stored on a micro-SD card. Max Seim Cottage Grove, Minnesota http://www.catpin.com Email: info@catpin.com ****************************************************/ #include #include #include #include #include #include // Defining Variables const int busyPin = 12; // Arduino pin wired player pin const int buttonPin = 8; //This is a button test read pin const int sleepPin = 5; //This is the sleep button const int shufflePin = 9; //This is the random song mode pin int shuffle = 0; // This is the shuffle value int stopPlay = 0; //This is the stop flag int buttonState; //Variable for test button reading int lastButtonState = LOW;//Variable for last know button reading unsigned long lastDebounceTime = 0; //last time the pin was toggled, used to keep track of time unsigned long debounceDelay = 50; //the debounce time which user sets prior to run int shutDownIndex=0; //increment for shutdown int shutDown=0; //Shutdown Flag int ledPin = 13; // LED if needed int songCount = 148; // number of songs on the micro SD card. // VOLUME KNOB int nibble=0; //Volume encoder half-step index int pinA = 3; // Connected to CLK on KY-040 int pinB = 4; // Connected to DT on KY-040 int encoderPosCount = 0; int pinALast; int aVal; boolean bCW; // TUNING (SONG SELECT) KNOB int nibble2=0; //Tuning encoder half-step index int pinA2 = 6; // Connected to CLK on KY-040 int pinB2 = 7; // Connected to DT on KY-040 int encoderPosCount2 = 0; int pinALast2; int aVal2; boolean bCW2; // Wire Jumper (Equalizer Mode) Assign int j1 = 14; int j2 = 15; int j3 = 16; int j4 = 17; int j5 = 18; // Starting values when Player is powered on. int Equalizer = 5; // Equalizer Value int Volume = 18; // Volume Value SoftwareSerial mySoftwareSerial(11, 10); // RX, TX DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); void setup() { mySoftwareSerial.begin(9600); Serial.begin(115200); Serial.println(); Serial.println(F("DFPlayer Mini Startup")); Serial.println(F("Initializing DFPlayer")); if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. Serial.println(F("Unable to begin:")); Serial.println(F("1.Please recheck the connection!")); Serial.println(F("2.Please insert the SD card!")); while(true); } // Random number generator uint16_t randomSong; Entropy.initialize(); randomSong = Entropy.random(1,songCount); // Start with random song Serial.println(F("DFPlayer Mini online.")); myDFPlayer.volume(Volume); //Set volume value. From 0 to 30 myDFPlayer.EQ(Equalizer); //Set equalizer value. From 0 to 5 myDFPlayer.play(randomSong); //Start with song // Setup the test button with an internal pull-up : pinMode(buttonPin,INPUT_PULLUP); // Setup the sleep button (has external pull-up) : pinMode(sleepPin,INPUT); //Setup the LED : pinMode(ledPin, OUTPUT); //Setup the Encoders pinMode (pinA,INPUT); pinMode (pinB,INPUT); pinMode (pinA2,INPUT); pinMode (pinB2,INPUT); pinALast = digitalRead(pinA); pinALast2 = digitalRead(pinA2); // Jumper Switches for Equalizer Mode Select pinMode(j1, INPUT_PULLUP); // jumper '1' pinMode(j2, INPUT_PULLUP); // jumper '2' pinMode(j3, INPUT_PULLUP); // jumper '3' pinMode(j4, INPUT_PULLUP); // jumper '4' pinMode(j5, INPUT_PULLUP); // jumper '5' // Jumper for Shuffle Mode pinMode(shufflePin, INPUT_PULLUP); // jumper '9'; // Repeat Timer for 10 minutes, increments shutDownIndex Alarm.timerRepeat(600, Repeats); } void loop() { // Read busy state int busyState = digitalRead(busyPin); // check if the player is not busy. if (busyState == 1 && stopPlay == 0) { if (digitalRead(shufflePin)==LOW) { shuffle = Entropy.random(1,songCount); // random song myDFPlayer.play(shuffle); } else{ myDFPlayer.next(); //Play next mp3. } Alarm.delay(1000); } if (myDFPlayer.available()) { printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. } //read the Sleep Buttons. int readingSleep = digitalRead(sleepPin); if ((readingSleep == LOW || shutDown == 1) && stopPlay == 0) { Serial.println("Stop Button"); myDFPlayer.pause(); // Stop stopPlay = 1; } if(stopPlay == 2){ myDFPlayer.previous(); stopPlay = 0; shutDownIndex = 0; } //read the jumper switch and set the Equalizer Value int jumpVal=0; if (digitalRead(j1)==LOW) { jumpVal=1; } if (digitalRead(j2)==LOW) { jumpVal=2; } if (digitalRead(j3)==LOW) { jumpVal=3; } if (digitalRead(j4)==LOW) { jumpVal=4; } if (digitalRead(j5)==LOW) { jumpVal=5; } if (Equalizer != jumpVal) { Alarm.delay(500); Equalizer = jumpVal; Serial.println(Equalizer); myDFPlayer.EQ(Equalizer); } //read the test button pin, if pressed will be high, if not pressed will be low int reading = digitalRead(buttonPin); //in the case that the reading is not equal to the last state set the last debounce time to current millis time if (reading != lastButtonState) { lastDebounceTime = millis(); } //check the difference between current time and last registered button press time, if it's greater than user defined delay then change the LED state as it's not a bounce if ((millis()-lastDebounceTime) > debounceDelay) { if (reading != buttonState) { buttonState = reading; if (buttonState == HIGH) { // Do something if the button is HIGH } } } //save the reading. next time through the loop the state of the reading will be known as the lastButtonState lastButtonState = reading; // VOLUME KNOB // ============================================== aVal = digitalRead(pinA); if (aVal != pinALast){ // Means the knob is rotating // if the knob is rotating, we need to determine direction // We do that by reading pin B. if(stopPlay == 1){ stopPlay = 2; shutDown = 0; } shutDownIndex = 0; // Reset the 2 hour timer if (digitalRead(pinB) != aVal) { // Means pin A Changed first - We're Rotating Clockwise encoderPosCount ++; nibble++; bCW = true; } else {// Otherwise B changed first and we're moving CCW bCW = false; encoderPosCount--; nibble++; } Serial.print ("Volume: "); if (bCW && nibble == 3){ Volume++; if(Volume > 30){ Volume = 30; } nibble = 0; myDFPlayer.volume(Volume); Serial.println (Volume); }else{ if(nibble == 3){ Volume--; if(Volume < 1){ Volume = 0; } nibble = 0; } myDFPlayer.volume(Volume); Serial.println (Volume); } //Serial.print("Encoder Position: "); //Serial.println(encoderPosCount); } pinALast = aVal; // TUNING (SONG SELECT) KNOB // ============================================== aVal2 = digitalRead(pinA2); if (aVal2 != pinALast2){ // Means the knob is rotating if(stopPlay == 1){ stopPlay = 2; shutDown = 0; } shutDownIndex = 0; // Reset the 2 hour timer // if the knob is rotating, we need to determine direction // We do that by reading pin B2. if (digitalRead(pinB2) != aVal2) { // Means pin A2 Changed first - We're Rotating Clockwise encoderPosCount2 ++; nibble2++; bCW2 = true; } else {// Otherwise B2 changed first and we're moving CCW bCW2 = false; encoderPosCount2--; nibble2++; } if (bCW2 && nibble2 == 2){ if (digitalRead(shufflePin)==LOW) { shuffle = Entropy.random(1,songCount); // random song myDFPlayer.play(shuffle); } else{ myDFPlayer.next(); //Play next mp3. } nibble2 = 0; }else{ if(nibble2 == 2){ if (digitalRead(shufflePin)==LOW) { shuffle = Entropy.random(1,songCount); // random song myDFPlayer.play(shuffle); } else{ myDFPlayer.previous(); //Play previous mp3. } nibble2 = 0; } } //Serial.print("Encoder Position: "); //Serial.println(encoderPosCount2); } pinALast2 = aVal2; } // Timer Function to auto-shutoff after two hours. // This gets triggered every 10 minutes. void Repeats(){ Serial.println("Shutdown Timer Incremented"); shutDownIndex++; if(shutDownIndex > 11){ shutDown = 1; shutDownIndex = 0; } } void printDetail(uint8_t type, int value){ switch (type) { case TimeOut: Serial.println(F("Time Out!")); break; case WrongStack: // Serial.println(F("Stack Wrong!")); break; case DFPlayerCardInserted: Serial.println(F("Card Inserted!")); break; case DFPlayerCardRemoved: Serial.println(F("Card Removed!")); break; case DFPlayerCardOnline: Serial.println(F("Card Online!")); break; case DFPlayerPlayFinished: Serial.print(F("Number:")); Serial.print(value); Serial.println(F(" Play Finished!")); break; case DFPlayerError: Serial.print(F("DFPlayerError:")); switch (value) { case Busy: Serial.println(F("Card not found")); break; case Sleeping: Serial.println(F("Sleeping")); break; case SerialWrongStack: Serial.println(F("Get Wrong Stack")); break; case CheckSumNotMatch: Serial.println(F("Check Sum Not Matched")); break; case FileIndexOut: Serial.println(F("File Index Out of Bound")); break; case FileMismatch: Serial.println(F("Cannot Find File")); break; case Advertise: Serial.println(F("In Advertise")); break; default: break; } break; default: break; } }