WTV020-SD-16P per la domotica

Il modulo WTV020-SD-16P per suonare con Arduino dei file in ordine di arrivo (buffer).

La particolarità di questo scketch  è la sua caratteristica di essere facilmente integrabile in altri progetti e di accettare più numeri file da suonare anche se questi arrivano mentre la scheda WTV020-SD-16P ne sta suonando uno. Funziona grazie ad un buffer in cui memorizza i file che poi invia uno dopo l’altrro al modulo per suonarli senza interruzioni. Ovvero ne invia uno, aspetta che venga finito di suonare prima di inviare il secondo del vettore e così via.

Il listato è in coda ed è un insieme di routine pensate per essere inserite all’interno di un altro programma.

Con la routine Wtv_Playsong(x) viene inserito il numero file e da suonare nel buffer. Può essere lanciata più volte anche se il modulo wtv020-sd-16p non ha finito di suonare il file precedente.

Il buffer memorizza fino a 12 numeri. Comunque modificabile a piacere modificando la variabile  Wtv_ElementiVettore ed inizializzando a zero tutti gli elementi  del vettore.

Il programma elimina dal buffer le ripetizioni di numeri. Se gli vengono passati uno dopo l’altro i numeri file seguenti 2,2,2,3,3,2,2,3 il programma suonerà 2,3,2,3 poiché in automatico elimina tutti i valori uguali vicini.

Se il buffer è pieno tutti i numeri file successivi rimpiazzano solo l’ultimo elemento del buffer.

Inoltre il programma gestisce la ripetizione automatica di un file audio. Se si invia il comando per suonare il file numero 99, questo viene suonato e contemporaneamente reimmesso in coda al buffer. Una funzionalità utile per ripetere i due toni di una sirena continuamente e comunque suonare anche altri file che nel frattempo sono arrivati nel buffer.

Tale funzione di ripetizione viene fermata solo dall’arrivo del numero file 98. Quando arriva il valore viene inserito immediatamente come primo elemento del buffer per essere suonato subito e contemporaneamente tutte le ricorrenze di 99 eventualmente presentinel buffer vengono eliminate. Funzionalità utile per far suonare un file audio che dica ad esempio “Allarme disattivato” e faccia cessare di suonare il file audio della sirena.

Come accennavo queste sono delle routine da aggiungere al vostro programma. Routine che vengono richiamate da Wtv_PlaySong(x).

Il listato seguente permette di testare il funzionamento del modulo (wtv020-sd-16p e simili) . Il contenuto del loop() genera a tempo dei richiami alla funzione per suonare alcuni file. Per l’utilizzo ricordate di inserire nella memoria SD file audio con quella numerazione (Es: per Wtv_PlaySong(2) deve esserci un file nominato 00002.ADF per Wtv_PlaySong(32) un file nominato 00032.ADF e così via.) Lo schema elettrico dei collegamenti è il seguente:

Arduino con il modulo wtv020-sd-16p

Schema Elettrico collegamenti Arduino al modulo wtv020-sd-16p

Alcuni file audio in italiano per testare lo schetch, qui di seguito:

Nome file


Voce che dice…


File: 0001.ad4 Luce sala 2
File: 0002.ad4 Applique sala 1
File: 0003.ad4 Applique sala 2
File: 0098.ad4 Allarme disattivato
File: 0099.ad4


Sirena


Per inserire in altri programmi lo sketch,  dovete copiare le dichiarative, tutte le routine in coda al vostro programma ed inserire nel loop() l’if che contiene il richiamo alla routine Wtv_SendToWtv020sd16(). Tale routine è quella che invia il primo elemento del buffer al modulo WTD20SD e poi aspetta che sia finito di essere suonato prima di ricominciare ad inviargli in nuovo file.

La routine Wtv020sd16 è richiamata più volte al secondo in modo che le sue funzioni vengono eseguite in parallelo al programma che lo ospita.

Lo schema

Listato:

