ArduinoGeneral

DFPLayer reset and non repeat

userHead Account cancelled 2022-01-08 04:33:05 407 Views0 Replies
I have a project where I am displaying the verses of a song on a TFT display while playing the song using the DFPlayer module. I'm using a Nano Every and a Adafruit 3.5" TFT display. I copied the logic for the DFPlayer from a example I found on YouTube, it does not use the DFPlayer library but sends the commands via SoftwareSerial. Everything works except 2 things I would like to add.

I only want to play the song once then stop until I reset the Nano. Looking in the play() function it does use the repeat play command, execute_CMD(0x11,0,1);. I tried commenting it out and changing the parameters but it either doesn't play the song or continues to repeat,

I also want to reset the player when I reset the Nano, I used the command execute_CMD(0x0C, 0, 1); in setup, but that also doesn't seem to work.

Here is my sketch
Code: Select all
// mp3 player with TFT display
// Cycles through circles, and verses sync'd with song
// With Bit map image at end
// added DFPlayer

#include <SPI.h>
#include "Adafruit_GFX.h"
#include "Adafruit_HX8357.h"
#include <SD.h>
#include <SPI.h>
// for mp3 player
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 4);
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00 //Returns info with command 0x41 [0x01: info, 0x00: no info]
boolean isPlaying = false;
# define ACTIVATED LOW

// These are 'flexible' lines that can be changed
#define TFT_CS 7
#define TFT_DC 9
#define TFT_RST 8 // RST can be set to -1 if you tie it to Arduino's reset
#define SD_CS 10

// Color definitions
#define BLACK    0x0000
#define BLUE     0x001F
#define RED      0xF800
#define GREEN    0x07E0
#define CYAN     0x07FF
#define MAGENTA  0xF81F
#define YELLOW   0xFFE0 
#define WHITE    0xFFFF

#define MAX_BMP 10  // bmp file num
#define FILENAME_LEN  20 //Max filename length

 
File bmpfile;

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);

char *verse[] = {"zero", "one", "two", "three", "four"};
byte verseNumber = 1;
const unsigned long verseChange = 2000;
unsigned long markTime = millis();
unsigned long currentTime;
long int test = 0;
char *color[] = {BLACK, BLUE, RED, GREEN, CYAN, MAGENTA, YELLOW, WHITE};
byte colorNumber;
int unsigned long verseDly[20];
int verseDlyIndx;


void setup() {

Serial.begin(9600);
mySerial.begin (9600);
delay(1000);

// reset player
  execute_CMD(0x0C, 0, 1);
  delay(500);

// start song
play();
isPlaying = true;
 
  tft.begin();
  tft.fillScreen(BLACK); //clears screen, sets to Black
  tft.setRotation(3);  // rotates screen 90' for landscape mode
  tft.setTextSize(2);
  
// delays between verses
  verseDlyIndx = 1;
  verseDly[1] = 23000;
  verseDly[2] = 27000;
  verseDly[3] = 37000;
  verseDly[4] = 28000;
  verseDly[5] = 27000;
  verseDly[6] = 15000;
  verseDly[7] = 11000;
  verseDly[8] = 32000;
  verseDly[9] = 32000;
  verseDly[10] = 1000;

  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("failed!");
  }
  else Serial.println("OK!");
  
  //bmpDraw("sunrise2.bmp", 0, 0);
  
  } // end setup

