Hi all, I'm new to this forum and new to Arduino as I recently picked up a tutorial kit to learn the basics. After that I jumped into the deep end, as my goal is to implement Arduino for light and sound on a starship project I'm working on.
The issue:
I'm using a DFPlayer Mini in combination with an Arduino Uno. This works fine. But when I transfer the code to an ATTiny85 the code doesn't behave the same:
Almost everything works, except the player.volume() . For some reason the ATTiny85 doesn't seem to understand or process this variable, whatever number from 0 to 30 I set there, the volume of the sound always remains at max level.
Bootloader core that supports serial communication used for ATTiny85 is this one, by Sleemanj:
I tried searching for this combination or similar problem on the internet but am at a loss. Especially since all other commands works perfectly.
Code (with pin designations for ATTiny85). Please note, besides the DFPlayerMini_Fast library I also tried using the DFRobotDFPlayerMini library. But both give the same result.
#include "SoftwareSerial.h"
#include "DFPlayerMini_Fast.h"
long prev = 0;
int buttonState = 0; // 0 = not pressed --- 1 = long pressed --- 2 short pressed
int buttonPin = 2; // The button used to trigger music and audio clips
int duration = 600; // How long it takes to reach long press
int clipNumber = 0; // counter for short audio clips
int trackNumber = 0; // counter for music
// Use pins to communicate with DFPlayer Mini
static const uint8_t PIN_MP3_TX = 0; // This MUST be pin 0 on ATtiny85 for serial to work! Connects to module's RX
static const uint8_t PIN_MP3_RX = 1; // This MUST be pin 1 on ATtiny85 for serial to work! Connects to module's TX.
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);
// Create the Player object
DFPlayerMini_Fast player;
void setup() {
pinMode(buttonPin, INPUT);
// Init USB serial port for debugging
Serial.begin(9600);
// Init serial port for DFPlayer Mini
softwareSerial.begin(9600);
// Start communication with DFPlayer Mini
if (player.begin(softwareSerial)) {
Serial.println("OK");
// Set volume to maximum (0 to 30).
player.volume(20);
} else {
Serial.println("Connecting to DFPlayer Mini failed!");
}
}
void loop() {
buttonState = 0;
if (digitalRead(buttonPin)) {
prev = millis();
buttonState = 1;
while ((millis() - prev) <= duration) {
if (!(digitalRead(buttonPin))) {
buttonState = 2;
break;
}
}
}
if (!buttonState) { // TODO nothing is pressed
}
else if (buttonState == 1) { // TODO button is pressed long
clipNumber = (clipNumber + 1) % 5; // modulo operator to track button presses
if (clipNumber == 1) {
player.playFromMP3Folder(11); // Plays clip 11
delay(3000);
} else if (clipNumber == 2) {
player.playFromMP3Folder(12); // Plays clip 12
delay(3000);
} else if (clipNumber == 3) {
player.playFromMP3Folder(13); // Plays clip 13
delay(3000);
} else if (clipNumber == 4) {
player.playFromMP3Folder(14); // Plays clip 14
delay(3000);
} else {
player.playFromMP3Folder(15); // Plays clip 15
delay(3000);
}
} else {
}
if (buttonState == 2) { //TODO button is pressed short
delay(300); // Delay for a period of time (in milliseconds). Useful for debounce
trackNumber = (trackNumber + 1) % 4; // modulo operator to track button presses
if (trackNumber == 1) {
player.playFromMP3Folder(1); // Plays track 1
} else if (trackNumber == 2) {
player.stop(); // Stop playing
} else if (trackNumber == 3) {
player.playFromMP3Folder(2); // Plays track 2
} else {
player.stop(); // Stop playing
}
} else {
}
}
And the pin layout of the ATTiny85 in the Sleemanj core:
If so, you could connect it to the DFPlayer TX pin and GND, then monitor the output in a serial terminal to check whether the hexadecimal frame and checksum sent by the ATtiny85 are correct.
This would help determine if the issue is not caused by a timing glitch or similar SoftwareSerial problem.
According to pinout, you connect your Serial and SoftwareSerial to same pins 0 & 1. You can't expect to use both serials at the time without issues.
When you print the debug messages to the Serial, it sends also to DFPlayer and can interrupt it's work. Comment outputting "OK" message in this peace of the code :
I don't have a serial to USB cable, but I tried commenting out the debug message before the volume command. Unfortunately this didn't do anything.
It did however push me to try something else: Use the example code from the DFPlayerMini_Fast github.
So that example code did work with the ATTiny85, including the volume. I'm not really sure why it works, but the only obvious difference I noticed that in the example the definition of RX and TX was moved to the beginning of the code, right after including the SoftwareSerial library instead of defining them as static constants.
I also named my serial "mySerial" as per the example, instead of ""softwareSerial". I don't know if that matters for the ATTiny85, as I'm now just glad it works.
So, problem solved. Below is my cleaned up working code:
#include <DFPlayerMini_Fast.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(1, 0); // RX, TX
DFPlayerMini_Fast player;
long prev = 0;
int buttonState = 0; // 0 = not pressed --- 1 = long pressed --- 2 short pressed
int buttonPin = 2; // The button used to trigger music and audio clips
int duration = 600; // How long it takes to reach long press
int clipNumber = 0; // counter for short audio clips
int trackNumber = 0; // counter for music
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(9600);
mySerial.begin(9600);
player.begin(mySerial, true, false); // adding false statement to eliminate speaker pop at startup, why it works no idea
delay(1000);
player.volume(20); // Playback volume min 0 to max 30
}
void loop() {
buttonState = 0;
if (digitalRead(buttonPin)) {
prev = millis();
buttonState = 1;
while ((millis() - prev) <= duration) {
if (!(digitalRead(buttonPin))) {
buttonState = 2;
break;
}
}
}
if (!buttonState) { // TODO nothing is pressed
}
else if (buttonState == 1) { // TODO button is pressed long
clipNumber = (clipNumber + 1) % 5; // modulo operator to track button presses
if (clipNumber == 1) {
player.playFromMP3Folder(11); // Plays clip 11
delay(3000);
} else if (clipNumber == 2) {
player.playFromMP3Folder(12); // Plays clip 12
delay(3000);
} else if (clipNumber == 3) {
player.playFromMP3Folder(13); // Plays clip 13
delay(3000);
} else if (clipNumber == 4) {
player.playFromMP3Folder(14); // Plays clip 14
delay(3000);
} else {
player.playFromMP3Folder(15); // Plays clip 15
delay(3000);
}
} else {
}
if (buttonState == 2) { //TODO button is pressed short
delay(300); // Delay for a period of time (in milliseconds). Useful for debounce
trackNumber = (trackNumber + 1) % 4; // modulo operator to track button presses
if (trackNumber == 1) {
player.playFromMP3Folder(1); // Plays track 1
} else if (trackNumber == 2) {
player.stop(); // Stop playing
} else if (trackNumber == 3) {
player.playFromMP3Folder(2); // Plays track 2
} else {
player.stop(); // Stop playing
}
} else {
}
}
Ah yes, I didn't realize that difference. I had a previous version of the code with the true and false statements which works with the Arduino Uno. I left it out of my ATTiny85 code at some point probably because I was clutching at straws to get it to work.
It must be the added delay then. It worked on the Uno without the delay, but I'm guessing the ATTiny85 needs the delay because it processes the code slower?
I'm curious, but I'll have to try later. I cleared the breadboard as I'm currently integrating the DFPlayer as a second DFPlayer into my main project. Ideally I want to control my whole project with one IC (the Arduino Uno, and when all is finished just an ATMega328) but my main code got too bulky for me to comprehend. So I offloaded the second DFPlayer to the ATTiny85 as an experiment to make it more comprehensible to me.
Anyway, with Arduino code it looks like a nights' sleep really does wonders to clear the mind and it looks like I'm getting somewhere with the main project.
I'll report back when I get around to testing with the ATTiny85 again!