///////////////////////////////////////////////* FRECUENCÍMETRO *//////////////////////////////////////////////////////////////
// Definición de pines
const int senyal_output = 23; // Pin de salida de la señal
const int senyal_entrada = 18; // Pin de entrada para medir la señal
const int sube = 32; // Pin para el botón de aumento de tiempo de medida
const int baja = 33; // Pin para el botón de disminución de tiempo de medida
const int empieza = 35; // Pin para el botón de inicio
// Frecuencia inicial de la señal y cálculos relacionados
const float frec_senyal_default = 5.8; // Frecuencia inicial de la señal en Hz
float frec_senyal = frec_senyal_default; //valor que toma la frecuencia de la señal (inicialmente 5,8)
float periodo_senyal_ms = 1000 * (1 / frec_senyal); //cálculo del periodo de la señal
// Variables para el control del programa
int start = 0; // La onda no se está generando
volatile unsigned long nflancos = 0; // Variable para contar los flancos
// Variables para el control de botones
volatile int sube_puls = 0; // Indica que no se ha presionado el botón de aumento
volatile int baja_puls = 0; // Indica que no se ha presionado el botón de disminución
// Variables de tiempo
unsigned long tp1 = 0; // Tiempo del último cambio de estado de la señal
unsigned long current_time; // Tiempo actual
unsigned long t_medida = 5000; // Tiempo de medida inicial (5 segundos)
unsigned long last_subida_time = 0; // Tiempo del último cambio de estado del botón sube
unsigned long last_bajada_time = 0; // Tiempo del último cambio de estado del botón baja
unsigned long debounce_time = 300; // Tiempo de rebote en milisegundos
hw_timer_t *timer = NULL; //Predefine un puntero para almacenar la ubicación del temporizador
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Función de interrupción para el botón de inicio
void IRAM_ATTR ISR_empieza()
{
start = 1; //se inicia la medición
}
// Función de interrupción para el temporizador
void IRAM_ATTR onTimer()
{
nflancos++; // Incrementa el número de flancos
}
// Funciones de interrupción para los botones de aumento y disminución de tiempo de medida
void IRAM_ATTR ISR_sube()
{
if (millis() - last_subida_time > debounce_time) //Asegurando que haya pasado más tiempo entre pulsaciones de subida que el tiempo de rebote configurado
{
sube_puls = 1; //botón de subida presionado
last_subida_time = millis(); //se actualiza el tiempo de la última pulsación de subida
}
}
void IRAM_ATTR ISR_baja()
{
if (millis() - last_bajada_time > debounce_time) //Asegurando que haya pasado más tiempo entre pulsaciones de bajada que el tiempo de rebote configurado
{
baja_puls = true; //botón de bajada presionado
last_bajada_time = millis(); //se actualiza el tiempo de la última pulsación de bajada
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
pinMode(senyal_output, OUTPUT); //Configurar el pin de salida
pinMode(senyal_entrada, INPUT_PULLUP); // Configurar el pin de entrada con pull-up para asegurar un nivel alto cuando no hay señal
attachInterrupt(digitalPinToInterrupt(senyal_entrada), onTimer, FALLING); // Configurar interrupción para el pin de entrada de la señal
attachInterrupt(digitalPinToInterrupt(empieza), ISR_empieza, FALLING); // Configurar interrupción para el botón de inicio
attachInterrupt(digitalPinToInterrupt(sube), ISR_sube, FALLING); // Configurar interrupción para el botón de aumento
attachInterrupt(digitalPinToInterrupt(baja), ISR_baja, FALLING); // Configurar interrupción para el botón de disminución
timer = timerBegin(0, 300, true); // Configurar temporizador 0 con prescaler de 300 para contar microsegundos y generar interrupción cada segundo
timerAttachInterrupt(timer, &onTimer, true); // Adjuntar la función de interrupción al temporizador. La función onTimer() se llama cada segundo y reinicia el contador nflancos.
timerAlarmWrite(timer, t_medida * 1000, true); // Configurar el temporizador para que expire después de t_medida * 1000 microsegundos
timerAlarmEnable(timer); // Habilitar el temporizador
Serial.begin(115200); // Iniciar la comunicación serial con velocidad de 115200 bps
Serial.println("Introduzca, si lo desea, un nuevo valor para la frecuencia autogenerada de la señal (en Hz): ");
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
delay(1); // Solo en el simulador, para que no tenga que procesar tantos "if" para nada, y así vaya más rápido
current_time = millis(); // Obtener el tiempo actual
// Aumentar el tiempo de medida si se ha presionado el botón de aumento y el tiempo actual de medida es menor que 9000 ms
if (sube_puls==1 && t_medida < 9000)
{
sube_puls = 0; //se desactiva el botón de subida
t_medida += 1000; //aumenta y actualiza el valor del tiempo de medida
Serial.println("Tiempo de medida aumentado a " + String(t_medida) + " ms");
}else{sube_puls = false;
}
// Disminuir el tiempo de medida si se ha presionado el botón de disminución y el tiempo actual de medida es mayor que 1000 ms
if (baja_puls==1 && t_medida > 1000)
{
baja_puls = 0; //se desactiva el botón de bajada
t_medida -= 1000; //disminuye y actualiza el valor del tiempo de medida
Serial.println("Tiempo de medida disminuido a " + String(t_medida) + " ms");
}else{baja_puls = false;
}
// Leer la entrada serial para obtener una nueva frecuencia autogenerada si está disponible
while (Serial.available() > 0)
{
String inputString = Serial.readStringUntil('\n'); // Leer la cadena hasta encontrar un carácter de nueva línea
float frec_senyal = inputString.toFloat(); // Convertir la cadena a un número flotante
inputString.trim(); // Ignorar los caracteres de retorno de carro y nueva línea
periodo_senyal_ms = 1000 * (1 / frec_senyal);
// Imprimir la frecuencia sin los caracteres de retorno de carro y nueva línea
Serial.print("Frecuencia actualizada a ");
Serial.print(frec_senyal);
Serial.println(" Hz");
}
// Iniciar la generación de la señal y la medición si el botón de inicio ha sido presionado
if (start == 1)
{
//Generador onda señal cuadrada
if (current_time - tp1 > periodo_senyal_ms / 2)
{
digitalWrite(senyal_output, !digitalRead(senyal_output));
tp1 = current_time; // Resetear el tiempo del último cambio de estado de la señal
}
// Imprimir la frecuencia medida cada vez que se cumple el tiempo de medida
if (current_time % t_medida == 0)
{
float valor_frec = (float)nflancos / (t_medida / 1000.0); //cálculo de la frecuencia medida (nº de flancos/s)
Serial.printf("Frecuencia medida: %4.2f Hz, Flancos contados: %lu en %lu ms\n", valor_frec, nflancos, t_medida);
nflancos = 0; // Reiniciar el contador de flancos para cada medida
}
}
}