Go Down

Topic: ¿Por qué me sale error al compilar la función de interrupción? (Read 265 times) previous topic - next topic

JMZ96

Buenas a todos, quería saber por qué no compila la funcion de interrupcion? Os dejo el código

Muchas gracias de antemano


Code: [Select]

int x=0;

void setup(){
attachInterrupt(digitalPinToInterrupt(2), velocidadMenos,RISING);
}

void loop(){
void velocidadMenos()
{
x++;
}
}

IgnoranteAbsoluto

Porque has metido la función velocidadMenos() dentro de la función loop().

IgnoranteAbsoluto

Tienes puesto:
Code: [Select]
void loop() {
void velocidadMenos()
{
  x++;
}

}


Has de "mover" } del final a justo después del inicio del loop():
Code: [Select]
void loop() {
}

void velocidadMenos()
{
  x++;
}

JMZ96

Muchísimas gracias, no sabia que las funciones iban fuera del void loop

JMZ96

Al solucionare la duda me ha surgido otra respecto a la funcion de interrupcion, mi pregunta es la siguiente:
La funcion de interrupcion solo se puede ejecutar una vez? es que resulta que he creado un programa muy basico en el que si pulso un punsador a una variable le suma 1, y un led se enciende solo si la variable vale 1, si vale 0 o mas de 1 deberia de estar apagado, pero una vez que se ha encendido no se vuelve a apagar cuando la variable ya no vale 1. Adjunto el programa

Code: [Select]

int boton=0;
void setup(){
attachInterrupt(digitalPinToInterrupt(2), pulsador, RISING);
pinMode(3,OUTPUT);//salida del led
pinMode(2,INPUT);//Pulsador
}

void loop(){

while(boton==1)
{
digitalWrite(3,HIGH);
}

}

void pulsador()
{
boton++;
}



IgnoranteAbsoluto

#5
Aug 18, 2019, 05:09 pm Last Edit: Aug 18, 2019, 05:40 pm by IgnoranteAbsoluto Reason: Corrección.
La salida digital se mantiene en el último estado que se le diga. Tu ejemplo nunca la pone a nivel bajo. Sólo la pone a nivel alto. Has la prueba de la interrupción con el siguiente loop(), sin el while:

Code: [Select]
void loop() {
  digitalWrite(3, boton % 2);
}


Corrigo el código, por despiste puse % 1 cuando lo correcto es % 2

JMZ96

Lo que has puesto de "boton % 2" que quiero decir? es que nunca he visto eso dentro de un digital write, solo he visto lo de high o low pero lo que has puesto no.

IgnoranteAbsoluto

El segundo parámetro que espera el digitalWrite() es de tipo boolean, eso quere decir que espera un valor "verdadero" o "falso". Si es verdadero pondrá la salida a nivel alto y si es falso lo pondrá a nivel bajo. El quid de la cuestión está en qué considera el C/C++ como "verdadero" o "falso". Aparte de los consabidos true y false, es considerado como "falso" aquello que su valor es cero, y como "verdadero" lo que su valor sea distinto de cero (por ejemplo: -3 sería considerado como "verdadero").

El operador % da como resultado el resto de la división entera. Si calculamos el resto que nos da el dividir un número entero ente 2, para todo entero que sea par nos dará como resto un cero (que se considera como un "falso") y si no es par nos dará un valor diferente de cero (que se considera como un "verdadero") así que la instrucción digitalWrite(3, boton % 2); pondrá a nivel bajo el pin 3 cuando bonton tenga un valor par y la pondrá a nivel alto cuando tenga un valor impar.

Por último, las constantes HIGH y LOW están definidas con el valor 1 y 0 respectivamente. Es aconsejable utilizar, siempre que se pueda, constantes en el código ya que lo hace más fácilmente comprensible. En este caso puse directamente la operación porque iba con prisas y no tenía ganas de escribir mucho. Es más código, pero sería más legible, si hubiera puesto:

Code: [Select]

  if ((boton % 2) != 0) {  // Verifica si el valor de boton es impar
    digitalWrite(3, HIGH); // boton es impar, encendemos el LED
  }
  else {
    digitalWrite(3, LOW); // boton es par, apagamos el LED
  }



Nota: lee las normas del foro y sobre todo la parte que explica cómo formatear el código en el post. Es más cómodo, si el código y los comentarios no excede cierto límite, poner el código directamente en el post (con el formato adecuado) y no capturas de pantalla. Y si pones imágenes es aconsejable hacer que se vean en el post sin necesidad de tener que descargarlas. Todo se explica en las normas que suelen ser la primera publicación de cada sección.