// Questo progaramma è inteso per essere inserito in un programma più complesso.
// Le sue funzioni permettono di suonare diversi file con la schedina WTV020SD16p.
// I file da suonare possono arrivare insieme o in modo casuale ed inseriti in un vettore. Poi verranno suonati, per intero, uno dietro l’altro.
// Collegare i pin così:
// Wtv20sd16p Pin <-> Arduino Pin
//              1 <-> 2
//              7 <-> 3
//              8 <-> to GND
//             10 <-> 4
//             15 <-> 5
//             16 <-> to 3,3V
//
// Collegare una resistenza da 1K in serie ad un led tra i pin 16 e 15 della scheda Wtv20sd16p. Il positivo del led verso il 16

#include <Wtv020sd16p.h>

int resetPin = 2; // The pin number of the reset pin.
int clockPin = 3; // The pin number of the clock pin.
int dataPin = 4; // The pin number of the data pin.
int busyPin = 5; // The pin number of the busy pin.

Wtv020sd16p wtv020sd16p(resetPin,clockPin,dataPin,busyPin);

double old_millis;
double old_millis2;
double old_millis3;

int Wtv_ElementiVettore=11;
int Wtv_VettArrivo[12] = {0,0,0,0,0,0,0,0,0,0,0}; //il vettore va da 0 a 11

void setup() {
//Initializes the module.
Serial.begin(115200); // set up Serial library at 115200 bps
wtv020sd16p.reset();
old_millis=0;

old_millis2=0;
old_millis3=0;
}

void loop() {

//ciclo da eliminare, utile per testarlo, dopo 90 secondi suona il file 98
if (millis()-old_millis3 >= 100000 )
{
Serial.println(“———————–  metto il 98 ————-“);
Wtv_PlaySong(98);
old_millis3 = millis();
}

//ciclo da eliminare, utile per testarlo, dopo 50 secondi suona un pò di file
if (millis()-old_millis2 >= 60000 )
{
Serial.println(“———————–  metto un po di play ————-“);
Wtv_PlaySong(1);
Wtv_PlaySong(99);
Wtv_PlaySong(2);
Wtv_PlaySong(32);
Wtv_PlaySong(2);
Wtv_PlaySong(2);
Wtv_PlaySong(2);
Wtv_PlaySong(2);

Wtv_PlaySong(3);
old_millis2 = millis();
}

//L’if seguente è quello da mettere nel loop del programma principale
//Poi da qualsiasi punto del programma si può mettere l’istruzione Wtv_PlaySong(3) per fargli suonare, in questo caso, il file 0003.ad4;
if (millis()-old_millis >= 50 )
{
Wtv_SendToWtv020sd16();
old_millis = millis();
}
}

void Wtv_PlaySong(int numerofile)
{
//metti il valore in numero file in coda al vettore.
//Però se è 98 allora cancella tutti i 99 presenti nel vettore e metti il 98 per primo in modo da suonarlo subito.
//Se invece il valore in numerofile è uguale all’ultimo elemento precedentmente inserito allora non fa nulla.

int Wtv_appo = 0;
int Wtv_esci=0  ;
//il primo valore è vuoto allora mettilo direttamente
if (Wtv_VettArrivo[0] == 0)
{
Wtv_VettArrivo[0] = numerofile;  //è il 98
Wtv_esci=1;

}

if (numerofile!=98 && Wtv_esci==0)
{
Wtv_appo = 0;
Wtv_appo = Wtv_posizione();
if  (Wtv_appo >=1 && Wtv_VettArrivo[Wtv_appo-1]==numerofile )
{
//in pratica se il valore è uguale a quello precedente allora non lo metti nel buffer
}
else
{
Wtv_VettArrivo[Wtv_appo] = numerofile;
}
}

//Se 98 elimina tutti i 99 e mettilo nel buffer
if (numerofile==98)
{
Wtv_appo = 0;
Wtv_appo = Wtv_posizione();   //trova il primo valore a zero, così non faccio il for per tutti gli elementi
int Wtv_i = 0;
//elimina tutti i 99 e 98 nel vettore
while (Wtv_i <= Wtv_appo )
{
if (Wtv_VettArrivo[Wtv_i] == 99 || Wtv_VettArrivo[Wtv_i] == 98 )
{
Wtv_shiftvettore (Wtv_i);
}
else
{
Wtv_i=Wtv_i+1;
}
}

//sposta tutto il vettore in basso per poter mettere in prima posizione il 98
for (int Wtv_i = Wtv_appo ; Wtv_i>=1 ; Wtv_i–)
{
Wtv_VettArrivo[Wtv_i] = Wtv_VettArrivo[Wtv_i-1];
}

Wtv_VettArrivo[0] = numerofile;  //è il 98
}
}

