Per questa lezione ho utilizzato LilyPad Buzzer che ho acquistato su Sparkfun. Si tratta di un piccolo buzzer induttivo con due pin I/O in grado di riprodurre suoni di un livello sufficientemente alto da poter essere sentiti ad esempio se avete il buzzer in tasca, ma non aspettatevi livelli sonori elevatissimi.
Le dimensioni sono di 20 mm di diametro e 0,8 mm di spessore.
Passo 01
Come consigliato nella lezione n. 3 procedete anche per questa piccola scheda alla realizzazione del supporto protettivo in cartocino al fine di evitare scivolamenti dei morsetti a coccodrillo.
Passo 02
Collegate il “+” del buzzer al piedino 9 di LilyPad e il “-” del buzzer al “-” di LiLyPad come rappresentato nell’immagine:
Passo 03
Avviate l’IDE di Arduino e copiate ed incollate il codice che trovate di seguito:
/* Arduino LilyPad: lezione 04: suono * Uso del modulo buzzer * Michele Maffucci LilyPad Buzzer per realizzare semplici note musicali * https://www.maffucci.it/2011/06/30/arduino-lilypa-zione-04-suono/ * Progetto originale: * http://web.media.mit.edu/~leah/LilyPad/07_sound.html * per un grafico sulle differenti frequenze delle note: * http://www.phy.mtu.edu/~suits/notefreqs.html */ int ledPin = 13; // il LED è connesso al pin digitale 13 int speakerPin = 9; // il buzzer è connesso al pin digitale 9 (uscita di tipo PWM) void setup() { pinMode(ledPin, OUTPUT); // si imposta ledPin come pin di output pinMode(speakerPin, OUTPUT); // si imposta speakerPin come pin di output } void loop() // inizio del loop { scale(); // chiamata della funzione scale() delay(1000); // attesa di 1 secondo } void beep (unsigned char speakerPin, int frequencyInHertz, long timeInMilliseconds) // funzione che produce il suono { int x; // converte il periodo della nota in un intero lungo long delayAmount = (long)(1000000/frequencyInHertz); long loopTime = (long)((timeInMilliseconds*1000)/(delayAmount*2)); for (x=0;x<loopTime;x++) { digitalWrite(speakerPin,HIGH); delayMicroseconds(delayAmount); digitalWrite(speakerPin,LOW); delayMicroseconds(delayAmount); } } void scale () { // speakerPin: piedino LilyPad; numero da: 2093 a 4186: frequenza della nota; 500: durata della nota digitalWrite(ledPin,HIGH); //accende il LED beep(speakerPin,2093,500); //C: suona le note C (C7 come da tabella linkata sopra) per 500ms beep(speakerPin,2349,500); //D beep(speakerPin,2637,500); //E beep(speakerPin,2793,500); //F beep(speakerPin,3136,500); //G beep(speakerPin,3520,500); //A beep(speakerPin,3951,500); //B beep(speakerPin,4186,500); //C digitalWrite(ledPin,LOW); //spegne il LED }
Un long è un tipo intero lungo che può contenere un numero intero positivo o negativo (quindi senza punto decimale) di 32 bit con valori compresi tra 2.147.483.647 a – 2.147.483.648
Analizziamo con molta attenzione la funzione beep.
long delayAmount = (long)(1000000/frequencyInHertz); ?
Domanda: cosa vuol dire 1000000/frequencyInHertz:
Vi ricordo che il periodo di una forma d’onda è:
T =1/f
dove f è la frequenza espressa in Hertz. L’unità di misura del periodo T è il secondo.
quindi la formula:
1000000/frequencyInHertz
può essere scritta come:
1000000 * (1/frequencyInHertz)
ovvero:
1000000 * T
Domanda: perché moltiplichiamo per 1000000?
Perché la variabile delayAmount verrà passata a delayMicroseconds() che è una funzione che mette in pausa il programma per un tempo, espresso in microsecondi, specificato dal parametro.
Domanda: ma in un secondo quanti microsecondi ci sono?
1 milione di microsecondi
Ecco spiegato l’arcano, poichè delayMicroseconds() accetta un parametro in microsecondi bisogna moltiplicare 1/frequencyInHertz per 1000000.
Domanda: cosa vuol dire (long) nell’istruzione:
long delayAmount = (long)(1000000/frequencyInHertz);
Per spiegare questa linea di codice devo parlarvi di Type-casting.
In C è possibile forzare il tipo di una variabile (int, long, float, …) in un altro tipo, utilizzando l’operatore “()”
Ad esempio:
int a; int b=67; float c=3.14; float d; char lettera='M'; /* assegna il valore 3 (solo la parte intera) ad a */ a=(int)c /* assegna il valore 77 (codice ASCII) ad a */ a=(int)lettera /* assegna alla variabile d il valore di b, 67.0 (valore float) */ d=(float)b
In alcuni casi il Type-casting viene fatto automaticamente dal compilatore in altri casi bisogna specificarlo. Il Type-casting è una richiesta al compilatore di trasformazione di tipo.
Quando siamo in dubbio è buona norma eseguire il Type-casting.
Il Type-casting risulta utile ad esempio in una divisione:
int x, y; float w; w=(float)x/(float)y;
questa operazione assicura che la divisione sia in floating-point.
Tornando alla nostra istruzione:
long delayAmount = (long)(1000000/frequencyInHertz);
quando effettuiamo un passaggio di valore ad una funzione bisogna convertire long in (long , infatti delayAmount viene passata a delayMicroseconds.
Domanda: ma cos’è delayAmount?
è il periodo T della frequenza della nota.
Domanda: a cosa serve loopTime?
loopTime definisce il numero di volte in cui la nota deve essere suonata.
Infatti nel corpo del for:
digitalWrite(speakerPin,HIGH); delayMicroseconds(delayAmount); digitalWrite(speakerPin,LOW); delayMicroseconds(delayAmount);
si ha:
digitalWrite(speakerPin,HIGH);
viene messo ad alto l’uscita speakerPin (pin 9)
delayMicroseconds(delayAmount);
la nota viene suonata per un tempo delayAmount, periodo della della nota
l’uscita speakerPin (pin 9) viene portata a massa (spento)
digitalWrite(speakerPin,LOW);
per una quantità di tempo pari al periodo:
delayMicroseconds(delayAmount);
La variazione del timbro della nota avviene se utilizzate la modulazione di larghezza di impulso in inglese Pulse Width Modulation, in questo modo se il treno di impulsi è sufficientemente elevato l’orecchio umano non percepirà una sequenza di impulsi ma un suono costante.