Adding a touch screen elevates this from a simple script to a fully functional standalone device. To achieve this, we will use the popular Adafruit ILI9341 library for the display and the XPT2046_Touchscreen library for the touch input.
You will need to install these three libraries in your Arduino IDE via the Library Manager:
Adafruit GFX Library
Adafruit ILI9341
XPT2046_Touchscreen (by Paul Stoffregen)
Standard ESP32 SPI Wiring
Both the Sender and Receiver will use the SPI bus for the display. Wire both ESP32s to their respective screens as follows:
(Note: T_IRQ, T_DO, T_DIN, and T_CLK share the SPI pins with the display, except for the Touch Chip Select T_CS)
1. Sender Code (The Touch Controller)
This code draws a large "PLAY" button on the screen. When you tap the button, it maps the raw touch coordinates to the screen dimensions and sends the Bluetooth command.
#include "BluetoothSerial.h"
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <XPT2046_Touchscreen.h>
// Display and Touch Pins
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
#define TS_CS 33
// Initialize Display and Touch
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(TS_CS);
// Initialize Bluetooth
BluetoothSerial SerialBT;
String targetName = "ESP32_Speaker";
bool connected = false;
// Button dimensions
int btnX = 40, btnY = 100, btnW = 160, btnH = 80;
bool buttonPressed = false;
void setup() {
Serial.begin(115200);
// Start TFT
tft.begin();
tft.setRotation(1); // Landscape mode
tft.fillScreen(ILI9341_BLACK);
// Start Touch
ts.begin();
ts.setRotation(1);
// UI Setup
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.setCursor(10, 10);
tft.print("Connecting to Speaker...");
// Start Bluetooth
SerialBT.begin("ESP32_Controller", true);
connected = SerialBT.connect(targetName);
tft.fillRect(0, 0, 320, 40, ILI9341_BLACK); // Clear top bar
tft.setCursor(10, 10);
if(connected) {
tft.setTextColor(ILI9341_GREEN);
tft.print("Connected!");
drawPlayButton(ILI9341_BLUE);
} else {
tft.setTextColor(ILI9341_RED);
tft.print("Connection Failed.");
}
}
void loop() {
if (ts.touched() && connected) {
TS_Point p = ts.getPoint();
// Map raw touch coordinates to screen coordinates (values may need tweaking based on your specific screen)
int touchX = map(p.x, 300, 3800, 0, 320);
int touchY = map(p.y, 300, 3800, 0, 240);
// Check if touch is within button bounds
if (touchX > btnX && touchX < (btnX + btnW) && touchY > btnY && touchY < (btnY + btnH)) {
if (!buttonPressed) {
buttonPressed = true;
drawPlayButton(ILI9341_DARKCYAN); // Visual feedback
SerialBT.println("PLAY");
Serial.println("Command Sent");
delay(300); // Debounce
drawPlayButton(ILI9341_BLUE); // Revert button color
}
}
} else {
buttonPressed = false;
}
}
void drawPlayButton(uint16_t color) {
tft.fillRoundRect(btnX, btnY, btnW, btnH, 10, color);
tft.drawRoundRect(btnX, btnY, btnW, btnH, 10, ILI9341_WHITE);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(4);
tft.setCursor(btnX + 35, btnY + 25);
tft.print("PLAY");
------------------
2. Receiver Code (The Display Speaker)
This code waits for the Bluetooth command and updates the screen to show what the device is currently doing.
#include "BluetoothSerial.h"
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// Display Pins
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
BluetoothSerial SerialBT;
const int BUZZER_PIN = 25;
// Song Data
int melody[] = {262, 262, 392, 392, 440, 440, 392, 349, 349, 330, 330, 294, 294, 262};
int noteDurations[] = {500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 1000};
int numNotes = sizeof(melody) / sizeof(melody[0]);
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
// Start TFT
tft.begin();
tft.setRotation(1); // Landscape
tft.fillScreen(ILI9341_BLACK);
// Start Bluetooth
SerialBT.begin("ESP32_Speaker");
updateScreen("Waiting for command...", ILI9341_YELLOW);
}
void loop() {
if (SerialBT.available()) {
String message = SerialBT.readStringUntil('\n');
message.trim();
if (message == "PLAY") {
updateScreen("Playing Song...", ILI9341_GREEN);
playSong();
updateScreen("Waiting for command...", ILI9341_YELLOW);
}
}
}
void playSong() {
for (int i = 0; i < numNotes; i++) {
tone(BUZZER_PIN, melody[i], noteDurations[i] * 0.9);
delay(noteDurations[i]);
}
}
void updateScreen(String text, uint16_t color) {
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(color);
tft.setTextSize(3);
// Center text roughly
int cursorX = 10;
int cursorY = 100;
tft.setCursor(cursorX, cursorY);
tft.print(text);
}
Something to check on the MP3 player module: if the chip used is a clone of the widely used VS1053B, it may have the problem of introducing a ground loop when connected to an external amplifier.
ReplyDeleteIn the VS1053B chip, the speaker output is referenced to a signal called GBUF. This is not a signal ground, but is instead a common reference that is biased above zero volts.
This is fine when connecting to something like headphones or powered speakers, but can produce a short if wired to something like a PC sound card input.
See my warning here:
https://github.com/TheSaturdayThing/laser_seal_arduino/wiki/DANGER