// Andrew Sleigh, Fablab Brighton // Stripped down version of the code for my // Fab Academy 2018 final project // 2018-06-28 // Just using the keycard reader unctionality //Assumes: //4021 Shift register to read media cards // Atmega32u4 board // HEADER ------------------------------------------------------------------------------ / ////////////////////////////////////////////////////////////////////////////////////////// // LIBRARIES --------------------------------------------------------------------------- / //#include // SPI For MP3 shield //#include // For MP3 shield //#include // For MP3 shield #include // For debouncing buttons //#include // I2C for OLED screen //#include // For displaying text on OLED screen // MEDIA CARD READER ------------------------------------------------------------------- / // Pins connected to shift register int latchPin = A0; int dataPin = A1; int clockPin = A2; //Define variable to hold the data for shift register. byte switchVar1 = 72; //01001000 // BUTTON DEBOUNCING ------------------------------------------------------------------- / #define B_PAUSE A4 // A0 #define B_SKIP A3 #define B_BACK 4 // digital pin #define B_READ A5 // Objects instancing buttons Bounce b_Pause = Bounce(); Bounce b_Skip = Bounce(); Bounce b_Back = Bounce(); Bounce b_Read = Bounce(); #define BUTTON_DEBOUNCE_PERIOD 20 //ms // SD AND MP3 LIBRARIES ----------------------------------------------------------------- / //SdFat sd; // Object instancing the SdFat library. //SFEMP3Shield MP3player; // Object instancing the SFEMP3Shield library. // PLAYBACK FILE NAMES AND LOGIC --------------------------------------------------------- / // Set up the album and track name arrays int albumIndex = 1; // integers, so they can be incremented int trackIndex = 1; char albumNumber[4]; // see https://stackoverflow.com/a/36658958 char trackNumber[4]; char trackToPlay[13]; // playMP3() expects a char type. Needs to be one char longer than needed to store filename bool startPlay; // set a variable to see if the Read button has been pressed, and if so, start playback uint8_t result; //result code from some function as to be tested at later time. // OLED SCREEN --------------------------------------------------------------------------- / // Constructor // The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp // this constructor uses hardware I2C - much faster //U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 3, 2); //char SorryTextLine1 = "I'm sorry Dave,"; //char SorryTextLine2 = "I can't do that"; // SETUP () ------------------------------------------------------------------------------ / ////////////////////////////////////////////////////////////////////////////////////////// void setup() { // OLED SCREEN --------------------------------------------------------------------------- / // u8g2.begin(); // u8g2.firstPage(); // do { // u8g2.setFont(u8g2_font_helvR14_tr); // u8g2.drawStr(0,24,"Insert media"); // u8g2.setFont(u8g2_font_helvR10_tr); // u8g2.drawStr(0,24,"I'm sorry Dave, I'm"); // u8g2.drawStr(0,54,"afraid I can't do that."); // u8g2.setFont(u8g2_font_helvR10_tr); // u8g2.drawStr(0,24,"I am completely"); // u8g2.drawStr(0,54,"operational"); // } while ( u8g2.nextPage() ); // SERIAL FOR DEBUGGING ---------------------------------------------------------------- / Serial.begin(9600); //Serial.println(F("Looking for buttons to be pressed...")); // BUTTONS ----------------------------------------------------------------------------- / pinMode(B_PAUSE, INPUT_PULLUP); pinMode(B_SKIP, INPUT_PULLUP); pinMode(B_BACK, INPUT_PULLUP); pinMode(B_READ, INPUT_PULLUP); b_Pause.attach(B_PAUSE); b_Pause.interval(BUTTON_DEBOUNCE_PERIOD); b_Skip.attach(B_SKIP); b_Skip.interval(BUTTON_DEBOUNCE_PERIOD); b_Back.attach(B_BACK); b_Back.interval(BUTTON_DEBOUNCE_PERIOD); b_Read.attach(B_READ); b_Read.interval(BUTTON_DEBOUNCE_PERIOD); // MEDIA CARD READER SHIFT REGISTER ---------------------------------------------------- / //define pin modes pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, INPUT); // SD CARD AND MP3 PLAYER ------------------------------------------------------------- / // if(!sd.begin(9, SPI_HALF_SPEED)) sd.initErrorHalt(); // if (!sd.chdir("/")) sd.errorHalt("sd.chdir"); // // result = MP3player.begin(); // MP3player.setVolume(10,10); // PLAYBACK LOGIC --------------------------------------------------------------------- / // play button has not been pressed yet startPlay = false; } // END SETUP FUNCTION // MAIN LOOP --------------------------------------------------------------------------- / ////////////////////////////////////////////////////////////////////////////////////////// void loop() { // MP3 PLAYBACK ------------------------------------------------------------------------ / // Check if the MP3 player is currently not playing, but also the play flag is set // If so, determine which track should be played now // if((MP3player.isPlaying() == 0) && startPlay){ // // Serial.print("albumNumber is: "); // Serial.println(albumNumber); // // // build the trackname from the index // // // empty the trackToPlay char array first! // for( int i = 0; i < sizeof(trackToPlay); ++i ) // trackToPlay[i] = (char)0; // // // create a string with leading zeroes to hold the album number // sprintf(albumNumber, "%03d", albumIndex); // //Serial.print("albumNumber is: "); // //Serial.println(albumNumber); // // sprintf(trackNumber, "%03d", trackIndex); // //Serial.print("trackNumber is: "); // //Serial.println(trackNumber); // // // construct the file path // strcat(trackToPlay, albumNumber); // strcat(trackToPlay, "/"); // strcat(trackToPlay, trackNumber); // strcat(trackToPlay, ".mp3"); // //Serial.println(trackToPlay); // // // play a file, then increment the track index // MP3player.playMP3(trackToPlay); // // // show a play icon on the OLED screen // u8g2.firstPage(); // do { // u8g2.drawTriangle(40,8, 88,32, 40,56); // } while ( u8g2.nextPage() ); // // // //Serial.print("Playing track: "); // //Serial.println(trackToPlay); // // // Increment the track index so next time this comes round we play the next track // trackIndex++; // // // Stop when we get to the end of an album // // Ideally this should work by building an array of track names in the directory // // then looping through till we get to the last one. // // But that is difficult, so for now, I'm just looping through a large number of times // // if (trackIndex == 100) { // change this to a high number for production // // // show a stop icon on the OLED screen // u8g2.firstPage(); // do { // u8g2.drawBox(40,8,48,48); // } while ( u8g2.nextPage() ); // // startPlay = false; // tell the player to stop playing now // trackIndex = 0; // reset the track index so we're ready to play a new album // // } // } // BUTTON FUNCTIONS ----------------------------------------------------------------------- / // READ MEDIA CARD AND SELECT ALBUM TO PLAY FUNCTION if (b_Read.update()) { if (b_Read.read() == LOW) { // if( MP3player.getState() == paused_playback) { // MP3player.resumeMusic(); // } // MP3player.stopTrack(); // stop whatever is playing currently // trackIndex = 1; // 1 if I'm building tracknames dynamically, 0 if I'm using an array // startPlay = true; // shiftRegisterReader(); // get the Album ID from the shift register // Serial.print(F("And the value is: ")); Serial.println(albumIndex); // temporarily adjust the range so I can limit it to just 3 directories // albumIndex = map(albumIndex, 0, 255, 1, 5); // Serial.print(F("Adjusted: ")); // Serial.println(albumIndex); // u8g2.firstPage(); // do { // u8g2.setFont(u8g2_font_helvR14_tr); // u8g2.drawStr(4,24,"Album ID"); // u8g2.setFont(u8g2_font_helvR14_tr); // u8g2.setCursor(4, 44); // u8g2.print(albumIndex); // } while ( u8g2.nextPage() ); } } } // FUNCTIONS TO READ MEDIA CARD AND SUPPLY AN ALBUM ID // I'm using this to generate a directory name from a punchcard style media reader int shiftRegisterReader() { //Pulse the latch pin: //set it to 1 to collect parallel data digitalWrite(latchPin,1); // wait delayMicroseconds(20); //set it to 0 to transmit data serially digitalWrite(latchPin,0); //while the shift register is in serial mode //collect each shift register into a byte //the register attached to the chip comes in first albumIndex = shiftinRevised(dataPin, clockPin, LSBFIRST); return albumIndex; Serial.println(albumIndex); } byte shiftinRevised(byte dataPin, byte clkPin, byte bitOrder) { byte shiftvalue = 0; // Try doing this manually to get around my badly ordered pins digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 3; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 2; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 1; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 0; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 4; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 5; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 6; digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); shiftvalue |= digitalRead(dataPin) << 7; digitalWrite(clkPin, HIGH); return shiftvalue; }