surbyte

Porque abres dos hilos del mismo tema y además en lugar de postear un código pones una imágen del mismo?
Llego tarde porque IgnoranteAbsoluto te respondió pero presta atención porque no es la primera vez que lo haces.
Edita tu post inicial y coloca el código. Con la imagen no importa si se visualiza o no si colocas el código debidamente.

JMZ96

Queria disculparme por no haber posteado correctamente, es la primera vez que entro en un foro,ya me he leido las normas, hay alguna manera de editar el post para ponerlo correctamente?

Respecto a lo que me has comentado de mi duda, lo he entendido lo que me has dicho y me lo he apuntado   dado que desconocía eso. La verdad que el supuesto circuito que he comentado no es lo que quería hacer, lo he dicho para enteder como funcionaba la funcion de interrupcion. El programa real que quiero hacer es que cada vez que pulso el pulsador ejecute un comando diferente, he hecho la prueba con el encendido de leds, cuando pulso una vez se encienda un led, cuado lo pulso por segunda vez se encienda otro y se apague el anterio, y asi sucesivamente con varios leds y esto que he comentado es lo que debería de pasar pero no me funciona.


Code: [Select]


int boton=0;

void setup() {
pinMode(2,INPUT);
pinMode(7,OUTPUT);
pinMode(6,OUTPUT);
pinMode(5,OUTPUT);
attachInterrupt(digitalPinToInterrupt(2), pulsador, RISING);
}

void loop() {
  while(boton==1)
{
  digitalWrite(5,HIGH);
}
  while(boton==2)
{
  digitalWrite(6,HIGH);
}

while(boton==3)
{
  digitalWrite(7,HIGH);
}

digitalWrite(7,LOW);
digitalWrite(6,LOW);
digitalWrite(5,LOW);

}



void pulsador()
{
 boton++;
}


IgnoranteAbsoluto

Tengo la impresión de que estás tratando de matar moscas a cañonazos. Cuando ni tan siquiera saber utilizar un matamoscas.

Este tipo de interrupciones se utilizan para atender cambios de estado de los pines lo más pronto posible, sin dilaciones. Porque podría ser que si tardas una milésima en atender el cambio del pin ya fuera demasiado tarde. No sé a dónde quieres llegar, pero creo que este no es el camino.

Hay una cosa que creo que no has tenido en cuenta, y es el "rebote" de los pulsadores. Cuando un botón mecánico se pulsa, o se suelta, la conexión o desconexión no tiene porqué hacerse "limpiamente" y se puede generar una "ráfaga" de pulsos antes de que el valor se estabilice. Si utilizas las interrupciones para la lectura del pin se puede captar cada pulso independientemente y tener el efecto de que se ha pulsado y soltado varias veces el botón cuando en realidad no es eso lo que quieres. Y aún teniendo pulsaciones "limpias de rebotes" sigo pensando que las interrupciones no son lo que necesitas… Te lo digo sin tener claro qué es "lo que buscas".

Supongamos que tienes "pulsaciones limpias". Con la primera pulsación se cumplirá el primer while, se encenderá el primer LED y permanecerá en ese bucle hasta que realices la segunda pulsación. Esa segunda pulsación hará que se salga del primer while y entre inmediatamente en el segundo, se encienda el segundo LED, y permanecerá en ese segundo bucle hasta que se vuelva a pulsar. En ese momento tendrás los dos primeros LED encendidos. Una nueva pulsación hará que se salga del segundo while y entre acto seguido en el tercero, encendiendo el tercer LED y permaneciendo en ese bucle hasta que se vuelva a pulsar. Mientras no se vuelva a pulsas tendrás ahora los tres LED encendidos. En cuanto pulses una cuarta vez se saldrá del bucle y se apagan los tres LED hasta que vuelvas a pulsar unas 65532 veces más, que se habrá desbordado la variable boton y volverá a valer 1. Porque para cualquier valor que no sean 1, 2 o 3 no vas a encender ningún LED.

