|
|
@@ -0,0 +1,319 @@ |
|
|
|
// === OVERVIEW === |
|
|
|
// Tape Deck player replacement |
|
|
|
// |
|
|
|
// VU meter --> OLED display |
|
|
|
// Cassette player --> MP3 player |
|
|
|
|
|
|
|
// === MP3 PLAYER === |
|
|
|
/*************************************************** |
|
|
|
DFPlayer - A Mini MP3 Player For Arduino |
|
|
|
<https://www.dfrobot.com/product-1121.html> |
|
|
|
|
|
|
|
*************************************************** |
|
|
|
This example shows the basic function of library for DFPlayer. |
|
|
|
|
|
|
|
Created 2016-12-07 |
|
|
|
By [Angelo qiao](Angelo.qiao@dfrobot.com) |
|
|
|
|
|
|
|
GNU Lesser General Public License. |
|
|
|
See <http://www.gnu.org/licenses/> for details. |
|
|
|
All above must be included in any redistribution |
|
|
|
****************************************************/ |
|
|
|
|
|
|
|
/***********Notice and Trouble shooting*************** |
|
|
|
1.Connection and Diagram can be found here |
|
|
|
<https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram> |
|
|
|
2.This code is tested on Arduino Uno, Leonardo, Mega boards. |
|
|
|
****************************************************/ |
|
|
|
|
|
|
|
#include "Arduino.h" |
|
|
|
#include "SoftwareSerial.h" |
|
|
|
#include "DFRobotDFPlayerMini.h" |
|
|
|
#include "EEPROM.h" |
|
|
|
|
|
|
|
#define PIN_EQ A1 |
|
|
|
#define PIN_CHROME 6 |
|
|
|
#define PIN_FORWARD 10 |
|
|
|
#define EEPROM_SONG_INDEX 1 |
|
|
|
#define SKIP_LIMIT 250 |
|
|
|
#define EEPROM_SKIP 2 |
|
|
|
|
|
|
|
SoftwareSerial mySoftwareSerial(9, 8); // RX, TX |
|
|
|
DFRobotDFPlayerMini myDFPlayer; |
|
|
|
void printDetail(uint8_t type, int value); |
|
|
|
|
|
|
|
int song_index = 0; |
|
|
|
unsigned long song_started = 0; |
|
|
|
int files_max = -1; |
|
|
|
bool skipping = false; |
|
|
|
|
|
|
|
void setup_player() |
|
|
|
{ |
|
|
|
pinMode(PIN_EQ, INPUT); |
|
|
|
pinMode(PIN_CHROME, INPUT); |
|
|
|
pinMode(PIN_FORWARD, INPUT); |
|
|
|
analogReference(DEFAULT); |
|
|
|
|
|
|
|
Serial.begin(9600); |
|
|
|
while (!Serial && millis() < 2000) { delay(10); } |
|
|
|
|
|
|
|
song_index = EEPROM.read(EEPROM_SONG_INDEX); |
|
|
|
unsigned int song_skip = EEPROM.read(EEPROM_SKIP); |
|
|
|
if (song_skip > SKIP_LIMIT) { |
|
|
|
song_skip = 0; |
|
|
|
} |
|
|
|
song_index += song_skip; |
|
|
|
if (song_index >= 255) { |
|
|
|
song_index = 0; |
|
|
|
} |
|
|
|
|
|
|
|
Serial.println(); |
|
|
|
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); |
|
|
|
mySoftwareSerial.begin(9600); |
|
|
|
if (!myDFPlayer.begin(mySoftwareSerial)) { |
|
|
|
Serial.println(F("Unable to begin:")); |
|
|
|
Serial.println(F("1.Please recheck the connection!")); |
|
|
|
Serial.println(F("2.Please insert the SD card!")); |
|
|
|
while(true){ |
|
|
|
delay(0); |
|
|
|
} |
|
|
|
} |
|
|
|
Serial.println(F("DFPlayer Mini online.")); |
|
|
|
|
|
|
|
myDFPlayer.volume(20); //Set volume value. From 0 to 30 |
|
|
|
myDFPlayer.play(song_index+1); //Play the first mp3 |
|
|
|
do { |
|
|
|
delay(100); |
|
|
|
files_max = myDFPlayer.readFileCounts(); |
|
|
|
} while (files_max <= -1); |
|
|
|
|
|
|
|
if (digitalRead(PIN_FORWARD) == 1) { |
|
|
|
// FastForward |
|
|
|
skipping = true; |
|
|
|
while (true) { |
|
|
|
delay(500); |
|
|
|
if (digitalRead(PIN_FORWARD) == 1) { |
|
|
|
song_skip = min(song_skip + 1, SKIP_LIMIT); |
|
|
|
EEPROM.update(EEPROM_SKIP, song_skip); |
|
|
|
Serial.print("Skipping +1 ... "); |
|
|
|
} else { |
|
|
|
Serial.print("Skipping +0 ... "); |
|
|
|
} |
|
|
|
if (song_index + song_skip >= files_max) { |
|
|
|
song_index = 0; |
|
|
|
song_skip = 0; |
|
|
|
} |
|
|
|
myDFPlayer.play(song_index + song_skip + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL); |
|
|
|
|
|
|
|
if (files_max > 0 && song_index >= files_max) { |
|
|
|
Serial.println("Song index out of bounds, skipping to next."); |
|
|
|
nextSong(); |
|
|
|
} |
|
|
|
|
|
|
|
song_started = millis(); |
|
|
|
} |
|
|
|
|
|
|
|
int eq_now = DFPLAYER_EQ_NORMAL; |
|
|
|
|
|
|
|
void loop_player() |
|
|
|
{ |
|
|
|
static unsigned long eq_timer = millis(); |
|
|
|
|
|
|
|
if (millis() - eq_timer > 100) { |
|
|
|
eq_timer = millis(); |
|
|
|
int eq_next = eq_now; |
|
|
|
int eqChrome = digitalRead(PIN_CHROME); |
|
|
|
if (eqChrome == 0) { |
|
|
|
//analogReference(DEFAULT); |
|
|
|
int eqRaw = analogRead(PIN_EQ); |
|
|
|
//Serial.print("EQ: "); |
|
|
|
//Serial.println(eqRaw); |
|
|
|
if (eqRaw < 512) { |
|
|
|
eq_next = DFPLAYER_EQ_BASS; |
|
|
|
//Serial.println("EQ: Bass"); |
|
|
|
} else if (eqRaw < 900) { |
|
|
|
eq_next = DFPLAYER_EQ_NORMAL; |
|
|
|
//Serial.println("EQ: Normal"); |
|
|
|
} else { |
|
|
|
eq_next = DFPLAYER_EQ_POP; |
|
|
|
//Serial.println("EQ: POP"); |
|
|
|
} |
|
|
|
} else { |
|
|
|
eq_next = DFPLAYER_EQ_ROCK; |
|
|
|
//Serial.println("EQ: Rock"); |
|
|
|
} |
|
|
|
if (eq_now != eq_next) { |
|
|
|
eq_now = eq_next; |
|
|
|
myDFPlayer.EQ(eq_now); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (myDFPlayer.available()) { |
|
|
|
printDetail(myDFPlayer.readType(), myDFPlayer.read()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void nextSong() { |
|
|
|
int files_max = myDFPlayer.readFileCounts(); |
|
|
|
song_index = (song_index + 1) % files_max; |
|
|
|
EEPROM.update(EEPROM_SONG_INDEX, song_index); |
|
|
|
EEPROM.update(EEPROM_SKIP, 0); |
|
|
|
myDFPlayer.play(song_index + 1); |
|
|
|
song_started = millis(); |
|
|
|
Serial.println("Next song..."); |
|
|
|
} |
|
|
|
|
|
|
|
void printDetail(uint8_t type, int value){ |
|
|
|
switch (type) { |
|
|
|
case TimeOut: |
|
|
|
Serial.println(F("Time Out!")); |
|
|
|
break; |
|
|
|
case WrongStack: |
|
|
|
Serial.println(F("Stack Wrong!")); |
|
|
|
break; |
|
|
|
case DFPlayerCardInserted: |
|
|
|
Serial.println(F("Card Inserted!")); |
|
|
|
break; |
|
|
|
case DFPlayerCardRemoved: |
|
|
|
Serial.println(F("Card Removed!")); |
|
|
|
myDFPlayer.stop(); |
|
|
|
break; |
|
|
|
case DFPlayerCardOnline: |
|
|
|
Serial.println(F("Card Online!")); |
|
|
|
myDFPlayer.start(); |
|
|
|
break; |
|
|
|
case DFPlayerUSBInserted: |
|
|
|
Serial.println("USB Inserted!"); |
|
|
|
break; |
|
|
|
case DFPlayerUSBRemoved: |
|
|
|
Serial.println("USB Removed!"); |
|
|
|
break; |
|
|
|
case DFPlayerPlayFinished: |
|
|
|
Serial.print(F("Number:")); |
|
|
|
//Serial.print(value); |
|
|
|
Serial.println(F(" Play Finished!")); |
|
|
|
nextSong(); |
|
|
|
break; |
|
|
|
case DFPlayerError: |
|
|
|
Serial.print(F("DFPlayerError:")); |
|
|
|
switch (value) { |
|
|
|
case Busy: |
|
|
|
Serial.println(F("Card not found")); |
|
|
|
break; |
|
|
|
case Sleeping: |
|
|
|
Serial.println(F("Sleeping")); |
|
|
|
break; |
|
|
|
case SerialWrongStack: |
|
|
|
Serial.println(F("Get Wrong Stack")); |
|
|
|
break; |
|
|
|
case CheckSumNotMatch: |
|
|
|
Serial.println(F("Check Sum Not Match")); |
|
|
|
break; |
|
|
|
case FileIndexOut: |
|
|
|
Serial.println(F("File Index Out of Bound")); |
|
|
|
delay(1000); |
|
|
|
song_index = 0; |
|
|
|
myDFPlayer.play(song_index + 1); |
|
|
|
break; |
|
|
|
case FileMismatch: |
|
|
|
Serial.println(F("Cannot Find File")); |
|
|
|
break; |
|
|
|
case Advertise: |
|
|
|
Serial.println(F("In Advertise")); |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// === DISPLAY === |
|
|
|
#include <SPI.h> |
|
|
|
#include <Wire.h> |
|
|
|
#include <Adafruit_GFX.h> |
|
|
|
#include <Adafruit_SH110X.h> |
|
|
|
|
|
|
|
#define PIN_VU A0 |
|
|
|
#define VU_SCALE 1 |
|
|
|
#define VU_WARN 700 |
|
|
|
#define VU_CRIT 900 |
|
|
|
#define VU_SLOWDOWN 10 |
|
|
|
#define VU_ATTACK 1 |
|
|
|
|
|
|
|
/* Uncomment the initialize the I2C address , uncomment only one, If you get a totally blank screen try the other*/ |
|
|
|
#define i2c_Address 0x3c //initialize with the I2C addr 0x3C Typically eBay OLED's |
|
|
|
//#define i2c_Address 0x3d //initialize with the I2C addr 0x3D Typically Adafruit OLED's |
|
|
|
|
|
|
|
#define SCREEN_WIDTH 128 // OLED display width, in pixels |
|
|
|
#define SCREEN_HEIGHT 64 // OLED display height, in pixels |
|
|
|
#define OLED_RESET -1 // QT-PY / XIAO |
|
|
|
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); |
|
|
|
|
|
|
|
void setup_display() { |
|
|
|
//Serial.begin(9600); |
|
|
|
|
|
|
|
delay(250); // wait for the OLED to power up |
|
|
|
display.begin(i2c_Address, true); // Address 0x3C default |
|
|
|
display.setContrast (0); // dim display |
|
|
|
|
|
|
|
// Clear the buffer. |
|
|
|
display.clearDisplay(); |
|
|
|
display.display(); |
|
|
|
|
|
|
|
display.setTextSize(2); |
|
|
|
display.setTextColor(SH110X_WHITE); |
|
|
|
display.setCursor(0, 20); |
|
|
|
display.println(" UNIVERSUM"); |
|
|
|
display.setTextSize(1); |
|
|
|
display.display(); |
|
|
|
delay(500); |
|
|
|
display.clearDisplay(); |
|
|
|
} |
|
|
|
|
|
|
|
void loop_display() |
|
|
|
{ |
|
|
|
display.clearDisplay(); |
|
|
|
|
|
|
|
display.setTextSize(2); |
|
|
|
display.setTextColor(SH110X_WHITE); |
|
|
|
display.setCursor(35, 20); |
|
|
|
unsigned long song_time = (millis() - song_started) / 1000; |
|
|
|
char song_time_text[16]; |
|
|
|
sprintf(song_time_text, "%02d", song_time / 60); |
|
|
|
display.print(song_time_text); |
|
|
|
display.print(":"); |
|
|
|
sprintf(song_time_text, "%02d", song_time % 60); |
|
|
|
display.println(song_time_text); |
|
|
|
|
|
|
|
display.setTextSize(1); |
|
|
|
display.setCursor(37, 50); |
|
|
|
char song_index_text[16]; |
|
|
|
sprintf(song_index_text, "%03d", song_index+1); |
|
|
|
display.print(song_index_text); |
|
|
|
display.print(" / "); |
|
|
|
char song_count_text[16]; |
|
|
|
sprintf(song_count_text, "%03d", files_max); |
|
|
|
display.print(song_count_text); |
|
|
|
|
|
|
|
display.display(); |
|
|
|
} |
|
|
|
|
|
|
|
// === MAIN === |
|
|
|
|
|
|
|
void setup() { |
|
|
|
setup_player(); |
|
|
|
setup_display(); |
|
|
|
} |
|
|
|
|
|
|
|
void loop() { |
|
|
|
loop_player(); |
|
|
|
loop_display(); |
|
|
|
} |