Scatola Musicale

Questo progetto nasce come regalo di natale per un mio amico che tanto desiderava poter aggiungere un tocco di comicità in ogni situazione mediante alcuni tipici suoni comici riprodotti al momento giusto.

Si tratta quindi di una scatolina portatile che deve poter stare comodamente in una tasca e che deve permettere la riproduzione veloce non appena l’utente preme un tasto associato al particolare suono adatto alla situazione.

Per questo progetto ho avuto bisogno di:

  • Una scatola piccola: sembra ovvio ma il fatto di dover restare entro piccoli spazi ha condizionato alcune mie scelte progettuali, come spiegherò.
  • Un modulo audio che sia programmabile da pc: ho trovato praticamente perfetto il modulo venduto su lpelettronica, il modulo lpm11162: programmabile e controllabile mediante pulsanti o microcontrollore
  • Un microcontrollore, piccolo, che leggesse la tastiera (3x4) e controllasse il modulo mediante protocollo seriale
  • Un amplificatore integrato: ho optato per il tba820m, in grado di erogare 1.2W a 9V (più che sufficienti per questo scopo) e molto configurabile attraverso componenti esterni.
  • Ovviamente uno stadio di alimentazione che fornisse i 3,3 volt tipici richiesti dal modulo audio. Ho scelto di regolare la tensione con un lm317 perchè è in grado di fornire tutta la corrente necessaria, e il non basso dropout non è un problema perchè il tutto sarà alimentato da una pila da 9V.

Diamo uno sguardo più da vicino a quello che è forse il componente più importante nonchè misterioso: il modulo audio.

Non mi dilungherò su ogni singolo passo necessario per utilizzare uno di questi moduli: per chi fosse interessato, il sito che lo vende offre una serie di articoli tecnici molto esaustivi che ho trovato ottimi per conoscere il modulo in ogni sua parte a cui vi rimando per i dettagli: articoli tecnici.

Si tratta di un modulo che memorizza i file audio dal pc (formato .wav, 16 bit 11025 kHz, mono) e, una volta programmato (è riprogrammabile) può essere controllato in due modi: in modalità key-mode attraverso l’utilizzo di pulsanti, o in modalità seriale: utilizzeremo quest’ultima perchè permette di riprodurre tutti i suoni che desideriamo, permette di regolare il volume, di fermare i suoni, insomma è la modalità più versatile. Necessita solo di qualcosa che la comandi in seriale, per questo utilizzeremo un microcontrollore, il pic16f628a.

All’avvio, il modulo audio necessita di “sapere” che vogliamo utilizzare la modalità seriale: per dirglielo, gli inviamo il cosiddetto “carattere di auto-baudrate”, cioè il carattere 0x55, o ‘U’ che dir si voglia: in questo modo il modulo capirà che lo vogliamo comandare in seriale, e aggiusterà automaticamente il suo baud-rate per adattarsi a quello impostato nel microcontrollore. A questo punto il modulo è già pronto per ricevere comandi.

I pin del modulo che vanno connessi al microcontrollore sono 3: il pin RESET ci permette di dare un reset iniziale al modulo, non ho scelto di pullupparlo per avere un migliore controllo dal pic; il pin BUSY ci informa, stando a livello logico basso, che il modulo è impegnato nell’esecuzione di un comando e non può accettarne altri; infine i due pin TX e RX, i pin per la comunicazione seriale. Il pin TX lo lasciamo scollegato, perchè non serve: viene utilizzato unicamente dal modulo, dopo l’invio del carattere di auto-baudrate, per comunicare il suo numero di serie e la versione del suo firmware. A noi non interessano queste informazioni, ci limiteremo a capire, attraverso il pin BUSY, quando il modulo ha finito di inviare queste informazioni ed è pronto a ricevere comandi.

La sequenza di inizializzazione, che deve seguire alcune tempistiche specifiche (le vedrete in seguito nel commento del codice sorgente) è riassunta in questo grafico preso dal datasheet:

I comandi vengono inviati attraverso più byte: il primo byte indica che comando vogliamo inviare; i due byte successivi informano il modulo sul numero di byte che dovrà ricevere come argomento del comando.

Queste tabelle, qui riportate dal datasheet, fanno chiarezza su questo sistema di invio dei comandi

Una volta inviato un comando, il modulo porta il suo pin BUSY a livello logico basso, e lo rialza quando ha finito ed è pronto a ricevere nuovi comandi. Il microcontrollore quindi dopo ogni comando aspetta che il modulo audio riporti questo pin a livello logico alto per riprendere a lavorare.

