// se declaran las librerias
#include <arduinoFFT.h> // Librería de la transformada rápida de Fourier FFT
#include <Adafruit_SSD1306.h> // Librería para el display OLED
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
// Definición de las variables del display OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Cambia el valor si tu pantalla OLED tiene un pin de reset
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Definición de las variables del programa FFT
#define SAMPLES 2048 // Número de muestras: este número debe estar en una potencia de 2. Cuanto mayor sea este número, mejor será la resolución (más contenedores -> rangos de frecuencia más estrechos)
#define SAMPLING_FREQUENCY 900 // Frecuencia de muestreo: debe ser al menos el doble de la frecuencia que queremos "capturar" (debido al teorema de Shannon-Nyquist)
unsigned int sampling_period_us;
unsigned long microsec_per_reading;
double volts_per_lsb;
arduinoFFT FFT = arduinoFFT();
// Definición de las variables de frecuencias del cuatro
const float frecuenciaLa = 242.0;
const float frecuenciaRe = 326.66;
const float frecuenciaFa = 389.99;
const float frecuenciaSi = 274.94;
const float rangoError = 0.05;
// Definición de las variables de salidas y entradas
const int pinLED_La = 19; // LED para LA
const int pinLED_Re = 18; // LED para RE
const int pinLED_Fa = 15; // LED para FA
const int pinLED_Si = 17; // LED para SI
const int pinResetButton = 26; // Botón de reset
const int pinSelectButton = 33; // Botón para seleccionar
// Definicion de varibles de menu y visualizacion
enum Afinacion { Esperando_LA, Afinado_LA, Esperando_RE, Afinado_RE, Esperando_FA, Afinado_FA, Esperando_SI, Afinado_SI, Afinado };
Afinacion estadoAfinacion = Esperando_LA;
void setup() {
Serial.begin(115200);
sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
microsec_per_reading = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
volts_per_lsb = 3.3 / 1024;
pinMode(pinLED_La, OUTPUT); // Configurar el pin del LED para LA como salida
pinMode(pinLED_Re, OUTPUT); // Configurar el pin del LED para RE como salida
pinMode(pinLED_Fa, OUTPUT); // Configurar el pin del LED para FA como salida
pinMode(pinLED_Si, OUTPUT); // Configurar el pin del LED para SI como salida
pinMode(pinResetButton, INPUT_PULLUP); // Configurar el botón de reset como entrada con resistencia pull-up
pinMode(pinSelectButton, INPUT_PULLUP); // Configurar el botón de selección como entrada con resistencia pull-up
// se declara pantalla principal
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("AFINADOR CUATRO"));
display.setTextSize(1);
display.setCursor(0, 40);
display.print(F("Presionar 'inicio' para comenzar"));
display.display();
}
void loop() {
static double vReal[SAMPLES];
static double vImag[SAMPLES];
for (int i = 0; i < SAMPLES; i++) {
int sensorValue = analogRead(34);
vReal[i] = sensorValue * volts_per_lsb;
vImag[i] = 0;
delayMicroseconds(sampling_period_us);
}
FFT.DCRemoval(); // Elimina el offset de la señal eléctrica
FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(FFT_FORWARD);
FFT.ComplexToMagnitude();
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
// Mostrar la frecuencia dominante en el monitor serie
Serial.print(F("Frecuencia dominante: "));
Serial.print(abs(peak));
Serial.println(F(" Hz"));
// se declara pantalla secundaria
// Mostrar la frecuencia dominante en el display OLED con letras grandes y dos decimales
display.clearDisplay();
display.setTextSize(1); // Configura el tamaño de fuente en 1 para letras grandes
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("Frecuencia dominante:"));
display.setTextSize(2); // Configura el tamaño de fuente en 2 para números más grandes
display.print(abs(peak));
display.print(F(" Hz"));
display.display();
// Display tuning states below the frequency
display.setTextSize(1);
display.setCursor(0, 40);
display.print(F("Estado de Afinacion: "));
switch (estadoAfinacion) {
case Esperando_LA:
display.print(F("Esperando LA"));
break;
case Afinado_LA:
display.print(F("Afinado LA"));
break;
case Afinado_RE:
display.print(F("Afinado RE"));
break;
case Afinado_FA:
display.print(F("Afinado FA"));
break;
case Afinado_SI:
display.print(F("Afinado SI"));
break;
case Afinado:
display.print(F("Afinado"));
break;
}
display.display();
switch (estadoAfinacion) {
case Esperando_LA:
if (abs(abs(peak) - (frecuenciaLa)) < frecuenciaLa * rangoError) {
estadoAfinacion = Afinado_LA;
digitalWrite(pinLED_La, HIGH);
}
break;
case Afinado_LA:
if (abs(abs(peak) - frecuenciaRe) < frecuenciaRe * rangoError) {
estadoAfinacion = Afinado_RE;
digitalWrite(pinLED_Re, HIGH);
}
break;
case Afinado_RE:
if (abs(abs(peak) - frecuenciaFa) < frecuenciaFa * rangoError) {
estadoAfinacion = Afinado_FA;
digitalWrite(pinLED_Fa, HIGH);
}
break;
case Afinado_FA:
if (abs(abs(peak) - frecuenciaSi) < frecuenciaSi * rangoError) {
estadoAfinacion = Afinado;
digitalWrite(pinLED_Si, HIGH);
}
break;
}
if (digitalRead(pinResetButton) == LOW) { // Si se pulsa el botón de reset
// Reiniciar el proceso de afinación
digitalWrite(pinLED_La, LOW);
digitalWrite(pinLED_Re, LOW);
digitalWrite(pinLED_Fa, LOW);
digitalWrite(pinLED_Si, LOW);
estadoAfinacion = Esperando_LA;
}
delay(10);
}