Problema bucle "for" y reles (SOLUCIONADO)

Hola:
Estoy usando arduino UNO y un modulo rele de 8 canales 5v como este:

Esta placa la alimento con otra fuente aparte a 5V

Utilizo solo dos (por ahora) de esos reles para dar señal a unas electrovalvulas a 220V AC

Pasa lo siguiente:
Si pruebo el codigo sin conectar nada a los reles funciona perfecto.
En el momento que le meto carga a un rele este empieza a traquetear. Acaba acionandose, pero despues de unos segundos con ese ruido caracteristico.

He probrado a alimentar el arduino desde otra fuente como el ordenador portatil (dejando la alimentacion a los reles)...pero el problema persiste.

Lo curioso es que quito el blucle "for" y las acciones de otra manera, con un simple digitalWrite, funcionan los reles perfectamente.

Por lo que estube mirando parece un problema de transistorios. Pero la solucion la daban con un diodo.. y yo tengo corriente alterna.

Os dejo aqui el codigo.

int vaciado = 8;
int llenado = 6;
int puerta = 2;

  void setup() {
  Serial.begin(9600);  
  pinMode(vaciado, OUTPUT);
  pinMode(llenado, OUTPUT);
  pinMode(puerta, INPUT);  
  }
  void loop() {      
        if (digitalRead(puerta)==HIGH){                  
           for (int a = 0; a<=250; a++){
            //bucle de vaciado
            digitalWrite(vaciado, !HIGH);       //vaciamos  agua
            Serial.println ("Vaciado");          
            delay (100);                         //tiempo de vaciado
            }
            digitalWrite(vaciado, !LOW);        //paramos vaciado de agua
            Serial.println ("Paramos vaciado");     
            delay (2000);        
           for (int a = 0; a<=350; a++){        //bucle de llenado
            digitalWrite(llenado, !HIGH);         //cargamos de agua
            Serial.println ("Llenado");          
            delay (100);                             //tiempo de llenado
            }
            digitalWrite(llenado, !LOW);         //paramos carga de agua
            Serial.println ("Paramos llenado");     
            delay (2000);
        }
  }

Alguna idea

PD- se que tengo que usar los timers :frowning:

Hi,
Si ese el problema del for/loop porque no haces el digitalwrite output high antes de entrar al for/loop. Pregunta Para que usas el for loop y como sabes que esta lleno/vacio. Una vez que mandas un comando digitalwrite no lo tienes que repetir otra vez. Con hacerlo una sola vez basta y el puerto se va quedar energizado hasta que no hagas otro digitalwrite output low. Otra cosa es que cuando energizas componentes electromecanicos como selenoides esto prucen ruidos electricos que teines que evtar que se propague al arduino. Hay varios componentes que puedes usar para cancelarlos como snubbers, mov y capacitores.

Hola:
Gracias por responder.
Se que tiene una solucion simple solo con cambiar el codigo,pero me gustaria saber a que se debe el problema.. y como encontrar la solucion. (solucion hardware) :slight_smile:

Gracias

Prueba esto

const byte vaciadoPin = 8;
const byte llenadoPin = 6;
const byte puertaPin  = 2;

bool status;

void setup() {
  Serial.begin(9600);  
  pinMode(vaciadoPin, OUTPUT);
  pinMode(llenadoPin, OUTPUT);
  pinMode(puertaPin, INPUT);  
}

void loop() {      
  status = digitalRead(puertaPin)

  if (status){                  
      //bucle de vaciado
      digitalWrite(vaciadoPin, !HIGH);       //vaciamos  agua
      Serial.println ("Inicio Vaciado");          
      delay (2500);                         //tiempo de vaciadoPin
      digitalWrite(vaciadoPin, !LOW);        //paramos vaciadoPin de agua
      Serial.println ("Paramos Vaciado");     
      delay (2000);        
      //bucle de llenado
      digitalWrite(llenadoPin, !HIGH);         //cargamos de agua
      Serial.println ("Llenado");          
      delay(3500);                            //tiempo de llenadoPin
      digitalWrite(llenadoPin, !LOW);         //paramos carga de agua
      Serial.println ("Paramos llenadoPin");     
      delay (2000);
  }
}