void loop() {
  // cycle through verses
  currentTime = millis();
  //Serial.print("verseNumber =");
  //Serial.print("\t");
  //Serial.println(verse[verseNumber]);

// fill screen with circles
if(verseNumber == 1){
  circles();
}
  
// Verse delays
if (((currentTime - markTime) > verseDly[verseDlyIndx]) && verseNumber <= 9)
{
  verseNumber ++;
  verseDlyIndx ++;
  Serial.print(verseNumber);
  Serial.print("\t");
  Serial.println(verseDlyIndx);
   
  switch (verseNumber)
  {
    case 1:
      
      tft.fillScreen(BLACK); //clears screen, sets to Black;
      circles();
     
      markTime = millis();
      
     break;
  
    case 2:
      
      tft.fillScreen(BLACK); //clears screen, sets to Black
      tft.setTextColor(BLUE);
           
        // Print verse 2
      tft.setCursor(10, 70);
      tft.print("Every day is so wonderful"); 
    
      tft.setCursor(10, 100);
      tft.print("Then suddenly it's hard to breathe");
    
      tft.setCursor(10, 130);
      tft.print("Now and then I get insecure");
    
      tft.setCursor(10, 160);
      tft.print("From all the pain");
    
      tft.setCursor(10, 190);
      tft.print("I'm so ashamed");
      
      markTime = millis();
      
      break;
  
   case 3:
      
      tft.fillScreen(BLUE); //clears screen, sets to Black
      tft.setTextColor(WHITE);
          
        // Print verse 3
      tft.setCursor(10, 70);
      tft.print("I am beautiful no matter what they say"); 
    
      tft.setCursor(10, 100);
      tft.print("Words can't bring me down");
    
      tft.setCursor(10, 130);
      tft.print("I am beautiful in every single way");
    
      tft.setCursor(10, 160);
      tft.print("Yes, words can't bring me down, oh no");
    
      tft.setCursor(10, 190);
      tft.print("So don't you bring me down today");
      
      markTime = millis();
    
      break;

   case 4:
      
      tft.fillScreen(RED); //clears screen, sets to Black
      tft.setTextColor(WHITE);
           
        // Print verse 4
      tft.setCursor(10, 70);
      tft.print("To all your friends you're delirious"); 
    
      tft.setCursor(10, 100);
      tft.print("So consumed in all your doom");
    
      tft.setCursor(10, 130);
      tft.print("Trying hard to fill the emptiness");
    
      tft.setCursor(10, 160);
      tft.print("The pieces gone, left the puzzle undone");
    
      tft.setCursor(10, 190);
      tft.print("Is that the way it is?");
      
      markTime = millis();
    
      break;

   case 5:
      
      tft.fillScreen(GREEN); //clears screen, sets to Black
      tft.setTextColor(BLACK);
            
        // Print verse 5
      tft.setCursor(10, 50);
      tft.print("You are so beautiful"); 

      tft.setCursor(60, 70);
      tft.print("no matter what they say");
    
      tft.setCursor(10, 100);
      tft.print("Words can't bring you down, oh no");
    
      tft.setCursor(10, 130);
      tft.print("you are so beautiful");

      tft.setCursor(60, 150);
      tft.print("in every single way");
    
      tft.setCursor(10, 180);
      tft.print("Yes, words can't bring you down, oh no");
    
      tft.setCursor(10, 210);
      tft.print("So don't you bring me down today");
      
      markTime = millis();
    
      break;

   case 6:
      
      tft.fillScreen(MAGENTA); //clears screen, sets to Black
      tft.setTextColor(BLACK);
            
        // Print verse 6
      tft.setCursor(10, 70);
      tft.print("No matter what we do"); 
    
      tft.setCursor(10, 100);
      tft.print("(No matter what we do)");
    
      tft.setCursor(10, 130);
      tft.print("No matter what we say");

      tft.setCursor(10, 160);
      tft.print("(No matter what we say)");
    
      tft.setCursor(10, 190);
      tft.print("We're the song inside the tune (Yeah)");
    
      tft.setCursor(10, 220);
      tft.print("Full of beautiful mistakes");
      
      markTime = millis();
    
      break;

   case 7:
      
      tft.fillScreen(CYAN); //clears screen, sets to Black
      tft.setTextColor(BLACK);
           
        // Print verse 7
      tft.setCursor(10, 70);
      tft.print("And everywhere we go"); 
    
      tft.setCursor(10, 100);
      tft.print("(And everywhere we go)");
    
      tft.setCursor(10, 130);
      tft.print("The sun will always shine");

      tft.setCursor(10, 160);
      tft.print("(The sun will always, always shine)");
    
      tft.setCursor(10, 190);
      tft.print("And tomorrow we might wake up");

      tft.setCursor(60, 210);
      tft.print("on the other side");
      
      markTime = millis();
    
      break;

   case 8:
      
      tft.fillScreen(YELLOW); //clears screen, sets to Black
      tft.setTextColor(BLACK);
            
        // Print verse 8
      tft.setCursor(10, 50);
      tft.print("'cause we are beautiful"); 

      tft.setCursor(60, 70);
      tft.print("no matter what they say");
    
      tft.setCursor(10, 100);
      tft.print("Yes, words won't bring us down, no, no");
    
      tft.setCursor(10, 130);
      tft.print("We are beautiful in every single way");

      tft.setCursor(10, 160);
      tft.print("Yes, words won't bring us down, no, no");
    
      tft.setCursor(10, 190);
      tft.print("So don't you bring me down today");
      
      markTime = millis();
    
      break;

    case 9:
      
      tft.fillScreen(WHITE); //clears screen, sets to Black
      tft.setTextColor(BLUE);
            
        // Print verse 9
      tft.setCursor(10, 70);
      tft.print("Ooh-oh-oh,yeah"); 
    
      tft.setCursor(10, 100);
      tft.print("Don't you bring me down today");
    
      tft.setCursor(10, 130);
      tft.print("Yeah, ooh");

      tft.setCursor(10, 160);
      tft.print("Don't you bring me down today");
    
      tft.setCursor(10, 190);
      tft.print("Ooh,today");
      
      markTime = millis();
    
      break;

    case 10:

    Serial.println("case 10");
      
     // print smilely sunrise
       bmpDraw("sunrise2.bmp", 0, 0);
       
      //markTime = millis();
    
      break;
      
   default:
      
      tft.fillScreen(BLACK); //clears screen, sets to Black
                   
      } // end switch
    
  } // end ((currentTime - markTime))

} // end loop