void Visualizza()
{
//Per visualizzare gli elementi del vettore
int i=0;
for (i=0; i<=Wtv_ElementiVettore; i++)
{
Serial.print( i ) ;
Serial.print( ” -> ” ) ;
Serial.println(  Wtv_VettArrivo[i]) ;
}
Serial.println(“”) ;
}

void Wtv_SendToWtv020sd16()
{
int Wtv_appo =0;
if (digitalRead(busyPin) == 0 )    //solo se la scheda non sta suonando faccio quanto segue
{

//Se è 99 allora riproponilo in coda sempre
if (Wtv_VettArrivo[0] == 99)
{
Wtv_appo = Wtv_posizione();
if (Wtv_appo == 1 || Wtv_VettArrivo[Wtv_appo – 1] != 99)
{ //se l’ultimo valore è già 99 allora non farlo
Wtv_VettArrivo[Wtv_appo] = 99;
}
}

if (Wtv_VettArrivo[0]!=0)   //se non è zero suonalo
{
wtv020sd16p.playVoice(Wtv_VettArrivo[0]);  //suonalo
Wtv_shiftvettore(0);                       //shift-a il vettore cosi che la prima posizione viene sostituita dalla seconda e così via…
Visualizza();
}
}

}

void Wtv_shiftvettore(int start)
{
//sposta tutti gli elementi. Da START+1 vengono portati di una posizione indietro.
int Wtv_esci = 0;
int Wtv_i=0;
Wtv_i = start;
while (Wtv_i <= Wtv_ElementiVettore – 1 && Wtv_esci == 0)
{
Wtv_VettArrivo[Wtv_i] = Wtv_VettArrivo[Wtv_i + 1];
if (Wtv_VettArrivo[Wtv_i] == 0 && Wtv_VettArrivo[Wtv_i + 1] == 0)
{Wtv_esci = 1;}
Wtv_i = Wtv_i + 1;
}
Wtv_VettArrivo[Wtv_ElementiVettore] = 0;

}

int Wtv_posizione()
{
//Questa funzione restituice il numero del primo elemento libero del vettore al fine di poterlo utilizzarlo.
//La ricerca avviene tramite metodo dicotomico per ridurre il numero di cofronti necessari
if (Wtv_VettArrivo[0] == 0 )
{
return 0  ;
}
else
{
int Wtv_inizio = 0;
int Wtv_mezzo = 0;
int Wtv_fine = 0;
Wtv_fine = Wtv_ElementiVettore;
while (Wtv_fine – Wtv_inizio > 1)
{
Wtv_mezzo = int((Wtv_inizio + Wtv_fine) / 2);
if (Wtv_VettArrivo[Wtv_mezzo] == 0 )
{
Wtv_fine = Wtv_mezzo;
}
else
{
Wtv_inizio = Wtv_mezzo;
}
}
return Wtv_fine;  //restituisci valore
}
}

 

Aggiornamento 15/01/2017:
La scheda SD dopo anni di funzionamento si è rovinata e con le nuove SD da 1B che da 2GB (stessa marca SANDISK) il modulo wtv020-sd-16p non voleva funzionare. Infine, dopo molteplici prove, solo le schede SD da 1GB  hanno ripreso a funzionare grazie alla formatazione effettuata con SDFORMATTER.