INTERRUPTS - INTERRUPCIONES

Buenas,

Queria hacer una consulta acerca de los INTERRUPT. Tengo un multiswitch y quiero leer las señales a traves de arduino, son 9 señales, una de arranque y las demas de control.

Pero tengo un problema , las señales se leen perfectamente, tambien se guardan en una matriz pero cuando llega la hora de jugar con esa matriz el programa no responde. He probado que a la hora de utilizar los valores de la matriz estos meterlos dentro de la funcion noInterrupt() y cuando finalize interrupt() pero me sigue pasando exactamente lo mismo.

Me gustaria saber si alguien le ha sucedido algo parecido o tiene idea y me pueda dar una solución con el fin de resolverlo.

Adjunto el codigo completo y seguidamente lo describo por fases para un mayor entendimiento.

#define Interrupcion 0 // INTERRUPT 0 = DIGITAL PIN 3 - use the interrupt number in attachInterrupt,.....pines 2 y/ó 3 en UNO.
#define ch7 3 // INTERRUPT 0 = DIGITAL PIN 3 - use the PIN number in digitalRead # changed to pin 3 for micro


volatile int pulso = 1500; // volatile, we set this in the Interrupt and read it in loop so it must be declared volatile
volatile unsigned long inicio_flanco = 0; // set in the interrupt
volatile unsigned long valor_inicio_flanco = 0; // set in the interrupt
volatile boolean nuevo_pulso = false; // set in the interrupt and read in the loop

unsigned long dead_time;
unsigned long current_time;

char buffer[80] = "";

int Multi_Switch[50]; //tamaño de la matriz para albergar los 9 valores
int switch_num = 0; // variable para indicar el switch de los 8 posibles

int valor_pulso = 1000; // variable Xpara el valor del pulso a leer, inicializado a 1000

void setup()
{
// should only have to see 8 of these... 9th should be sync signal
Multi_Switch[0] = 1500;// inicializa en el valor central de cada interruptor 
Multi_Switch[1] = 1500;
Multi_Switch[2] = 1500;
Multi_Switch[3] = 1500;
Multi_Switch[4] = 1500;
Multi_Switch[5] = 1500;
Multi_Switch[6] = 1500;
Multi_Switch[7] = 1500;
Multi_Switch[8] = 1500;

// tell the Arduino we want the function calcReceiver to be called whenever INT0 (digital pin 3) changes from HIGH to LOW or LOW to HIGH
// catching these changes will allow us to calculate how long the input pulse is
attachInterrupt(Interrupcion,calcReceiver,CHANGE);

//we will be sending a ton of data
Serial.begin(57600);//57600

dead_time = millis();

Serial.println("system ready");
}

void loop()
{

if(nuevo_pulso == true)
    {
    //copy to our non volatile var
    valor_pulso = pulso; // pulso es el valor volatil. valor_pulso es el valor a utilizar
        if (switch_num < 50)
        {
        Multi_Switch[switch_num] = valor_pulso;
        }
    switch_num++;
    
    nuevo_pulso = false;
    } // end nuevo_pulso

sprintf(buffer ,"valor_pulso %d , counter %d", valor_pulso, switch_num);
Serial.println(buffer);

//servo channel orientation normal
if (valor_pulso < 1000)
  {
  sprintf(buffer ,"valor_pulso < 1000 %d %d this is sync signal", valor_pulso, switch_num);
  Serial.println(buffer);
  switch_num = 0;
  }

//servo channel orientation reversed
if (valor_pulso > 2000)
  {
  sprintf(buffer ,"valor_pulso > 2000 %d %d this is reversed sync signal", valor_pulso, switch_num);
  Serial.println(buffer);
  switch_num = 0;
  }

// Failsafe
current_time = millis();

//it has been 3 seconds since we got a servo pulse...
if ((current_time - dead_time ) > 3000)
  {
  Serial.println("receiver lost signal");
  //change Multi_Switch[0]..Multi_Switch[7] to failsafe values
  }

// put your code here to run through values stored in Multi_Switch[0]...Multi_Switch[7] to position switches/lights/horns/servos accordingly

delay(10); // delay in between reads for stability

// other processing ... 
} //end of void loop()


void calcReceiver()
{
// if the pin is high, its the start of an interrupt
if(digitalRead(ch7) == HIGH)
      { 
      // get the time using micros - when our code gets really busy this will become inaccurate, but for the current application its easy to understand and works very well
      valor_inicio_flanco = inicio_flanco;
      inicio_flanco = micros();
      }
else
{
// if the pin is low, its the falling edge of the pulse so now we can calculate the pulse duration by subtracting the 
// start time inicio_flanco from the current time returned by micros()
if(inicio_flanco && (nuevo_pulso == false))
      {
      pulso = (int)(micros() - inicio_flanco);
      inicio_flanco = 0;
      
      // tell loop we have a new signal on the CHANNEL channel
      // we will not update pulso until loop sets
      // nuevo_pulso back to false
      nuevo_pulso = true;
      
      //reset our dead-man's switch
      dead_time = millis();
      }
}
} //end of void calcReceiver()

