Hi,
I am writing a sketch to show an image of a train and then play its sound. The sketch uses RFID to trigger the image and sound.
The sketch runs without the sound successfully and when ready will look for a 2nd RFID tag to pass and successfully display the image.
I have added a DFMini Player for the sound which plays for the first tag but the sketch 'freezes' and I cannot work out why !
I am using a Mega with 3.5" TFT screen and a DF Mini Player:
Screen is 3.5" TFT LCD Display Module For Arduino & Mega 2560 Board Touch Panel 480x320 UK | eBay and DF Mini MP3 DF Player Module Module Music Audio FAST SHI O8F8 J9K C8H4 .
I have run sketches with the same connections for the image and for the sounds, all works OK. When I run the combined sketch I have the lock up problem and as stated it runs for one pass of the RFID tag and then runs the sketch to show the second image, lights the relevant LED and the freezes before playing the sound.
I know the sketch is slightly cumbersome with the LEDs and Serial Monitor but I use these to help guide me through the running sequence and fault find.
Code:
#include <SPI.h> // f.k. for Arduino-1.5.2
#define USE_SDFAT
#include <SdFat.h> // Use the SdFat library
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#if SPI_DRIVER_SELECT != 2
#error edit SdFatConfig.h . READ THE SKETCH INSTRUCTIONS
#endif
/* Mega Connections for RFID
* RST - 43
* MOSO - 51
* MISO - 50
* SCK - 52
* SDA - 53
*/
SoftSpiDriver<12, 11, 13> softSpi; //Bit-Bang on the Shield pins SDFat.h v2
SdFat SD;
#define SD_CS SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)
#include <MFRC522.h> //include library code for RFID
const int SS_PIN = 53; //define RFID pins
const int RST_PIN = 43;
MFRC522 mfrc522(SS_PIN, RST_PIN); //create MFRC522 instance.
// DF MiniPlayer setup
// Use pins 30 and 31 to communicate with DFPlayer Mini
static const uint8_t PIN_MP3_TX = 18; // Connects to module's RX
static const uint8_t PIN_MP3_RX = 19; // Connects to module's TX
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);
// Create the Player object
DFRobotDFPlayerMini player;
//LED Setup
const int redLEDpin = A8; // red LED attached to analog pin 8
const int greenLEDpin = A9; // green LED attached to analog pin 7
const int blueLEDpin = A10; // blue LED attahced to analog pin 10
const int yellowLEDpin = A11;// green LED attached to analog pin 11
#include <Adafruit_GFX.h> // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#define NAMEMATCH "" // "" matches any name
#define PALETTEDEPTH 8 // support 256-colour Palette
char namebuf[32] = "/"; //BMP files in root directory
File root;
int pathlen;
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
void setup()
{
uint16_t ID;
Serial.begin(9600);
Serial.print("Show BMP files on TFT with ID:0x");
ID = tft.readID();
Serial.println(ID, HEX);
if (ID == 0x0D3D3) ID = 0x9481;
tft.begin(ID);
tft.fillScreen(WHITE);
tft.setTextColor(0xFFFF, 0x0000);
bool good = SD.begin(SD_CS);
if (!good)
Serial.print(F("cannot start SD"));
while (!Serial)
delay(100);
SPI.begin(); //initiate SPI bus
mfrc522.PCD_Init(); //initiate MFRC522
// Mini Player
softwareSerial.begin(9600);// Start communication with DFPlayer Mini
if (player.begin(softwareSerial, true, false)) // true, false neede for mega, not uno
Serial.println("OK");
// Set volume to maximum (0 to 30).
player.volume(30);
pinMode(redLEDpin, OUTPUT); //sets redLEDpin as OUTPUT
pinMode(greenLEDpin, OUTPUT);//sets greenLEDpin as OUTPUT
pinMode(yellowLEDpin, OUTPUT);//sets greenLEDpin as OUTPUT
pinMode(blueLEDpin, OUTPUT);//sets greenLEDpin as OUTPUT
{
Serial.println("Put your RFID tag close to the reader...");
Serial.println();
}
root = SD.open(namebuf);
pathlen = strlen(namebuf);
}
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
//Show UID on serial monitor
Serial.print("UID tag :");
String content = "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
Serial.println();
Serial.print("Message : ");
content.toUpperCase();
tft.setRotation(3);
if (content.substring(1) == "49 0E 4F A2") //change here the UID of the card/cards that you want to give access
{
Serial.println("Talyllyn.bmp");
digitalWrite(redLEDpin, HIGH);
showBMP("Talyllyn_400x267.bmp", 40, 0);
tft.fillRoundRect(40, 267, 400, 50, 5, RED);
tft.setCursor(180, 285);
tft.setTextSize(2);
tft.setTextColor(GREEN);
tft.println("Talyllyn");
player.play(8);
delay(3000);
digitalWrite(redLEDpin, LOW);
}
else if (content.substring(1)=="61 2C 28 27")
{
Serial.println("Dolgoch.bmp");
digitalWrite(greenLEDpin, HIGH);
showBMP("Dolgoch_400x267.bmp", 40, 0);
tft.fillRoundRect(40, 267, 400, 50, 5, GREEN);
tft.setCursor(180, 285);
tft.setTextSize(2);
tft.setTextColor(BLUE);
tft.println("Dolgoch");
player.play(9);
delay(3000);
digitalWrite(greenLEDpin, LOW);
}
else if (content.substring(1)=="60 AB 66 1B")
{
Serial.println("Sir Haydn");
digitalWrite(blueLEDpin, HIGH);
showBMP("Sir_Haydn_400x267.bmp", 40, 0);
tft.fillRoundRect(40, 267, 400, 50, 5, BLUE);
tft.setCursor(180, 285);
tft.setTextSize(2);
tft.setTextColor(YELLOW);
tft.println("Sir Haydn");
player.play(10);
delay(3000);
digitalWrite(blueLEDpin, LOW);
}
else
{
Serial.println("Sir Henry");
digitalWrite(yellowLEDpin, HIGH);
showBMP("Sir_Henry_400x267.bmp", 40, 0);
tft.fillRoundRect(40, 267, 400, 50, 5, YELLOW);
tft.setCursor(180, 285);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.println("Sir Henry");
player.play(11);
delay(3000);
digitalWrite(yellowLEDpin, LOW);
}
for(int i=0; i<150; i+=10){
}
tft.fillScreen(WHITE); //resets screen to white after BMP loaded
Serial.println("Put your RFID tag close to the reader...");
}
#define BMPIMAGEOFFSET 54
#define BUFFPIXEL 20 // must be a divisor of 240
uint16_t read16(File& f) {
uint16_t result; // read little-endian
f.read(&result, sizeof(result));
return result;
}
uint32_t read32(File& f) {
uint32_t result;
f.read(&result, sizeof(result));
return result;
}
uint8_t showBMP(char *nm, int x, int y)
{
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24, 16, 8, 4, 1)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL;
uint8_t bitmask, bitshift;
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx;
uint32_t pos; // seek position
boolean is565 = false; //
uint16_t bmpID;
uint16_t n; // blocks read
uint8_t ret;
if ((x >= tft.width()) || (y >= tft.height()))
return 1; // off screen
bmpFile = SD.open(nm); // Parse BMP header
bmpID = read16(bmpFile); // BMP signature
(void) read32(bmpFile); // Read & ignore file size
(void) read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
(void) read32(bmpFile); // Read & ignore DIB header size
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
n = read16(bmpFile); // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
pos = read32(bmpFile); // format
if (bmpID != 0x4D42) ret = 2; // bad ID
else if (n != 1) ret = 3; // too many planes
else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565
else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette
else {
bool first = true;
is565 = (pos == 3); // ?already in 16-bit format
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
if (bmpHeight < 0) { // If negative, image is in top-down order.
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w) >= tft.width()) // Crop area to be loaded
w = tft.width() - x;
if ((y + h) >= tft.height()) //
h = tft.height() - y;
if (bmpDepth <= PALETTEDEPTH) { // these modes have separate palette
//bmpFile.seek(BMPIMAGEOFFSET); //palette is always @ 54
bmpFile.seek(bmpImageoffset - (4<<bmpDepth)); //54 for regular, diff for colorsimportant
bitmask = 0xFF;
if (bmpDepth < 8)
bitmask >>= bmpDepth;
bitshift = 8 - bmpDepth;
n = 1 << bmpDepth;
lcdbufsiz -= n;
palette = lcdbuffer + lcdbufsiz;
for (col = 0; col < n; col++) {
pos = read32(bmpFile); //map palette to 5-6-5
palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8);
}
}
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
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).
uint8_t r, g, b, *sdptr;
int lcdidx, lcdleft;
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?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col = 0; col < w; ) { //pixels in row
lcdleft = w - col;
if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
uint16_t color;
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
r = 0;
}
switch (bmpDepth) { // Convert pixel from BMP to TFT format
case 24:
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
color = tft.color565(r, g, b);
break;
case 16:
b = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
if (is565)
color = (r << 8) | (b);
else
color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
break;
case 1:
case 4:
case 8:
if (r == 0)
b = sdbuffer[buffidx++], r = 8;
color = palette[(b >> bitshift) & bitmask];
r -= bmpDepth;
b <<= bmpDepth;
break;
}
lcdbuffer[lcdidx] = color;
}
tft.pushColors(lcdbuffer, lcdidx, first);
first = false;
col += lcdidx;
} // end cols
} // end rows
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
ret = 0; // good render
}
Serial.println();
bmpFile.close();
return (ret);
}
Any suggestions gratefully received,
Brian