Muchas gracias por responder... surbyte estas en todos los hilos :slight_smile:

El sketch que me pones no me falla..pero es algo curioso lo que pasa. Aqui lo explico.

Si solo se le da una señal, es decir un solo digitalWrite al rele actua sin problemas.

He hecho el codigo con los millis y si que me funciona perfecto, en vacio. Pero con carga en los reles tambien traquetea, no tanto, pero lo hace.
Parece que mientras se cumple la condicion (cual sea) el programa da señal en bucle al rele, y esto parece que no le va bien.
Esta claro que con el delay no pasa eso...pues solo se ejecuta una sola vez un digitalWrite hacia el rele.
EDITO:
Prodando con el motor monofasico con un simple digitalWrite tampoco va, hace un intento (se enciende la luz del rele medio seg), pero ahi se queda. Y todo esto aclarando que en vacio funciona perfecto.
Me da a mi que es un tema de ruidos.
Lo curioso es que si alimento la placa arduino desde un ordenador (donde el ruido no le debia afectar) sigue fallando.
Alguna pista.

Con las electrovalvulas que estoy provando traquetea algo, pero con un motor (monofasico pequeño) ya ni prenden los reles... y siempre funcionando el sketch perfectamente en vacio.

Cosa curiosa

Hi,
Para poder estar seguro los relay son de 5 voltios si/no. Si son de 5 voltios posiblemente al enegizar el coil no tiene suficiente fuerza para cerrar el contacto y dejar pasar la corriente del motor. Esto lo que puede causar es de quemar los contactos. Puedes hacer una prueba y la de cerrar contacto solamente y te va probar si el relay es el correcto para tu aplicacion. Escribe una routina que solamente cierre el relay te vaz a un delay lo apagas y lo repites varia veces. Asi sabras donde esta el problema. Mientras hagas esta pueba lee el voltaje de los 5 voltios y el voltaje de 220 que recibe el motor cuando el relay cierra. Deberias de leer tambien los 220 voltios que suple el motor.Otra cosa que podrias hacer es de leer la resistencia de los coils de las valvulas para asi calcular la corriente que estas usando.

Como bien dices, todo apunta a un problema de ruido.
Has intentado poner un diodo entre el GND y el pin que activa el rele? Siempre que usemos bobinas,debemos evitar los retornos al micro, normalmente estas placas no vienen filtradas.

Hi,
Antykrysto normalmente estos modulos de relays ya tienen su diodo incluido pues ellos usan un transistor para abrir/cerrar los relay. De todas manera es buena tu observacion, El dice que los relays hacen que ss abren/cierran continuamente por cierto tiempo. Cuando esto sucede puede ser que el PS no puede suplir suficiente voltaje para mantenerlos cerrado.Otra cosa que debes de dejarnos saber es la corriente del PS de 5 voltios que alimenta el modulo de los relays. Por eso es de leer el voltaje cuando esto ocurre. Otra cosa que se pasa por alto es de que cuando energizas un componente que tienen inductores como los selenoides , motores y valvulas la corriente inicial puede ser de 2 a 3 veces la corriente normal del componente. Esto a veces no se toma en consideracion al energizarlo. Por ejemplo nosotros surbyte y yo siempre hemos recomendados para prender/apagar motores el mejor componente para este tipo de servicio es el de usar un AC SSR que tenga lo que se conoce como "zero crossing". Este le va prender/apagar el motor cuando el voltaje de AC se encuentra pasando por el zero del voltaje. Esto va a resultar en un switching de voltaje que no produce ruido electricos. Les pido disculpas por la letania de la explicacion arriba descrita.

hola:
Pues tras mucho indagar creo que he encontrado el problema...pero no la solucion

El problema se ve que se da en la interrupcion. Siento mucho que no la puse en el codigo de arriba, tiendo a poner el sketch lo mas simple posible. Sorry.

Respecto al cogido anterior he remodelado el codigo y usado millis, asi me lo habeis recomendado.Pero basicamente es el mismo:

int vaciado = 8;
int bobinaA = 10;
int bobinaT = 11;
int llenado = 6;
int pulsador = 5;
int puerta = 2;
int cont = 0;
int contadormotor = 0;
unsigned long tanterior = 0;
unsigned long tiempo = 0;