Ahora lo explicare paso por paso.

Esta linea de codigo es la que se encarga de llamar a la funcion calReceiver cada vez que por la entrada cambia el voltaje, es decir cada interrupcion.

attachInterrupt(Interrupcion,calcReceiver,CHANGE);

Cuando esto sucede se llama a calcReceiver.

void calcReceiver()
{
// si la entrada va a alto,es el inicio de una interrupcion
if(digitalRead(ch7) == HIGH)
      { 
     // mide el tiempo en microsegundos - when our code gets really busy this will become inaccurate, but for the current application its easy to understand and works very well
      valor_inicio_flanco = inicio_flanco;
      inicio_flanco = micros();
      }
else
{
//// si la entrada va a bajo, el pulso ha terminado y es el momento de calcular su duracion restando el tiempo de inicio menos el tiempo final devuelto por la funcion micros()
// if the pin is low, its the falling edge of the pulse so now we can calculate the pulse duration by subtracting the 
// start time inicio_flanco from the current time returned by micros()
if(inicio_flanco && (nuevo_pulso == false))
      {
      pulso = (int)(micros() - inicio_flanco);
      inicio_flanco = 0;
      
      // tell loop we have a new signal on the CHANNEL channel
      // we will not update pulso until loop sets
      // nuevo_pulso back to false
      nuevo_pulso = true;
      
      //reset our dead-man's switch
      dead_time = millis();
      }
}

Cuando acaba entra en loop de nuevo y en esta parte es cuando se carga la matriz con los valores que envia la señal de radio.

if(nuevo_pulso == true)
    {
// si detecta un pulso, guarda el valor en la matriz, si no, sigue el loop
    //copy to our non volatile var
    valor_pulso = pulso; // pulso es el valor volatil. valor_pulso es el valor a utilizar
        if (switch_num < 50)
        {
        Multi_Switch[switch_num] = valor_pulso;
        }
    switch_num++;
     // cambiar el boleano a falso al terminar
  // con pulso, mientras sea verdadero, calcInput no actualizara el pulso
    nuevo_pulso = false;
    } // end nuevo_pulso

Todo el codigo restante solo sirve para mostrar informacion y saber cuando empieza de nuevo el arranque es decir cuando poner la matriz a 0 de nuevo.

El problema como anteriormente he dicho es que la matriz se carga con los valores pero a la hora de mostrarlos y utilizar esos valores en condiciones resulta imposible.

Gracias a las personas que colaboran y se ayudan sin intereses. :slight_smile:

Me surge la consulta de como has conectado el switch al pin INT0? Usas una resistencia PULL DOWN?

Esta es la respuesta que obtuve con tu código para frencuencias mayores y menores que 500 hz

Otra cosa que he visto es que counter no se detiene en 50 y tu código lo ratifica.
Tu código dice

if (switch_num < 50)    {
    		Multi_Switch[switch_num] = valor_pulso;
    	}
    	switch_num++;
    
    	nuevo_pulso = false;
    } // end nuevo_pulso

    sprintf(buffer ,"valor_pulso %d , counter %d", valor_pulso, switch_num);
    Serial.println(buffer);

pero que ocurre cuando switch_num supera 50? nada.. sigue creciendo y como intentas acceder a direcciones de memoria inexistentes eso siempre conlleva problemas.
Asi que restringe a swit_num++ para que nunca llegue a 50.

No utilizo ninguna resistencia, en cuanto al llenado de la matriz me he olvidado a mencionar que la matriz solo necesita 9 valores, la matriz podria ser de 9 perfectamente, no de 50, es algo aleatorio, un ejemplo

VALOR INICIAL DE ARRANQUE= 984 ==> Multi_Switch[0]

Las demas señales de 1 a 8 son de control.

En el siguiente codigo detalla que cuando el pulso es menor de 1000 , es decir cuando llega la señal de sincronizacion, el contador se reinicia a 0 para volver a llenar la matriz.

//servo channel orientation normal
if (valor_pulso < 1000)
  {
  sprintf(buffer ,"valor_pulso < 1000 %d %d this is sync signal", valor_pulso, switch_num);
  Serial.println(buffer);
  switch_num = 0;
  }

//servo channel orientation reversed
if (valor_pulso > 2000)
  {
  sprintf(buffer ,"valor_pulso > 2000 %d %d this is reversed sync signal", valor_pulso, switch_num);
  Serial.println(buffer);
  switch_num = 0;
  }

Podrias probar si al llenar la matriz puedes ponerle una condicion algun valor de la matriz para encender un led por ejemplo. Es lo que no consigo, que al estar la matriz llena, en ESTE codigo no lo muestro, pero cuando la matriz se llena , es decir,cuando ha llegado a 8, en ese momento recorro array y tengo unas condiciones para accionar servos y demas parafernalia. Pero se queda el programa bloqueado.

Que programa utilizas de simulacion?

Gracias. :slight_smile: