Ciao a tutti.
Ho acquistato il modulo breakout VS1053b di Adafruit.
Ho fatto un po’ di test e funziona molto bene.
Purtroppo però noto che se voglio far partire un suono in determinate condizioni non va come dovrebbe e non riesco a capire il perché.
Attualmente ho un led che si accende alla pressione di un pulsante e si spegne se, viene rilasciato il pulsante o se è trascorso un tempo di 3 secondi. Se insieme al l’accensione del led voglio inserire il suono mi va ad eliminare il tempo dei 3 secondi e quindi neanche più il led si spegne ma entrambi terminano se viene rilasciato il pulsante. Avete qualche consiglio? Io ho provato di tutto
Se non metti il codice come facciamo a capire? ... inserisci il codice usando gli appositi TAG CODE.
Guglielmo
modifica post
In basso dove indico la modifica in cui il codice funziona ma non come dovrebbe.
Hai ragione, scusatemi.
Allora cosi se il pulsante rimane premuto, il brano continua fino al termine e il pwm rimane a 250 a prescindere dal rilascio o dalla pressione del pulsante. Il codice rimane bloccato anche al termine del brano lasciando il pwm a 250 e il led acceso. Se si preme e si rilascia velocemente il pulsante il pwm torna a 30 e il brano si interrompe all'istante.
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//Define Pin to use VS1053
#define CLK 13
#define MISO 12
#define MOSI 11
#define BREAKOUT_RESET 7
#define BREAKOUT_CS 10
#define BREAKOUT_DCS 8
#define CARDCS 4
#define DREQ 3
Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
unsigned long start_time = 0; // Memorize time of button are pressed
unsigned long disable_time = 0; // Memorize time to disable button activation
unsigned long wait_time = 5000; // Set duration of wait after duration as passed
unsigned long durate_time = 3000; // Set duration
int state; // Variable for verify function
int state_2; // 2nd Variable for verify function
int x;
int x_min = 30; // Set min value pwm
int x_max = 250; // Set max value pwm
//Input Pin
int button = 2;
//Output Pin
int pwm = 6;
byte led = A6;
void setup() {
Serial.begin (9600);
//Setting for VS1053
if (!musicPlayer.begin()) {
Serial.println("VS1053 Error");
while (1);
}
if (!SD.begin(CARDCS)) {
Serial.println("VS1053 SD Error");
while (1);
}
musicPlayer.setVolume(20,20);
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
//End setting to VS1053
pinMode (button, INPUT_PULLUP); // interrupt Pin with internal Pullup
pinMode (led, OUTPUT);
pinMode (pwm, OUTPUT);
delay(10);
}
void loop() {
if (digitalRead(button) == LOW && millis() > disable_time) {
// If the conditions to set the max PWM are met
if (start_time == 0) {
start_time = millis(); // Memorize the time when the button is pressed
state_2 = 0; // Set 2nd function to 0 (ON)
state = 'Y'; // Set state to 'Y' (ON)
}
if (millis() - start_time >= durate_time) {
// If the time since the button was pressed is greater than or equal to the duration
state_2 = 2; // Set 2nd function to 2 (OFF)
disable_time = millis() + wait_time; // Set the wait time for new activation
start_time = 0; // Reset the time of the button
}
} else {
state_2 = 2; // Set 2nd function to 2 (OFF)
start_time = 0; // Reset the time of the button
}
if (state_2 == 2) {
// If the 2nd function is 2 (OFF)
state = 'N'; // Set state to 'N' (OFF)
} else if (state_2 == 0) {
// If the 2nd function is 0 (ON)
state = 'Y'; // Set state to 'Y' (ON)
}
state_2 = (state_2 == 2 || disable_time > millis()) ? 2 : state_2;
// If the conditions to set the max PWM are not met
if (state == 'Y') {
// If the state is 'Y' (ON)
x = x_max;
analogWrite(pwm, x); // Set PWM to max value
digitalWrite(led, HIGH); // Turn ON the LED
musicPlayer.startPlayingFile("/track002.mp3");
} else if (state == 'N') {
// If the state is 'N' (OFF)
x = x_min;
analogWrite(pwm, x); // Set PWM to min value
digitalWrite(led, LOW); // Turn OFF the LED
musicPlayer.stopPlaying();
}
Serial.print("PWM: ");
Serial.println(x); // Send the PWM value to the serial monitor
delay(10);
}
Modificando alla fine, eliminando la partenza del brano se la condizione è Y (ON) e eliminando lo stop se la condizione è N (OFF), aggiungendo una condizione dove viene anche verificato se c'è qualcosa in esecuzione il codice funziona ma il tempo di durata non funziona. Quando termina il brano allora il pwm torna a 30, inizia il tempo di attesa e si puoi riattivare il tutto. Riparto da serial.print("PWM: ", il resto rimane invaiato:
Serial.print("PWM: ");
Serial.println(x); // Send the PWM value to the serial monitor
if (state == 'Y') {
if (musicPlayer.stopped()) {
musicPlayer.startPlayingFile("/track001.mp3");
}
} else if (state == 'N') {
if (!musicPlayer.stopped()) musicPlayer.stopPlaying();
}
delay(10);
}
Quali sarebbero queste condizioni?
Però cerca di esprimerle in modo non fraintendibile.
Ciao.
Hai ragione, infatti come consigliato da Guglielmo ho postato il codice. In tutti i modi il suono dovrebbe partire quando:
-Se premo il pulsante mantenendolo premuto (suono on)
-se il pulsante rimane premuto per più di 3 secondi (suono off)
-se rilascio il pulsante prima dei 3 secondi (suono off)
-se la pressione del pulsante raggiunge i 3 secondi, il suono rimane disabilitato per 5 secondi e poi è possibile riattivarlo come dall’inizio.
Complicatuccio mi sembra, anche il codice che hai messo in piedi non è facile da seguire.
Io ho modellato il comportamento secondo come lo capito io facendo uso della libreria JC_Button.
Però io non ho suono ma solo il led di stato L sul pin 13.
Raggiunti i 3 secondi di pressione del pulsante il led si spegne, da questo momento devono passare 5 secondi per riabilitare la lettura del pulsante play.
Prova questa libreria che già gestisce il debounce, fa sapere se risolvi.
Ti lascio due link che puntano a due articolo che descrivono una applicazione che impiega millis e una macchina a stati finiti basata sul comando switch case del C++.
Ciao.
Ciao Maurotec e mille grazie. Provo a installare la libreria e a trovare il modo per far fare al led ciò che dicevo e poi provo il modulo VS1053. Attualmente anche senza libreria ho provato con un led e il led fa ciò che voglio ma il suono come dicevo no. Ho visto però che il pwm non torna a metà a termine del brano ma semplicemente dopo un tempo "strano". Sembrerebbe che il modulo quando viene richiamato il brano modifichi in qulache modo il timer e i 3 secondi che avevo impostato magicamente diventano circa 12 che neanche a farlo apposta era proprio il tempo del brano. Mi sono reso conto che se voglio una durata di 3 secondi devo impostare 1000. Il modulo richiede un pin di interrupt e io ho collegato il 3 che dovrebbe essere anche un pin che gestisce il timer interno quindi proverò a collegare il pin 2.
Avevo dimenticato di dire che sto utilizzando un nano every ma ho già fatto il tentativo su nano standard e il risultato è uguale
Allora io ho letto il contenuto della funzione che usi per avviare la riproduzione, anzi la posto qui di seguito:
boolean Adafruit_VS1053_FilePlayer::startPlayingFile(const char *trackname) {
// reset playback
sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_LINE1 | VS1053_MODE_SM_SDINEW |
VS1053_MODE_SM_LAYER12);
// resync
sciWrite(VS1053_REG_WRAMADDR, 0x1e29);
sciWrite(VS1053_REG_WRAM, 0);
currentTrack = SD.open(trackname);
if (!currentTrack) {
return false;
}
// We know we have a valid file. Check if .mp3
// If so, check for ID3 tag and jump it if present.
if (isMP3File(trackname)) {
currentTrack.seek(mp3_ID3Jumper(currentTrack));
}
// don't let the IRQ get triggered by accident here
noInterrupts();
// As explained in datasheet, set twice 0 in REG_DECODETIME to set time back
// to 0
sciWrite(VS1053_REG_DECODETIME, 0x00);
sciWrite(VS1053_REG_DECODETIME, 0x00);
playingMusic = true;
// wait till its ready for data
while (!readyForData()) {
#if defined(ESP8266)
ESP.wdtFeed();
#endif
}
// fill it up!
while (playingMusic && readyForData()) {
feedBuffer();
}
// ok going forward, we can use the IRQ
interrupts();
return true;
}
Ora io penso che non gestisci lo stato di play, cioè se il riproduttore è il stato di play quella chiamata a funzione non la deve ripetere in loop. Una cosa del tipo:
If (playState == false) {
musicPlayer.startPlayingFile("/track001.mp3");
}
Vedo che lo hai fatto:
if (musicPlayer.stopped()) {
musicPlayer.startPlayingFile("/track001.mp3");
}
Mi dispiace ma non conosco il modulo come pure la libreria.
Comunque ottima idea di escludere il modulo VS1053 e simularlo con un serial print che dovrà comparire una sola volta dopo il play e una sola volta dopo lo stop.
Ciao.
Eccomi, allora ho fatto la prova con la libreria che mi hai indicato (davvero comoda) anche se credo di aver esagerato con le bool forse potevo usare meglio la libreria ma avevo fretta di provare. Il comportamento è uguale ovvero per avere i 3 secondi di durata di accensione devo impostare 1000 e non più 3000, che anche se mi può star bene mi da un pochino fastidio...
diversamente dal mio miscuglio per raggiungere il risultato, con la libreria basta un play e uno stop e il codice non va in blocco.
Ecco il codice che ho usato:
#include <JC_Button.h>
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//Define Pin to use VS1053
#define CLK 13
#define MISO 12
#define MOSI 11
#define BREAKOUT_RESET 7
#define BREAKOUT_CS 10
#define BREAKOUT_DCS 8
#define CARDCS 4
#define DREQ 3
Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
int x;
int x_min = 30; // Set min value pwm
int x_max = 250; // Set max value pwm
const int buttonPin = 2;
const int ledPin = A6;
const int pwm = 6;
Button myButton(buttonPin);
bool ledOn = false;
unsigned long buttonPressStartTime = 0;
unsigned long delayStartTime = 0;
const unsigned long delayDuration = 5000;
bool buttonEnabled = true;
void setup() {
Serial.begin (9600);
//Setting for VS1053
if (!musicPlayer.begin()) {
Serial.println("VS1053 Error");
while (1);
}
if (!SD.begin(CARDCS)) {
Serial.println("VS1053 SD Error");
while (1);
}
musicPlayer.setVolume(0,0);
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
//End setting to VS1053
pinMode (pwm, OUTPUT);
pinMode(ledPin, OUTPUT);
myButton.begin();
delay(10);
}
void loop() {
myButton.read();
if (myButton.wasPressed()) {
if (buttonEnabled) {
buttonPressStartTime = millis();
ledOn = true;
digitalWrite(ledPin, HIGH);
x = x_max;
analogWrite(pwm, x);
musicPlayer.startPlayingFile("/track002.mp3");
}
}
if (ledOn && (millis() - buttonPressStartTime >= 1000)) {
ledOn = false;
digitalWrite(ledPin, LOW);
delayStartTime = millis();
buttonEnabled = false;
x = x_min;
analogWrite(pwm, x);
musicPlayer.stopPlaying();
}
if (!buttonEnabled && (millis() - delayStartTime >= delayDuration)) {
buttonEnabled = true;
}
if (myButton.wasReleased()) {
ledOn = false;
digitalWrite(ledPin, LOW);
x = x_min;
analogWrite(pwm, x);
musicPlayer.stopPlaying();
}
Serial.print("PWM: ");
Serial.println(x);
delay(10);
}
Come hai fatto a leggere la funzione?
Hai aperto l'intera libreria adafruit VS1053 cercando la funzione?
No, ma tu hai la libreria in versione sorgente in locale, cioè sul tuo pc devi solo trovarla sotto le tante cartelle all'interno della cartella su cui è installato l'IDE e poi dipende pure quale versione di Arduino IDE.
Io ho cercato con google il file header di inclusione che usi all'inizio e qui c'è il link al repositor ufficiale di adafruit (i frutti di lady Ada).
Ciao.
Sarebbe il file con estensione .cpp che trovo nelle librerie installate?
Si esatto, almeno dovrebbe essere lo stesso identico file che hai in locale.
Allora ti posto il codice che ovviamente è solo un esempio e non è detto che faccia quello che desideri.
Se dovesse fare proprio quello che desideri, ci si devi lavorare su per renderlo più comprensibile e modulare, comunque un passo per volta.
byte playState = 0;
uint32_t saveMillis;
uint16_t interval;
void loop() {
playBtn.read();
if ((playState == 0) && playBtn.wasPressed()) {
playState = 1;
interval = 3000;
saveMillis = millis();
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("play track002.mp3");
}
if (playState == 1) {
if (playBtn.isReleased()) {
digitalWrite(LED_BUILTIN, LOW);
Serial.println("Stop track002.mp3");
playState = 0;
} else {
if (millis() - saveMillis >= interval) {
digitalWrite(LED_BUILTIN, LOW);
interval = 5000;
saveMillis = millis();
playState = 2;
Serial.println("Stop track002.mp3");
}
}
}
if (playState == 2) {
if (millis() - saveMillis >= interval) {
playState = 0;
}
}
}
Il setup c'è lo metti tu, perché ho scritto il codice all'interno di uno sketch su cui stavo lavorando.
Ciao.
Mi da questo avviso che sicuramente è per via del nano every:
ATTENZIONE: la libreria JC_Button dichiara di funzionare sulle architetture avr e potrebbe non essere compatibile con la tua scheda che utilizza l'architettura megaavr.
Ho provato a caricare questo sketch e all'accensione si accende il led lampeggiando 2 volte e poi non risponde al pulsante. Sullo sketch ho modificato solo il led in quanto il pin 13 veniva utilizzato già dal modulo breakout, ecco lo sketch caricato:
#include <JC_Button.h>
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//Define Pin to use VS1053
#define CLK 13
#define MISO 12
#define MOSI 11
#define BREAKOUT_RESET 7
#define BREAKOUT_CS 10
#define BREAKOUT_DCS 8
#define CARDCS 4
#define DREQ 3
Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
int x;
int x_min = 30; // Set min value pwm
int x_max = 250; // Set max value pwm
Button playBtn(2);
const int led = A6;
const int pwm = 6;
byte playState = 0;
uint32_t saveMillis;
uint16_t interval;
void setup() {
Serial.begin(9600);
//Setting for VS1053
if (!musicPlayer.begin()) {
Serial.println("VS1053 Error");
while (1);
}
if (!SD.begin(CARDCS)) {
Serial.println("VS1053 SD Error");
while (1);
}
musicPlayer.setVolume(0, 0);
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
//End setting to VS1053
pinMode(pwm, OUTPUT);
pinMode(led, OUTPUT);
delay(10);
}
void loop() {
playBtn.read();
if ((playState == 0) && playBtn.wasPressed()) {
playState = 1;
interval = 3000;
saveMillis = millis();
digitalWrite(led, HIGH);
Serial.println("play track002.mp3");
}
if (playState == 1) {
if (playBtn.isReleased()) {
digitalWrite(led, LOW);
Serial.println("Stop track002.mp3");
playState = 0;
} else {
if (millis() - saveMillis >= interval) {
digitalWrite(led, LOW);
interval = 5000;
saveMillis = millis();
playState = 2;
Serial.println("Stop track002.mp3");
}
}
}
if (playState == 2) {
if (millis() - saveMillis >= interval) {
playState = 0;
}
}
}
Lo dimentico pure io il begin nel setup.
playBtn.begin();
Aggiungilo e fa sapere se si comporta come desideri.
Ciao.
Pensa che l'avevo anche inserito e poi l'ho tolto per sbaglio
...Allora, il comportamento è quello desiderato, ma quando aggiungo il Play il tempo torna ad allungarsi e quindi i 3 secondi diventano circa 9.. i 5 di attesa rimangono invariati
Allura, allura. Sparo un poco di info che spero possano essere utili a chi ha il tempo per indagare.
Ci sono due modalità d'uso del player VS1053 breakout.
Una è "bloccante" e l'altra dovrebbe esserlo un po meno.
In modo bloccante arduino legge da sdcard un tot di byte che invia via SPI al player (mi pare di avere capito cosi).
L'altra modalità "poco bloccante" invece arduino legge da sdcard invia tot byte al player via SPI ed è libero di fare altro fino al momento in cui il player solleva il pin di interrupt che sta ad indicare che gli servono dati per continuare il player. Arduino risponde alla richiesta di interruzione sollevata dal player e invia altri dati così il player continua la riproduzione.
Sembra proprio che nel tuo caso o la modalità "poco bloccante" non funziona (e non so se dipende dallo sketch). Oppure il poco bloccante impedisce l'esecuzione di interrupt del timer che conta i millesimi di secondo, cioè millis() non conta.
Tra gli esempi mi pare di capire che il modo "poco bloccante" sia il file
File che però nel poco tempo che ho dedicato non ho compreso.
Ciao.
Si, leggendo avevo visto che ci sono due modi (non so se ce ne sono altri) per richiamare il file audio:
musicPlayer.playFullFile(file audio)
//bloccante
musicPlayer.startPlayingFile(file audio)
//non bloccante
Le ho provate entrambe e la prima blocca completamente il codice fino al termine dell’audio. Ho provato anche a copiare completamente il codice da Paolo Aliverti su YouTube ma anche lì vedo che il tempo fa nello stesso modo…
Posta l'ultimo sketch.
Non ho visto il video, troppo lunghi per me i video.
Con la nano Every la mcu è un arm per cui dovrebbe essere molto più veloce sia SPI che la lettura del buffer dalla ram. In su arm c'è un timer dedicato all'orologio di sistema e teoricamente lavora anche spegnendo gli interrupt (o almeno dovrebbe).
EDIT: Errore mi sono confuso la nano every monta una MCU ATmega4809.
Stampa millis() prima e dopo questa chiamata:
musicPlayer.startPlayingFile(file audio)
Ciao.