void setup() {
  Serial.begin(9600);  
  cont = 0;
  contadormotor == 0;
  pinMode(senalpuerta, OUTPUT);  
  pinMode(vaciado, OUTPUT);
  pinMode(llenado, OUTPUT);
  pinMode(bobinaT, OUTPUT);
  pinMode(bobinaA, OUTPUT);
  pinMode(pulsador, INPUT);
  pinMode(puerta, INPUT);    
  digitalWrite (vaciado, !LOW);
  digitalWrite (llenado, !LOW);
  digitalWrite (bobinaT, !LOW);
  digitalWrite (bobinaA, !LOW);
  attachInterrupt(digitalPinToInterrupt(puerta), PuertaAbierta, LOW);
}

void PuertaAbierta() {  
  contadormotor = 0;                //ponemos contador a cero  
  digitalWrite(bobinaT, !LOW);    //detenemos bobina trabajo
  digitalWrite(bobinaA, !LOW);    //detenemos bobina arranque
  digitalWrite(llenado, !LOW);     //paramos carga de agua
  digitalWrite(vaciado, !LOW);    //paramos vaciado
  Serial.println ("Puertaabierta");
}
  
void loop() {  
  while (cont == 0){    
    tanterior=millis();
    Serial.println ("Esperando orden");   
    if (digitalRead(pulsador)==HIGH){     
      cont = 1;      
      Serial.println ("Entramos en programa");      
      }
  }    
          if((millis()-tanterior>=3000) && (millis()-tanterior<28000)){
            digitalWrite(vaciado, !HIGH);
            Serial.println ("vaciamos");            
          }                    
          if((millis()-tanterior>28000)&& (millis()-tanterior<32000)){
            digitalWrite(vaciado, !LOW);                      
            Serial.println ("paramos vaciado");            
          }
          if((millis()-tanterior>=32000)&& (millis()-tanterior<67000)){
            digitalWrite(llenado, !HIGH);
            Serial.println ("llenamos");                               
          }          
          if((millis()-tanterior>67000)&& (millis()-tanterior<70000)){
            digitalWrite(llenado, !LOW);
            Serial.println ("paramos llenado");                        
          }          
          if((millis()-tanterior>70000) && (millis()-tanterior<95000)){
            if (contadormotor == 0){ 
              digitalWrite(bobinaT, !HIGH);     //arrancamos bomba
              Serial.println ("Arracamos BT");
              digitalWrite(bobinaA, !HIGH);     //arrancamos bomba
              Serial.println ("Arrancamos BA");
              delay (350);                      //retardo para apagar bobina de arranque       
              }
            contadormotor = 1;                  //contador de proteccion para que no funcione la bobina de arranque cuando no debe            
            digitalWrite(bobinaA, !LOW);        //detenemos bobina arranque
            Serial.println ("Paramos BA");                       
          }
          if((millis()-tanterior>95000) && (millis()-tanterior<100000)){
            digitalWrite(bobinaT, !LOW);
            Serial.println ("Paramos bomba");
          }
          if((millis()-tanterior>=100000) && (millis()-tanterior<125000)){
            digitalWrite(vaciado, !HIGH);
            Serial.println ("vaciamos"); 
          }
          if((millis()-tanterior>125000)){
            digitalWrite(vaciado, !LOW);                      
            Serial.println ("programa finalizado");
            cont=0;
          }  
            
}

Las "!" en los digitalWrite es por la logica inversa de los reles.

Pues bien, si yo elimino la interrupcion los reles no traquetean. Es decir, si por ejemplo dejamos la interrupcion asi programada:

void PuertaAbierta() {  
  contadormotor = 0;                //ponemos contador a cero 
  digitalWrite(llenado, !LOW);     //paramos carga de agua
  digitalWrite(vaciado, !LOW);    //paramos vaciado
  Serial.println ("Puertaabierta");
}

Aqui solo me fallarian/traquetearian los reles a los que corresponden dichos digitalWrites.

He medido el voltaje que alimenta al pin 2 de la interrupcion (LOW), a ver si por una caida de votaje llega a entrar dicha interrupcion, pero me da siempre sobre unos 4,9V. Se ve que hay momentos en los que se ejecuta y eso hacer parar el rele. Al momento vuelve al loop y se vuelve accionar... y de ahi el traqueteo.

