//Práctica 3
//Definimos los pines
const int senyal_output = 23; // pin generacion señal simulación -> en el lab, conectar generador de funciones
const int senyal_entrada = 18; // GPIO pin interrupcion para la entrada de señal
//Valores de la frecuencia y periodo de la función que queremos crear
float frec_senyal = 5.8; // poner valores entre 1 y 25 Hz para el simulador, en la placa real se pueden elevar los tiempos
float periodo_senyal_s = (1/frec_senyal); // periodo en s
float t_medida=1; //Empezamos con 1 segundo (tiempo de visualizacion de la señal)
//Variables globales de las interrupciones
//HAY QUE PONERLOS COMO VOLATILES!!
volatile float start=0; //Registra el botón que da comienzo a la señal
volatile float nflancos=0; //Cuenta el número de flancos
volatile int subida=0;//VA A REGISTRAR SI PULSAMOS EL BOTON DE AUMENTAR 1 SEGUNDO
volatile int bajada=0;//VA A REGISTRAR SI PULSAMOS EL BOTON DE DISMINUIR 1 SEGUNDO
volatile int cuenta1=0; //Regista cuando pasa el tiempo de conteo de la frecuencia
volatile int cuenta2=0; //Registra la mitad del periodo
//Variales para los timers (timer cada segundo y timer2 cada mitad de periodo)
hw_timer_t * timer = NULL; //puntero a la estructura
hw_timer_t * timer2 = NULL; //puntero a la estructura
#define temp1 1
#define temp2 2
#define temp0 0
#define fprescaler 80e6 //Definido por el microprocesador
#define prescaler 290 //200 + 10 *9 (puesto 9)
volatile float valor_cuenta=fprescaler/prescaler; //valor para obtener 1 segundo
volatile float nuevo_valor=valor_cuenta; //inicialmente
//PARA EVITAR LOS REBOTES
int cts=0;//tiempo de subida
int ctb=0;//tiempo de bajada
////////////////////////////////////////////////////////////////////
//ISR Habilita la señal
void IRAM_ATTR ISR_start_senyal(){
start++;
}
//ISR Cuenta el número de flancos
void IRAM_ATTR ISR_senyal(){
nflancos++;
}
// ISR Registra cuando pasa el tiempo de conteo de la frecuencia
void IRAM_ATTR finTimer() {
cuenta1=1;
}
// ISR Registra la mitad del periodo de la señal creada
void IRAM_ATTR finTimer2() {
cuenta2=2;
}
//ISR Aumenta el tiempo de medida 1 segundo
void IRAM_ATTR ISR_sube(){
if(millis()>cts+300)
subida =1;
cts=millis();
}
//ISR Disminuye el tiempo de medida 1 segundo
void IRAM_ATTR ISR_baja(){
if(millis()>ctb+300)
bajada =1;
ctb=millis();
}
///////////////////////////////////////////////////////////////////
void setup(){
Serial.begin(115200);
Serial.printf("\n\n Práctica 3: Interrupciones y timers\n");
Serial.print("Para cambiar la frecuencia introduzca el valor deseado en cualquier momento\n");
pinMode(senyal_output, OUTPUT);
attachInterrupt(digitalPinToInterrupt(35), ISR_start_senyal, FALLING);
//para habilitar la señal con el boton del pin35 en flanco desdendiente
attachInterrupt(digitalPinToInterrupt(18), ISR_senyal, FALLING);//configuro el pin como entrada de interrupción
//en el pin 18 cuando se detecte un flanco descendente, se ejecuta la funcion ISR_senyal(cuenta el número de flancos)
attachInterrupt(digitalPinToInterrupt(32), ISR_sube, FALLING);//configuro el pin como entrada de interrupción
//en el pin 23 cuando se detecte un flanco descendente, se ejecuta la funcion ISR_sube(aumenta 1 segundo el tiempo de visualización)
attachInterrupt(digitalPinToInterrupt(33), ISR_baja, FALLING);//configuro el pin como entrada de interrupción
//en el pin 18 cuando se detecte un flanco descendente, se ejecuta la funcion ISR_baja(disminuye 1 segundo el tiempo de visualización)
/*Configuramos 2 timers
- timer -> Para definir el tiempo de toma de la frecuencia
- timer2 -> Define el tiempo de la frecuencia de la señal */
//Inicializamos los timers, contando en el flanco ascendente de la señal de reloj
timer = timerBegin(temp0, prescaler, true);
timer2 = timerBegin(temp1, prescaler, true);
//Indicamos la función de interrupción que se activa al pasar el tiempo deseado
timerAttachInterrupt(timer, &finTimer, true);
timerAttachInterrupt(timer2, &finTimer2, true);
// 80 MHz / prescaler 290 => valor cuenta = 2,75862e5 tics / sec
timerAlarmWrite(timer, valor_cuenta, true); //Alarma que se activa cada x segundo
timerAlarmWrite(timer2, valor_cuenta*periodo_senyal_s/2, true); //Alarma que se activa a la mitad de la señal
//Activamos las alarmas
timerAlarmEnable(timer);
timerAlarmEnable(timer2);
}
//////////////////////////////////////////////////////////////////////
void loop()
{
//Función para introducir un nuevo valor de la señal
if(Serial.available()>0)
{
#define DEBUG(a) Serial.println(a); //para que aparezca en la pantalla el valor que hemos introducido
timerAlarmDisable(timer2); //Primero desactivamos la alarma
String str = Serial.readStringUntil('\n');
frec_senyal = str.toFloat();
DEBUG(frec_senyal);
periodo_senyal_s = (1/frec_senyal); //cambiamos el valor del periodo
timerAlarmWrite(timer2, valor_cuenta*periodo_senyal_s/2, true); //mitad de la señal
timerWrite(timer2, 0); //Se pone a 0 el valor de cuenta del timer
timerAlarmEnable(timer2); //lo volvemos a activar
}
//Para crear la señal cunado se ha pulsado el botón de inicio
if( cuenta2 ==2 && start!=0) //Cuando ha pasado el tiempo del timer2 (mitad de periodo)
{
cuenta2 = 0;
digitalWrite(senyal_output, !digitalRead(senyal_output) ); //(la señal pasa de 1 a 0 y vv)
}
//Para aumentar 1 segundo el tiempo de la visualización de la frecuencia
if(subida ==1 && nuevo_valor < valor_cuenta*9)
{
timerAlarmDisable(timer); //Se desactiva el timer
nuevo_valor += valor_cuenta ; //se suma 1 segundo a lo de antes
t_medida = nuevo_valor/valor_cuenta;
timerAlarmWrite(timer, nuevo_valor, true); // se ejecuta a lo de antes + 1
timerWrite(timer, 0); //El valor del timer se pone a 0
timerAlarmEnable(timer); //Se vuelve a activar
subida=0;
}
//Para disminuir 1 segundo el tiempo de la visualización de la frecuencia
if(bajada == 1 && nuevo_valor > valor_cuenta) //De forma análoga a la función anterior
{
timerAlarmDisable(timer);
nuevo_valor -= valor_cuenta ; //se resta 1 segundo a lo de antes
t_medida = nuevo_valor/valor_cuenta;
timerAlarmWrite(timer, nuevo_valor, true); // se ejecuta a lo de antes + 1
timerWrite(timer, 0);
timerAlarmEnable(timer);
bajada=0;
}
if(cuenta1==1){//si se ha ejecutado la rutina de interrupcion del timer (temp0)
cuenta1=0;
float valor_frec=nflancos/t_medida;
Serial.printf("Frec:%4.2f hz - nflancos: %.0f en %.0f s \n ", valor_frec, nflancos, t_medida );
nflancos=0;
}
}