Hi, slowly getting to grips with the static machine ! I have built a sutable board with LEDS and switches and am trying to get to grips with the problems within the introduction to the static machine.
I have also been trying to get the busy pin on the DF mini player working correctly. Currently the sketch works for 1 pass of an RFID TAG then freezes, which was my original problem, although the sketch now looks better then the original. I have noted that the baud speed for the DF Player should be set at 9600 to give it enough time to reset. Running the Serial Monitor at 115200 at the same time does not seem to bother either, the sketch runs well - for the first time. Whilst the track is playing the busy light on the mini player is lit and goes out when the track finishes.
I cannot seem to get out of this loop.
Current sketch:
#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
// SD Card Setup
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)
// RFID Setup
/* Mega Connections for RFID
* RST - 43, * MOSO - 51, * MISO - 50, * SCK - 52, * SDA - 53
*/
#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 18 and 19 to communicate with DFPlayer Mini
# define Busy_PIN 42
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);
int BusyState = 0; // Busy state variables
int prevBusyState = 0;
// Create the Player object
DFRobotDFPlayerMini player;
// TFT Setup
#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
// Array through structuring 'Card'
struct Card {
const char * imageName;
const char * fileName;
byte size; // Number of bytes in the UID. 4, 7 or 10.
byte uidByte[10];
const char * soundName;
};
Card knownCards[] = {
{ "Talyllyn", "Talyllyn_400x267.bmp", 4, {0x49, 0x0E, 0x4F, 0xA2}, "0001_Talyllyn.wav"},
{ "Dolgoch", "Dolgoch_400x267.bmp", 4, {0x61, 0x2C, 0x28, 0x27}, "0002_Dolgoch.wav"},
{ "Sir Haydn", "Sir_Haydn_400x267.bmp", 4, {0x60, 0xAB, 0x66, 0x1B}, "0003_Sir Haydn.wav"},
{ "Sir Henry", "Sir_Henry_400x267.bmp", 4, {0x91, 0x6B, 0x0E, 0x26}, "0004_Tom Rolt.wav"},
{ "Unknown", " ", 0, {" "}, " "}, // this is a catch all card when unknown card is presented
};
constexpr size_t knownCardsCount = (sizeof knownCards / sizeof * knownCards) - 1; // -1 because the very last one is a catch all card
void hexDump(byte *buffer, size_t bufferSize) {
for (size_t i = 0; i < bufferSize; i++) {
Serial.write(buffer[i] < 0x10 ? '0' : ' ');
Serial.print(buffer[i], HEX);
Serial.write(' ');
}
}
void setup()
{
uint16_t ID;
Serial.begin(9600);
// Serial.println("Show BMP files on TFT with ID:0x");
ID = tft.readID();
// Serial.println(ID, HEX);
if (ID == 0x0D3D3) ID = 0x9481;
tft.begin(ID);
tft.setRotation(3);
tft.fillScreen(BLACK);
tft.setTextSize(2);
tft.setTextColor(GREEN);
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 needed for mega, not uno
Serial.println("OK");
// Set volume to maximum (0 to 30).
player.volume(25);
pinMode(Busy_PIN, INPUT);
{
Serial.println("Put your RFID tag close to the reader...");
Serial.println();
}
root = SD.open(namebuf);
pathlen = strlen(namebuf);
}
void loop()
{
if ( ! mfrc522.PICC_IsNewCardPresent()) return;
if ( ! mfrc522.PICC_ReadCardSerial()) return;
MFRC522::Uid currentCard = mfrc522.uid; // copy what we received
mfrc522.PICC_HaltA(); // Halt PICC
mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD
size_t cardIndex = 0; // See notes
for (; cardIndex < knownCardsCount; cardIndex++)
if (knownCards[cardIndex].size == currentCard.size)
if (memcmp(knownCards[cardIndex].uidByte, currentCard.uidByte, currentCard.size) == 0) break; // found (see https://cplusplus.com/reference/cstring/memcmp/)
//Show UID and image name on serial monitor (if not found, cardIndex is equal to knownCardsCount which is the last "catch all" card
Serial.print(F("Tag: "));
hexDump(currentCard.uidByte, currentCard.size);
Serial.print(F("-> "));
Serial.println(knownCards[cardIndex].imageName);
BusyState = digitalRead (Busy_PIN);
if (BusyState != prevBusyState) {
if (BusyState == LOW);
}
prevBusyState == BusyState;
Serial.println ("playing");
if (cardIndex == 0) { // Talyllyn
Serial.println(knownCards[cardIndex].imageName);
showBMP(knownCards[cardIndex].fileName, 40, 0);
tft.setCursor(180, 285);
tft.println(knownCards[cardIndex].imageName);
player.play(knownCards[cardIndex].soundName);
}
else if (cardIndex == 1) { // Dolgoch
Serial.println(knownCards[cardIndex].imageName);
showBMP(knownCards[cardIndex].fileName, 40, 0);
tft.setCursor(180, 285);
tft.println(knownCards[cardIndex].imageName);
player.play(knownCards[cardIndex].soundName);
}
else if (cardIndex == 2) { // Sir Haydn
Serial.println(knownCards[cardIndex].imageName);
showBMP(knownCards[cardIndex].fileName, 40, 0);
tft.setCursor(180, 285);
tft.println(knownCards[cardIndex].imageName);
player.play(knownCards[cardIndex].soundName);
}
else if (cardIndex == 3) { // Sir Henry
Serial.println(knownCards[cardIndex].imageName);
showBMP(knownCards[cardIndex].fileName, 40, 0);
tft.setCursor(180, 285);
tft.println(knownCards[cardIndex].imageName);
player.play(knownCards[cardIndex].soundName);
}
else { // Unknown card
Serial.println("No cigar...");
}
tft.fillScreen(BLACK); //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
}
prevBusyState = BusyState;
Serial.println();
bmpFile.close();
return (ret);
}
In addition, the sound track played is always the track related to the 3rd RFID TAG. Each tag always brings up the correct image but only playes the sound for 'Sir Haydn' the 3rd tag on the card index. Whilst learning lots, I am baffled by this !
Any pointers gratefully received.
Regards,
Brian