Se que no me vais a recomendar usar interrupciones, pero me resulta muy comoda dado que me para el sketch en el moment, me bloquea millis, me inicia justo donde se interrmpio....y sobre todo porque esoy muy verde en programacion.

Alguna idea.

  Serial.println ("Puertaabierta");

No puede ni debe estar en una interrupción.. quítalo. Si quieres que haga algo entonces coloca un flag y con ese flag en el loop haras que muestre o no "Puerta abierta"

Eso en pruebas mias por error, me ha generado reinicios, porque usar Serial.print involucra muchos milisegundos y actua el watchdog x defecto del arduino.

Edito 1: si usas interrupciones mas allá que ya te digo que no es necesario no tienes que poner esto

 pinMode(puerta, INPUT);

Ahora te re escribo el código para que prescindas de la interrupción.

Supuse que estas con Resistor pull-up de modo que

int vaciado = 8;
int bobinaA = 10;
int bobinaT = 11;
int llenado = 6;
int pulsador = 5;
int puerta = 2;
int cont = 0;
int contadormotor = 0;
unsigned long tanterior = 0;
unsigned long tiempo = 0;
bool estado, estadoAnt = HIGH;

void setup() {
  Serial.begin(9600);  
  cont = 0;
  contadormotor == 0;
  pinMode(senalpuerta, OUTPUT);  
  pinMode(vaciado, OUTPUT);
  pinMode(llenado, OUTPUT);
  pinMode(bobinaT, OUTPUT);
  pinMode(bobinaA, OUTPUT);
  pinMode(pulsador, INPUT);
  pinMode(puerta, INPUT);
  digitalWrite (vaciado, !LOW);
  digitalWrite (llenado, !LOW);
  digitalWrite (bobinaT, !LOW);
  digitalWrite (bobinaA, !LOW);
  //attachInterrupt(digitalPinToInterrupt(puerta), PuertaAbierta, LOW);
}

void PuertaAbierta() {  
  contadormotor = 0;                //ponemos contador a cero  
  digitalWrite(bobinaT, !LOW);    //detenemos bobina trabajo
  digitalWrite(bobinaA, !LOW);    //detenemos bobina arranque
  digitalWrite(llenado, !LOW);     //paramos carga de agua
  digitalWrite(vaciado, !LOW);    //paramos vaciado
  Serial.println ("Puertaabierta");
}
  
void loop() {  
 
  estado = digitalRead(puerta);
  if (!estado && estadoAnt)
      PuertaAbierta();
  estadoAnt = estado;

  while (cont == 0){    
    tanterior=millis();
    Serial.println ("Esperando orden");   
    if (digitalRead(pulsador)==HIGH){     
      cont = 1;      
      Serial.println ("Entramos en programa");      
      }
  }    
  if ((millis()-tanterior>=3000) && (millis()-tanterior<28000)){
      digitalWrite(vaciado, !HIGH);
      Serial.println ("vaciamos");            
  }                    
  if ((millis()-tanterior>28000)&& (millis()-tanterior<32000)){
      digitalWrite(vaciado, !LOW);                      
      Serial.println ("paramos vaciado");            
  }
  if ((millis()-tanterior>=32000)&& (millis()-tanterior<67000)){
      digitalWrite(llenado, !HIGH);
      Serial.println ("llenamos");                               
  }          
  if ((millis()-tanterior>67000)&& (millis()-tanterior<70000)){
      digitalWrite(llenado, !LOW);
      Serial.println ("paramos llenado");                        
  }          
  if ((millis()-tanterior>70000) && (millis()-tanterior<95000)){
      if (contadormotor == 0){ 
          digitalWrite(bobinaT, !HIGH);     //arrancamos bomba
          Serial.println ("Arracamos BT");
          digitalWrite(bobinaA, !HIGH);     //arrancamos bomba
          Serial.println ("Arrancamos BA");
          delay (350);                      //retardo para apagar bobina de arranque       
      }
      contadormotor = 1;                  //contador de proteccion para que no funcione la bobina de arranque cuando no debe            
      digitalWrite(bobinaA, !LOW);        //detenemos bobina arranque
      Serial.println ("Paramos BA");                       
  }
  if ((millis()-tanterior>95000) && (millis()-tanterior<100000)){
      digitalWrite(bobinaT, !LOW);
      Serial.println ("Paramos bomba");
  }
  if ((millis()-tanterior>=100000) && (millis()-tanterior<125000)){
      digitalWrite(vaciado, !HIGH);
      Serial.println ("vaciamos"); 
  }
  if ((millis()-tanterior>125000)){
      digitalWrite(vaciado, !LOW);                      
      Serial.println ("programa finalizado");
      cont=0;
  }  
}

