/*
-----------------------------------------------------------------------------
Esempio_Buzzer_2_TullioAndMax
Obbiettivo:
NON usare più
la fuzione standard tone() *** che su Arduino Nano RP2040 non funziona ***
ed utilizzare una nuova funzione di generazione dei tone (appositamente scritta)
ATTENZIONE:
la tone() ufficiale non tiene bloccato lo sketch perchè usa un Timer (e necessita di un delay in coda)
la nuova fuzione TIENE BLOCCATO LO SKETCH (fino al termine del BEEP emesso) e NON necessita di delay in coda
quindi NON è più necessaria neppure la notone()
-----------------------------------------------------------------------------
*/
int BuzzerPin = 6; // Scegli un pin digitale qualsiasi (anche se non è PWM)
float NoteArrayFrequency[9*12]; // Array delle frequense delle note di 9 ottave
int LoopCount = 0; // Contatore delle escuzioni della funzione loop()
// -------------------------------------------------------------------------- setup()
void setup() {
// --- Imposto il Pin del buzzer
pinMode(BuzzerPin, OUTPUT);
// --- Imposto la seriale per gli User FeedBack
Serial.begin(9600);
while (!Serial);
// --- Inizializzo array delle frequenze delle note musicali
SetNoteArrayFrequency();
for (int i=48;i<=48+12;i++) {
Serial.print("NoteArrayIndex[" + String(i)+"]"+"\t");
Serial.print("=NoteArrayFrequency=" + String(NoteArrayFrequency[i])+"\t");
Serial.print("\r\n");
}
// --- End setup()
}
// -------------------------------------------------------------------------- loop()
void loop() {
int Frequency = 0; // Frequenza in Hertz della nota da emettere
int DurationMillis = 0; // Durata della nota da emettere (in millisecondi)
// --- Conteggio Loop eseguiti
LoopCount = LoopCount + 1;
// --- Determino tempo impiegato da un ciclo di 1000000 for
if ( LoopCount == 1 ) {
long ForMicroseconds = GetForMicroseconds(1000000);
Serial.print("ForMicroseconds="+String(ForMicroseconds));
delay(5000);
}
// --- Loop per 1 ottava da 440 Hertz in su (mezzo tono per volta)
if ( LoopCount == 1 ) {
for (int i=48;i<=48+12;i++) {
Frequency = NoteArrayFrequency[i];
DurationMillis = 200;
TullioAndMaxBeep(BuzzerPin,Frequency,DurationMillis);
delay(200);
}
}
// --- Loop per 9 ottave
if ( LoopCount == 1 ) {
for (int i=0;i<108;i=i+12) {
Frequency = NoteArrayFrequency[i];
DurationMillis = 200;
TullioAndMaxBeep(BuzzerPin,Frequency,DurationMillis);
delay(200);
}
}
// --- Loop mezzo tono per volta per 9 ottave
if ( LoopCount == 1 ) {
for (int i=0;i<108;i++) {
Frequency = NoteArrayFrequency[i];
DurationMillis = 100;
TullioAndMaxBeep(BuzzerPin,Frequency,DurationMillis);
// delay(200);
}
}
// --- Giro di DO per 4 volte
if ( LoopCount <= 4 ) {
DurationMillis = 200;
int ModoMaggiore = 0;
int ModoMinore = 1;
// --- Arpeggio di DO maggiore
Arpeggio(BuzzerPin,51,DurationMillis,ModoMaggiore);
// --- Arpeggio di LA minore
Arpeggio(BuzzerPin,48,DurationMillis,ModoMinore);
// --- Arpeggio di FA maggiore
Arpeggio(BuzzerPin,44,DurationMillis,ModoMaggiore);
// --- Arpeggio di SOL maggiore
Arpeggio(BuzzerPin,46,DurationMillis,ModoMaggiore);
}
// --- End loop()
}
// -------------------------------------------------------------------------- TullioAndMaxBeep()
// Input:
// int InpPin = Numero del Pin digitale su cui emettere il beep
// int InpFreq = Frequenza in Hertz da emettere (tra 55 e 15000 circa)
// int InpDurationMillis = Durata del beep (in millisecondi)
void TullioAndMaxBeep(int InpPin, int InpFrequency, int InpDurationMillis) {
// --- Definizioni
long CycleMicroseconds = 0;
int CycleMaxNumber = 0;
long HalfCycleMicroseconds = 0;
long HighDelayMicroseconds = 0;
long LowDelayMicroseconds = 0;
// --- Determino numero di "Cicli" da eseguire
CycleMaxNumber = long(InpFrequency) * long(InpDurationMillis) / 1000.0;
// --- Determino lunghezza di ogni "Ciclo" HIGH-LOW (espressa in in Microsecondi)
CycleMicroseconds = 1000000.0 / InpFrequency;
// --- Determino lunghezza del "Semi-Ciclo"
HalfCycleMicroseconds = CycleMicroseconds / 2.0;
// --- Determino il Delay da applicare al semiciclo HIGH
// è SEMPRE uguale al Semi-Ciclo standard
HighDelayMicroseconds = HalfCycleMicroseconds;
// --- Determino il Delay da applicare al semiciclo LOW
// è SEMPRE uguale al Semi-Ciclo standard - qualche microsoecondo
// (per consentire l'esecuzione della FOR)
// Per fare le cose fatte per bene:
// bisognerebbe determinare la durata reale della istruzione for
// e non togliere arbitrariamente 1 microsecondo... :-)
LowDelayMicroseconds = HalfCycleMicroseconds - 1;
Serial.println("");
Serial.print("InpFrequency="+String(InpFrequency));
Serial.println("\tInpDurationMillis="+String(InpDurationMillis));
Serial.print("CycleNumber="+String(CycleMaxNumber));
Serial.println("\tCycleMicroseconds="+String(CycleMicroseconds));
Serial.print("HalfCycleMicroseconds="+String(HalfCycleMicroseconds));
Serial.print("\tHigh="+String(HighDelayMicroseconds));
Serial.print("\tLow="+String(LowDelayMicroseconds));
Serial.println("");
// --- LOOP di emissione dei cicli di HIGH-LOW *** per simulare la tone() ***
for (long Cycle=0 ; Cycle<CycleMaxNumber ; Cycle++) {
digitalWrite(InpPin, HIGH);
delayMicroseconds(HighDelayMicroseconds);
digitalWrite(InpPin, LOW);
delayMicroseconds(LowDelayMicroseconds);
}
// --- End TullioAndMaxBeep()
}
// -------------------------------------------------------------------------- Arpeggio()
// Input:
// int InpPin = Numero del Pin digitale su cui emettere il beep
// int InpNote = Numero della nota fondamentale
// int InpDutationMillis = Durata della singola nota (in millisecondi)
// int InpModo = Modo dell'accordo (0=Maggiore, 1=Minore)
void Arpeggio(int InpPin, int InpNote, int InpDurationMillis, int InpModo) {
// --- Definisco nota da suonare
int N = InpNote; // Nota da emettere
int DurationMillis = InpDurationMillis; // Durata della nota da emettere (in millisecondi)
int T = N; // Nota tonica
int M = N + 4; // Nota modale (la terza giusta)
if ( InpModo == 1 ) { M = M - 1; } // ma se l'accordo è minore è diminuita di mezzo tono
int D = N + 7; // Nota dominante (la quinta giusta)
int O = N + 12; // Nota tonica (ottava superiore)
// --- Emetto tonica
TullioAndMaxBeep(BuzzerPin,NoteArrayFrequency[T],DurationMillis);
// --- Emetto modale
TullioAndMaxBeep(BuzzerPin,NoteArrayFrequency[M],DurationMillis);
// --- Emetto dominante
TullioAndMaxBeep(BuzzerPin,NoteArrayFrequency[D],DurationMillis);
// --- Emetto tonica (ottava superiore)
TullioAndMaxBeep(BuzzerPin,NoteArrayFrequency[O],DurationMillis);
// --- ri-Emetto dominante
TullioAndMaxBeep(BuzzerPin,NoteArrayFrequency[D],DurationMillis);
// --- ri-Emetto modale
TullioAndMaxBeep(BuzzerPin,NoteArrayFrequency[M],DurationMillis);
// -- End Arpeggio()
}
// -------------------------------------------------------------------------- GetForMicroseconds()
// Input:
// int InpMax = Numero di cicli for da eseguire
// Output:
// long Microsecondi impiegati
long GetForMicroseconds(long InpMax) {
// --- Definizioni
unsigned long StartMicroseconds;
unsigned long StopMicroseconds;
unsigned long DeltaMicroseconds;
// --- Memorizzo Microsecondi di Start
StartMicroseconds = micros();
// --- Eseguo il ciclo di for
for (long i=0 ; i<InpMax; i++) {
// i = i;
}
// --- Memorizzo Microsecondi di Stop
StopMicroseconds = micros();
// --- Calcolo Microsecondi impiegati
DeltaMicroseconds = StopMicroseconds - StartMicroseconds;
// --- Rendo al chiamante
return DeltaMicroseconds;
// --- End GetForMicroseconds()
}
// -------------------------------------------------------------------------- SetNoteArrayFrequency()
// Caricamenteo Array delle frequenze delle Note Musicali (scala cromatica)
// Input:
// nulla
void SetNoteArrayFrequency() {
// --- Si parte dalla nota 0 = 1° LA basso del pianoforte
int NoteArrayIndex = 0;
// --- Scansione delle 9 ottave
for (int Ottava=0;Ottava<9;Ottava++) {
// --- Scansione dei 12 semitoni di ogni ottava
for (int SemiTono=0;SemiTono<12;SemiTono++) {
// --- Imposto la frequenze della singola nota
NoteArrayFrequency[NoteArrayIndex] = 27.500 * pow(2,float(NoteArrayIndex)/12);
// --- Prossima nota
NoteArrayIndex = NoteArrayIndex + 1;
// --- End loop delle note della ottava
}
// --- End loop delle ottave
}
// --- End SetNoteArrayFrequency()
}