Un cenno alla programmazione del modulo audio: è possibile prevedere la programmazione in-circuit del modulo, ma per ragioni di spazio non la ho inserita in questo progetto. Per questo vi rimando all’articolo tecnico numero 3.

Ecco invece come programmare il modulo audio su un programmatore fatto appositamente (anche per questo è previsto un esauriente articolo tecnico): è sufficiente alimentarlo a 3,3V e connetterlo alla porta seriale di un computer. Ovviamente serve un adattatore di livelli logici (dai +/- 12V della seriale pc ai 0-3,3V del modulo): il comunemente usato max232 NON va bene perchè non lavora a questa tensione troppo bassa. Occorre quindi un convertitore che lavori a tensioni più basse, come il MAX3222, oppure un modulo convertitore come il modulo LPM232, soluzione per cui ho optato perchè molto versatile.

Interponendo la necessaria conversione di livelli, bisogna collegare i pin della seriale a quelli del modulo come illustrato in questo schema:



(clicca sull'immagine per vederla più grande)

Il pin RX della seriale al pin TX del modulo, il pin TX della seriale al pin RX del modulo, il pin RTS al RESET e il CTS al BUSY.

A questo punto si avvia dal pc il programma apposito, disponibile sempre sul sito, che dovrebbe (una volta aperta la porta seriale appropriata) riconoscere il modulo e mostrarvi, nella parte bassa della finestra, la sua ID e la sua versione del firmware. Questo programma è molto intuitivo e semplice da usare, permette anche di provare i file appena programmati (se il modulo è connesso a un amplificatore) previa preparazione del file nel modo appropriato: il modulo può infatti memorizzare solo file in formato WAV 16bit monocanale, frequenza di campionamento 11025 Hz. La conversione dei file in questo formato può essere effettuata direttamente dal programma, opzione molto utile, oppure da un programma di editing audio esterno (personalmente consiglio Audacity). Anche per la preparazione dei file audio e la loro programmazione vi rimando ai rispettivi articoli tecnici (7 e 8).


Ora che abbiamo programmato il modulo con i nostri file audio preferiti, vediamo cosa mettergli intorno:

Punto primo, l’alimentazione: il modulo deve lavorare con tensioni da 2,7 a 3,6V, tipicamente a 3,3V: ho scelto quindi di alimentare il complesso con una pila da 9V e un regolatore LM317, che dia in uscita 3,4V stabilizzati. Alla stessa tensione sarà alimentato il microcontrollore, che lavora da 2 a 5,5V, mentre l’amplificatore viene alimentato direttamente dalla pila: ciò permette di riprodurre i suoni ad un volume molto maggiore di quello che otterremmo alimentando a 3,4 V anche lui.

Prepariamo quindi un lm317 per ottenere in uscita tale tensione: io ho trovato davvero utile questa pagina che spiega molto bene come fare: lm317 (un ringraziamento ad Adriano Gandolfo per avermi permesso di appoggiarmi a questa sua pagina).

Utilizziamo il circuito mostrato in tale pagina in figura 2, dimensionando i componenti secondo la formula

R2 = [(Volt uscita : 1,25) - 1] x R1

Otteniamo che, scegliendo per R1 un valore arbitrario (io ho scelto 330 Ohm), R2 dovrà essere

R2=[(3,4/1,25)-1]x330=(2,72-1)x330=1,72x330=567 Ohm.

Prenderemo una resistenza del valore commerciale di 560 Ohm.


Punto secondo: il microcontrollore.

Il microcontrollore deve occuparsi di leggere la tastiera e comandare il modulo. Siccome la tastiera ha 3 colonne e 4 righe, serviranno 7 pin di I/O per leggerla, e serviranno altri 3 pin per controllare il modulo audio (TX,RESET e BUSY). Il minimo numero di pin che ci servono è quindi 10, ragion per cui non possiamo utilizzare un pic a 8 pin (sempre stando nell’ottica dell’occupare meno spazio possibile) ma un pic a 18 pin va benissimo: ho scelto quindi il PIC16F628A, assegnando a ciascun pin il suo compito in questo modo:

PORTA:

Pin 6,7: Quarzo;
Pin 2,3,4: Uscite colonne tastiera;
Pin 1: Led per segnalazioni luminose;
Pin 0,5: Non usati

PORTB:

Pin 4,5,6,7: Ingresso riga tastiera;
Pin 3: RESET modulo audio;
Pin 2: Tx seriale;
Pin 1: Rx seriale;
Pin 0: BUSY Modulo audio

I pin 6 e 7 di portA sono obbligatoriamente impegnati per il quarzo, necessario in quanto per utilizzare la comunicazione seriale serve un clock preciso: ho provato ad utilizzare l’oscillatore interno, ed il tutto ha smesso di funzionare.

La tastiera verrà letta attraverso i pin 2,3 e 4 di portA per le colonne (il pin 4 necessita di una resistenza di pull-up sull’uscita perchè è open-drain: significa che può soltanto, se utilizzato come uscita, chiudere a massa o non chiudere) e i pin 4,5,6,7 (con rispettivi pull-down) di portB per le righe. Non mi è stato possibile utilizzare i pull-up interni di portB perchè il 16f628a non dà la possibilità di attivarli soltanto sui pin desiderati, ma soltanto di attivarli o non attivarli su tutta portB, e attivandoli avevo problemi con la comunicazione seriale.

Sul pin 1 di portA è collegato un led per segnalazioni utili soprattutto in fase di debug.

Infine, i pin 0,1,2,3 di portB si occupano del controllo del modulo audio: i pin 1 e 2 costituiscono l’interfaccia seriale mentre i pin 0 e 3 si occupano di leggere il pin BUSY e impostare il RESET del modulo audio.

Il pin 0 di portB ha una resistenza di pull-down: la ho inserita sebbene non fosse indicata nel datasheet del modulo, perchè senza il circuito non funzionava. La prima volta che ho provato questo modulo, infatti, non riuscivo a farlo andare, e si è messo a funzionare quando lo ho avviato tenendo il puntale del tester sul pin BUSY per vedere se c’erano problemi. Da lì ho capito che una resistenza di pull-down era necessaria, senza tuttavia sapere esattamente perchè. Probabilmente il microcontrollore deve, durante la fase di avvio, considerare il modulo come "occupato" finchè quest’ultimo non si è completamente avviato e ha impostato il pin BUSY secondo la sua volontà.

Ecco lo schema che riassume queste impostazioni:


L’ultimo elemento necessario nel circuito è l’amplificatore, perchè l’uscita del modulo audio non è ovviamente in grado di pilotare direttamente uno speaker.

Ho scelto di utilizzare un amplificatore integrato TBA820M perchè molto configurabile grazie ai componenti esterni e anche discretamente potente: a 9V con un carico di 8Ohm, raggiunge una potenza di 1,2W. Inoltre la sua corrente a riposo è appena 4mA, e dato che questo dispositivo sarà alimentato da una batteria, ci interessa che questo valore sia il più piccolo possibile.

Lo schema da seguire è indicato direttamente nel suo datasheet: si tratta dello schema con carico connesso a massa, che riporto qui:

I due valori dei componenti che non sono specificati (Rf e Cb) dobbiamo deciderli in base a cosa vogliamo ottenere dall’amplificatore: Rf è la resistenza che regola il guadagno in tensione. Provando il circuito con un trimmer ho trovato che un valore di 100 Ohm è un buon compromesso tra una buona amplificazione e una bassa distorsione. Abbassando questa resistenza si ottiene una maggiore amplificazione ma anche una maggiore distorsione.

Il condensatore Cb è quello che determina la banda passante. Lavorando in campo audio, la banda che ci serve è intorno ai 20 kHz, il modulo che utilizziamo ha una banda di 5 kHz. In rete ho trovato indicazioni per un valore di 220pF con banda passante di 25 kHz, io ho usato un condensatore da 390pF perchè era il valore più vicino che avessi disponibile, e la qualità del suono è comunque molto buona.

Ho utilizzato uno speaker preso da una vecchio telefono perchè aveva un buon suono ma soprattutto le giuste dimensioni.


Mettendo insieme tutti questi elementi giungiamo finalmente allo schema complessivo che è il seguente:



(clicca sull'immagine per vederla più grande)

Il condensatore C8 in uscita dal modulo audio è necessario per disaccoppiare il segnale in uscita.

Dallo schema si può notare che il modulo audio dispone di 4 pin per l’alimentazione: DVCC, AVCC, DGND, AGND. E’ sufficiente collegare DVCC e AVCC insieme a Vcc e gli altri due insieme a massa. Ricordarsi di inserire, in parallelo all’alimentazione, i condensatori per evitare problemi riguardo a sbalzi/oscillazioni dell’alimentazione (C4 e C6 nel disegno), sia per il modulo audio che per l’amplificatore finale e per il microcontrollore.

Nello schema ho utilizzato una tastiera 4x4 semplicemente perchè non avevo il modello della tastiera 4x3; infatti una colonna è stata lasciata non collegata (un piccolo appunto: il simbolo della tastiera non lo ho fatto io, si tratta di una libreria che avevo trovato in rete ma non so più dove, quindi non posso citarne l’autore).


Passiamo ora al programma da inserire nel microcontrollore: non descriverò i singoli step ora (se necessario vi saranno i commenti nel sorgente) ma dirò a grandi linee in che modo procede:

Innanzitutto il software è stato scritto in C nell’ambiente mikroCversione 8.2.0.0; La configuration word è 0x2109, impostata attraverso la voce di menù "Project –> Edit Project" Con le impostazioni che vedete nella figura:

Ovviamente va selezionato il microcontrollore 16F628A e la frequenza di clock appropriata (nel mio caso era 4 MHz, ma ciò è irrilevante poichè il compilatore eseguirà automaticamente gli eventuali calcoli necessari variando la frequenza di clock).

Il funzionamento del software è il seguente: innanzitutto si procede all’inizializzazione del modulo audio secondo le tempistiche specificate nel datasheet; poi si recupera dalla eeprom il volume da impostare (il modulo audio permette di impostare il volume attraverso un apposito comando) in modo da non doverlo impostare tutte le volte al livello desiderato. Il volume si cambia premendo due tasti appositi, ma vedremo dopo.

Dopo aver inizializzato il tutto parte il ciclo principale del programma: si legge ciclicamente la tastiera attivando una colonna alla volta e leggendo gli ingressi; per ogni tasto premuto, alla variabile "code" viene aggiunto un numero pari al doppio del numero del tasto precedente: il tasto 1 aggiunge 1 alla variabile se premuto, il tasto 2 aggiunge 2, il tasto 3 aggiunge 4, il tasto 4 aggiunge 8 ecc.

Una volta letta la tastiera, se la variabile “code” è diversa da zero significa che un tasto (o più) è stato premuto; si va quindi a controllare se è stato premuto uno dei due tasti per alzare o abbassare il volume e si agisce di conseguenza. Il volume modificato viene salvato nella eeprom.

Una volta controllato se bisogna modificare il volume, si chiama la procedura "uart_send_play" che prende come argomento la variabile “code” e ordina al modulo di riprodurre un suono; essa funziona in questo modo:

  • si converte la variabile passata come argomento in stringa attraverso la funzione IntToStr, già definita nell’ambiente mikroC che segue una particolare formattazione: restituisce una stringa di 6 numeri allineati a destra, i restanti caratteri a sinistra vengono riempiti con degli spazi.
  • si imposta il volume al livello desiderato dall’utente attraverso la procedura set_volume
  • si invia al modulo la sequenza per il comando Play: 0x10 per dire che il comando è play, 0x00 e 0x0A per dirgli che dovrà ricevere 10 byte per il nome del file: sono 10 perchè chiameremo i file da programmare sul modulo audio in un modo particolare: ad esempio il suono associato al pulsante 4, quindi codice 8 (vedi codice sorgente), è chiamato “000008.wav”; il suono associato al codice 256 sarà chiamato “000256.wav”; in questo modo la lunghezza del nome del file è sempre la stessa e il software si semplifica notevolmente
  • ora si invia al modulo il nome del file in questo modo: con un ciclo consideriamo singolarmente ogni carattere della stringa convertita dalla funzione IntToStr: se è uno spazio, si invia al modulo il carattere ‘0’, altrimenti si invia al modulo il carattere così com’è. Poi si invia al modulo la sequenza di caratteri per completare l’estensione, ossia ‘.’ ‘w’ ‘a’ ‘v’.
  • ora il modulo inizia la riproduzione del file audio, con un while aspettiamo che il pin BUSY torni alto ad indicare che ha finito, ma mentre aspettiamo ciò, controlliamo se l’utente preme il pulsante di stop, attivando la colonna e leggendo la riga corrispondenti al tasto STOP. Se il tasto è premuto, inviamo il comando di STOP.

La funzione uart_send_play è piuttosto intricata, ma non è per masochismo: chiamando i file da programmare sul modulo nel modo giusto e seguendo questa procedura per l’invio del comando, si permette di snellire notevolmente il codice: la funzione così ha solo bisogno di un numero che provvederà a trasformare nel giusto comando da inviare al modulo. Definire manualmente tutti i nomi dei file, ad esempio “ciao.wav” o “suono.wav” avrebbe comportato un aumento di memoria occupata non indifferente per un microcontrollore che di certo non abbonda e un appesantimento del codice.


Ecco il sorgente:codice sorgente

E l'hex già compilato:hex compilato

 


Vi chiederete perchè non ho assegnato semplicemente i numeri in modo crescente per ogni tasto: perchè nel caso si desiderino inserire dei suoni riproducibili con una combinazione di tasti, in questo modo si può fare; ad esempio, se desideriamo che si attivi un particolare suono alla pressione dei tasti 2 e 5, basta programmare sul modulo un suono chiamato “000018.wav” (2 + 16).

Non avrei potuto fare la stessa cosa se avessi assegnato semplicemente numeri crescenti, perchè la pressione del tasto 2 e del tasto 5 avrebbe dato come risultato il codice 7, numero che sarebbe stato già impegnato per il pulsante numero 7.

Se si desidera questa funzionalità bisogna però apportare una piccola modifica al codice aggiungendo, subito dopo il while (1) che determina l’inizio del ciclo iniziale, la seguente porzione di codice:

asm {
    controllo:
    movlw 0x1C
    iorwf porta,f
    movlw 0xF0
    andwf portb,w
    btfss status,z
    goto controllo
    movlw 0xE3
    andwf porta,f
}
Delay_ms(200);

per un semplice motivo: facciamo finta che l’utente voglia associare un suono ai tasti 2 e 5, come dicevamo prima: se questo pezzo di codice non ci fosse, l’utente premerebbe uno dei due tasti prima (perchè nessun essere umano riesce a premere due tasti insieme con precisione al microsecondo) e di conseguenza il microcontrollore riprodurrebbe subito il suono associato al tasto premuto prima.

Inserendo questo pezzo di codice, il microcontrollore attiva tutte le colonne e legge tutti gli ingressi, in modo da accorgersi se un qualsiasi pulsante è premuto. Quando si accorge che un qualsiasi pulsante è stato premuto, esce dal ciclo di controllo (quello che inizia con la label denominata appunto “controllo”), aspetta un po’ di tempo per permettere all’utente di premere tutti e due i tasti, e poi passa alla scansione della tastiera come detto in precedenza. Questo concede all’utente un certo lasso di tempo per premere tutti i pulsanti desiderati.


Qualche nota a riguardo della realizzazione pratica: come ho detto all’inizio dell’articolo, la necessità di stare in uno spazio ristretto mi ha costretto ad apportare certe modifiche:

  • Il condensatore di filtro C3 mi impediva di piegare il regolatore lm317 che in piedi era più alto della scatola; ho dovuto quindi sostituire il condensatore con uno più piccolo da 100uF.
  • Un led con opportuna resistenza dovrebbe segnalare che il dispositivo è acceso, per non dimenticarsi di spegnerlo; non ho potuto inserirlo proprio per mancanza di spazio, anche se vedrete nelle foto quello collegato al pin RA1 che ho usato in fase di debug.

A chi volesse replicare questo progetto in uno spazio maggiore, dò alcuni consigli che, sempre per mancanza di spazio, non ho potuto attuare nel mio progetto:

  • un connettore ICSP per la programmazione del microcontrollore mediante pickit;
  • un connettore per la programmazione in circuit del modulo audio, come spiegato nell’articolo tecnico numero 3
  • una regolazione del volume con un potenziometro, più versatile della regolazione digitale che ho usato in questo progetto

Ecco infine le foto della realizzazione con un video:

Nelle foto potete vedere alcune resistenze connesse fra i pin di controllo del modulo audio e il pic (per intenderci, sui pin di portA 0,1,2,3): non fateci caso, esse risalgono alla versione precedente del progetto, e non sono comprese in questo; infatti sono cortocircuitate da sotto la millefori. Non le ho dissaldate perchè avrei rischiato di rimuovere anche la piazzola in rame complicandomi notevolmente il cablaggio (vedrete che lo spazio è davvero ristretto!).

Il microcontrollore, col quarzo, i pin di controllo per il modulo audio e i fili del connettore per la tastiera e l'amplificatore (l'interruttore non era ancora a posto):

  

(clicca sulle foto per vederle molto più grandi)

La parte interna, senza il modulo audio e la parte interna col modulo audio e il connettore per tastiera

  

(clicca sulle foto per vederle molto più grandi)

Il tutto prima della chiusura e il tutto dopo la chiusura e la sistemazione dell'interruttore (e la colorazione, volutamente ironica, affidata a mio fratello, più portato di me sotto il profilo artistico):

  

(clicca sulle foto per vederle molto più grandi)

Ma siccome un video vale più di mille foto, ecco un video del funzionamento in cui provo alcuni suoni, modifico il volume e spengo/riaccendo per verificare che tenga effettivamente in memoria il volume. Purtroppo nel video non risalta bene la regolazione del volume, ma dal vivo si sente eccome.

ecco il video: VIDEO del funzionamento

Un ringraziamento a Luca Pellegrini di lpelettronica.it per avermi permesso le citazioni agli articoli tecnici presenti sul loro sito.

Con questo ho terminato, spero che il progetto vi sia piaciuto.