Eso si no hay rebotes. Si hay rebotes lo más probable es que se te encienda más de un LED a la vez con una sola pulsación o incluso que se te enciendan todos y se apaguen de una única pulsación porque una pulsación puede tener "rebotes" y a efectos práctico es como si hubieras pulsado varias veces. Basta que la primera pulsación genere tres o más rebotes a parte de la pulsación, para que el Arduino interprete has pulsado cuatro veces o más. Así que se encenderán los tres LED se apagarán inmediatamente. Y permanecerán apagados hasta que se desborde la variable.

Hay librerías para "combatir" los rebotes (debounce, en inglés, es lo que deberías de buscar en Google si estás interesado en ellas). Pero estas librerías no están pensadas para trabajar con interrupciones.

Mi consejo es que te olvides de las interrupciones y que busques documentación sobre millis() y máquinas de estados (podrás encontrar algo en este mismo foro https://forum.arduino.cc/index.php?topic=502735.0) y orientes tus programas a ello. Eso es lo básico en Arduino… Bueno, lo realmente básico es saber programar en C o C++.


JMZ96

Buenos días, te quería comentar que soy consciente de para que sirven las interrupciones y quiero que la tenga el programa, el problema por el cual el programa no funciona bien es por lo que me has dicho de los "rebotes" que no tenía ni idea de eso. Una de las cosas que has dicho es que se puede eliminar los "rebotes" con una librería pero que ésta no sirve si el programa tiene interrupciones, en este caso cómo soluciono los rebotes?

IgnoranteAbsoluto

Pues entonces cambio un poco mi consejo: usa las interrupciones, máquinas de estados y millis().

Si explicas con más detalle lo que quieres hacer te podríamos orientar mejor.

Hace poco he propuesto en este mismo foro esto: https://forum.arduino.cc/index.php?topic=631807.msg4278591#msg4278591

En ese programa sólo hago uso de las interrupciones y una máquina de estados. No uso millis() porque no tiene rebotes ni controla ningún tipo de tiempo. Imagino que no tiene nada que ver con lo que tienes en mente, pero tal vez te de alguna idea.

Una cosa que has de tener en cuenta es que las interrupciones se han de ejecutar rápidamente. Cuanto menos tiempo "esté interrumpido" el micro mejor. "Lo pesado" se ha de hacer "fuera de las interrupciones".

surbyte

Esto resume todo

Quote
Si explicas con más detalle lo que quieres hacer te podríamos orientar mejor.
Y como no has leído las normas o no las has comprendido es que estas conversando sobre interrupciones sin explicar para que las necesitas.
Si resulta que luego solo quieres usar interrupciones porque usas delay() y quieres ver cuando se presiona un interruptor como ultimamente todo el mundo pregunta resulta ser que es un verdadero contrasentido.

Te dejo para tu consideración el punto 11 de las normas

Quote
11.  Tips para obtener mejores respuestas

• Menciona que Arduino tienes. ¿Es un UNO?  ¿Leonardo? ¿Due? ¿Mini? ¿Mega? El problema podría ser específico de cualquiera de estos modelos.
Describe tu problema en detalle.
• Si es relacionado a una pieza electrónica (chip o modulo), menciona el modelo exacto y preferentemente un link al data sheet.
• Describe cómo has conectado cosas como registros.  ¿Los has conectado a tierra? ¿o +5v? ¿Están con resistencias pull-up ó pull-down? Postea el circuito si tienes dudas.
• Agrega el Sketch (código) ¡completo!  Si no lo haces harás perder el tiempo a las personas que te pidan hacerlo. Sin embargo, con problemas de código, si es posible postear un sketch mínimo que reproduzca el problema  - sin cientos de líneas de código. Si el problema se desvanece en el sketch reducido, el error no estaba donde pensabas que estaba.
Y hay mas cosas para explicar/detallar pero pongo éstas como relevantes.

La medición de RPM es muy simple.
Usas una ventana de tiempo de X mseg y cuentas los pulsos dentro de dicho intervalo. Si la frecuencia de dichos pulsos es baja requieres una ventana mayor y si es alta con una menor será suficiente. En general todo lo que se mide por debajo de 1Khz es preferible medirlo de otra forma.
En lugar de contar pulsos se mide el tiempo de un ciclo de estos pulsos. Al ser lento, y medir su periódo (inversa de la frecuencia) lo haces con menor error que midiendo la frecuencia y de modo mas rápido.

Entonces.... habilita interrupciones durante 1000 mseg por ejemplo, cuentas pulsos, y cuando termina la ventana, deshabilitas interrupcones, lees el valor de los pulsos contados y lo presentas o haces el cálculo de las RPM. Re habilitas Interrupciones y de repites todo una y otra vez.




JMZ96

Teneis razón, el problema es que no he explicado el programa. Para empezar, lo que estoy haciendo es  una figura que dentro lleva varios leds, un minialtavoz y un pulsador. Mi idea es que con el mismo pulsador tenga 3 modos de funcionamiento:
1ºNo pulso el pulsador todo está apagado
2ºPulso una vez, se encienden y apagan unos leds amarillos
3ºPulso por segunda vez, ocurre lo mismo que en el modo 2 pero empieza a sonar una musica
4º Pulso por tercera vez, se encienden los leds de antes y otros de color azul y suena otra musica

Si pulso una cuarta vez volvería al estado 1, es decir, todo apagado. El reproductor de musica es el "DFPlayer_mini".
El problema sigue siendo el mismo, que al pulsar una vez es como si hubiera presionado varias veces. También he detectado otro error y es que una vez está ejecutando uno de los modos cuando pulso no pasa a otro modo, sigue ejecutando el mismo modo.

Ahora veréis que el programa es mucho más complejo de lo que os habia preguntado.
Code: [Select]
/*Pines:
 Azul Inferior 7
 Amarillo Inferior 5(PWM)
 Ojos 12
 Azul Superior 4
 Amarillo Superior 3 (PWM)
 Boton 2
 */




#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;




//Variables Luces
int ojos=12, AmaSup=3, UVSup=4, AmaInf=5, UVInf=7, boton=0;//Todo son salidas del arduino que encienden leds, excepto "boton" que es una entrada para el pulsador

//Variables auxiliares y otras de los case
int aux1,ama;//Case 1
int aux2;//Case 2



void setup()
{
//Configuracion pines
pinMode(ojos,OUTPUT);
pinMode(AmaSup,OUTPUT);
pinMode(UVSup,OUTPUT);
pinMode(AmaInf,OUTPUT);
pinMode(UVInf,OUTPUT);
pinMode(2,INPUT);

//Interrupcion para el boton
attachInterrupt(digitalPinToInterrupt(2), pulsador, RISING);

 
 
 
 
 
  //¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡No tocar lo que viene a continuacion, es del DFPlayer(Reproductor de música) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
   }
  myDFPlayer.volume(20);  //Configuracion del volumen, valores de 0 a 30!!!!!!!!!!!!!!!!
   
}