Hi,
Surbyte Una sugerencia porque no aumentar la velocidad de 9600 a 115200 para mande el mesaje mas rapido. Eso minimizael delay de mandar el mansaje.

y que ganas si lo que envia es una cosa muy corta.
Mira sus msg.. si quiere que lo suba, no cambiará demasiado.

¿pero sigue entando la interrupcion en el codigo?

Mi no entender. Aunque veo que añadiste esto al loop:

surbyte:

void loop() { 

estado = digitalRead(puerta);
  if (!estado && estadoAnt)
      PuertaAbierta();
  estadoAnt = estado;

Creo que pones ese codigo para asi evitar la interrupcion. ¿no? Pero yo quiero que me salte en cualquier momento del loop. De ahi mi interes por la interrupcion.
Tienes que disculparme si no me explico bien.
Muchas gracias ante todo

Hi,
Quiero pedirte un favor y es de que describas como trabaja tu projecto pues todavia no tengo una buena idea de lo que tu quires obtener. Cuando describiste tu problema no explicastes cuantos componentes tienes . Sin embargo en la routina que hizo surbyte aparencen los siguentes. Dices que tienes dos vavulas , un motor, un contacto que no dices como se activa. Como determina cuando el tanque esta vacio y cuando esta lleno. Usa el switche para determinar esto. Hablas de puertas , pulsador, Pero todo esto no lo mencionas en ninguno de tus hilos.

Hola @tauro0221:
Perdona por no explicarlo con atelacion.
Basicamente es el funcionamiento de un lavavajillas. Y es exactamente el sketch de PRELAVADO, por lo que ciertos componentes no entran en "accion". (resitencia y NTC)

Tenemos:
Pulsador - Para que inicie el
Puerta - Contacto que detecta la apertura de la puerta, esta pausará el skech cuando esta se abra.
Llenado - Electrovalvula que permite el llenado de agua (lo gestionamos por tiempo)
Vaciado - Bomba que vacia el agua del lavavajillas (lo gestionamos por tiempo)
BobinaA-
BoninaT- Son las dos bobinas (arranque y trabajo) del motor/bomba. Este tipo de motores usan las dos bobinas, pero solo la de arranque (BoninaA) para el primer impulso, luego esta se desconecta funcionado solo la bobina de trabajo.

Y solo es eso.

Cito otra vez el problema.
El programa funciona perfectamente sin carga, pero en el momento que se le mete carga los reles traquetean.
En dicho programa uso una interrupcion para parar el lavavajillas (Llenado, Vaciado, BoninaA, BobinaT =LOW).
Pues por lo que he visto, con CARGA, la interrupcion se "microejecuta" y da señal a esos reles para que se paren, luego vuelve al loop y da señal HIGH. Y ahi aparece el traqueteo.

Si por ejemplo en dicha interrupcion dejo solo la funcion LOW de Llenado y Vaciado, solo me traquetean esos reles.

He medido la entrada de voltaje a pin de la interrupcion y me da unos constante 4,9V.
Lo primero que me viene a la mente es un problema de ruido.

Si el problema esta en la interrupcion voy intentar hacer el codigo sin la interrupcion. Pero me da rabia no saber donde esta el problema.

Muchas gracias

Yo sinceramente si en vacio funciona bien y cuando aplicas carga en los reles empieza el problema, para mi es blanco y en botella. Tienes un problema muy serio de ruido.
Hay escritos gigas y gigas de como solucionar los problemas de ruido.
Como consejo, tengo una emrpesa de reparaciones indusriales. Es que usaras algun tipo de sensor de nivel de agua para el ciclo de llenado. Se podria atascar la entrada de agua o cortarse el suministro y eso provocaria que la bomba funcionara en vacio, con el consiguiente riesgo de rotura o incendio.
Se me ocurre si es un domestico que uses el propio sensor del pozo, si fuera un industrial la misma campana presostatica te serviria.

//attachInterrupt(digitalPinToInterrupt(puerta), PuertaAbierta, LOW);

Si algo esta comentado no funciona, como puedes decir que la rutina de interrupcción funciona?
Si la llamo para que haga lo que deba hacer cuando el pin 2 cae a low, pero a diferencia tuya lo hago solo cuando el flanco pasa de 1 a 0 y no como en tu caso con LOW que tal vez fuera tu gran error.

De todos modo lo que te muestro es que JAMAS necesitas usar interrupciones para algo tan simple como accionar 4 salidas al estado que sea.
Claro que no lo sabes y estas aprendiendo.

Ahora veré como modificar el código para que tenga en cuenta tu loop.
A ver si esto satisface tu criterio.

void loop() {  
  
  while (cont == 0){    
    tanterior = millis();
    Serial.println ("Esperando orden");   
    estado = digitalRead(puerta);
    if (!estado && estadoAnt)
        PuertaAbierta();
    estadoAnt = estado;
    if (digitalRead(pulsador)){     
      cont = 1;      
      Serial.println ("Entramos en programa");      
    }
  }

Reemplaza esta parte y el resto del programa igual.

Comparto el criterio que tienes ruido generado por motores, bobinas, etc.
Asi que vas a tener que trabajar en cada caso.

Antykrysto:
Yo sinceramente si en vacio funciona bien y cuando aplicas carga en los reles empieza el problema, para mi es blanco y en botella. Tienes un problema muy serio de ruido.

Tengo que indargar a ver como elemino ese ruido.

Antykrysto:
Es que usaras algun tipo de sensor de nivel de agua para el ciclo de llenado. Se podria atascar la entrada de agua o cortarse el suministro y eso provocaria que la bomba funcionara en vacio, con el consiguiente riesgo de rotura o incendio.
Se me ocurre si es un domestico que uses el propio sensor del pozo, si fuera un industrial la misma campana presostatica te serviria.

Muchas gracias por responder, el lavavajillas tiene un detector de presion/agua pero va en serie con la resistencia. (si no hay agua no funciona la resistencia) pero si que es verdad que no afecta a la bomba, y esta prodria funcionar en vacio.
Tienes toda la razon pero tengo que hacer el sketch poco a poco, porque ya aun siendo "sencillo" me esta dando mucho trabajo.

surbyte:
Ahora veré como modificar el código para que tenga en cuenta tu loop.
A ver si esto satisface tu criterio.

Te lo agradezco, pero no te preocupes que tarde o temprano lo programaré.
De hecho ya lo tengo funcionado sin usar la interrupcion y parandome el programa en el momento que se abre la puerta.

Lo que me resultaba "comodo" de la interrupion es que al ejecutarse, al margen de parar el programa, me para la funcion millis(), es decir que cuando volvia al loop empezaba justo donde se "pauso"

Ahora lo me para pero millis() sigue corriendo. Evidente es un tema de programacion. Ya lo sacaré

Ante todo gracias a todos por vuestra ayuda.

Hi,
Muchas gracias por tu explicacion ahora tengo una idea completa de tu projecto. Ahora veo un problema con el motor pues estas usando un motor con un embobinado para prenderlo y el otro para correr continuo. Tienes que prender el de empezar por un tiempo al mismo tienpo empezar el de correr y apagar el de empezar, Creo que esos relay de 5 voltios que usas no son los correctos pues el voltaje de los coils es muy bajo. Todos los motores los prenden con un relay de 24 voltios.Si miras los aires acondiciobado los prenden con relay de 24 voltios. Deberias de usal AC SSR con zero crossing esto te permite hacerlo sin causar mucho ruido. Puedes usar uno para prender los dos coils y el otro papa contrlolar el de prender y despues de un delay lo apagas.
adjunto un squematico de como hacerlo pero en vez de usar relay mecanicos usas AC SSR zero crossing relays.