void circles() {

 tft.fillCircle(random(0,480), random(0,320), random(10, 40), color[random(1, 8)]);
 delay(250);

} // end void circles

#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint16_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print(F("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.startWrite(); // Start TFT transaction
        tft.setAddrWindow(x, y, w, h);

        for (row=0; row<h; row++) { // For each scanline...

          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            tft.endWrite(); // End TFT transaction
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
            tft.startWrite(); // Start new TFT transaction
          }

          for (col=0; col<w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              tft.endWrite(); // End TFT transaction
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
              tft.startWrite(); // Start new TFT transaction
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.color565(r,g,b));
          } // end pixel
        } // end scanline
        tft.endWrite(); // End last TFT transaction
        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println(F("BMP format not recognized."));
}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t read16(File &f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File &f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

void playFirst()
{
  execute_CMD(0x3F, 0, 0);
  delay(500);
  setVolume(20);
  delay(500);
  execute_CMD(0x11,0,1); 
  delay(500);
}// end playFirst

void setVolume(int volume)
{
  execute_CMD(0x06, 0, volume); // Set the volume (0x00~0x30)
  delay(2000);
}

void execute_CMD(byte CMD, byte Par1, byte Par2)
// Excecute the command and parameters
{
// Calculate the checksum (2 bytes)
word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);
// Build the command line
byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge,
Par1, Par2, highByte(checksum), lowByte(checksum), End_Byte};
//Send the command line to the module
for (byte k=0; k<10; k++)
{
mySerial.write( Command_line[k]);
}
}

void play()
{
  execute_CMD(0x3F, 0, 0);
  delay(500);
  setVolume(5);
  delay(500);
  execute_CMD(0x11,0,1); 
  delay(500);
}
Thanks for the help
John