void loop()
{

switch(boton){//Acontinuacion los diferentes modos de funcionamiento


 
  case 0://Todo apagado
  digitalWrite(UVSup,LOW);
  digitalWrite(UVInf,LOW);
  digitalWrite(ojos,LOW);
  analogWrite(AmaSup,0);
  analogWrite(AmaInf,0);
  break;



  case 1://Solo luz amarilla
  while(aux1==0)//Le pongo el while para que el primer "for" solo se ejecute una vez
{
   for(ama=0;ama<=100;ama++)//Este solo para cuando se inicie por primera vez
  {
   delay(50);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
  aux1++;
}
 
  for(ama=100;ama<=255;ama++)
  {
   delay(20);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
delay(1000);//Tiempo de duracion con la luz máxima
   for(ama=255;ama>=50;ama--)
  {
   delay(20);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
  for(ama=50;ama<=100;ama++)
  {
   delay(20);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }

  break;



 
  case 2://Luz amarilla y musica
  while(aux2==0)////Le pongo el while para que el primer "for" solo se ejecute una vez
{
  myDFPlayer.play(1); //Comando para que empiece a sonar la primera cancion
   for(ama=0;ama<=100;ama++)//Este solo para cuando se inicie por primera vez
  {
   delay(50);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
  aux2++;
}
 
  for(ama=100;ama<=255;ama++)
  {
   delay(20);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
delay(1000);//Tiempo de duracion con la luz máxima
   for(ama=255;ama>=50;ama--)
  {
   delay(20);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
  for(ama=50;ama<=100;ama++)
  {
   delay(20);
    analogWrite(AmaSup,ama);
    analogWrite(AmaInf,ama);
  }
  break;

 

  case 3://Todos los efectos(todas las luces y la musica)
//Falta
  break;
}




 

 

 
}

//Funcion para el pulsador
void pulsador()
{
 boton++;
 delay(700);
 if(boton==4)//He supuesto que a la cuarta pulsacion vuelva al estado inicial
 {
  boton=0;
 }
}

Go Up