Bloqueo de Arduino por comunicación serie [SOLUCIONADO]

Hola a todos,

Quería exponeros mi problema, a ver si me ilumináis con una solución:

Tengo un Arduino Mega 2560 que lee varios sensores de presión y namures de presencia.
También está conectado a una placa de 8 relés, los cuales activan unos motores industriales.
Arduino Mega también se conecta por el puerto USB con un PC y un programa de Visual Basic 6.0, el cual manda instrucciones a Arduino para controlar los relés.

El problema es que, muy esporadicamente, la conexión entre Arduino y el PC se bloquea, y esto conlleva que Arduino pone sus salidas digitales a 0 y activa todos los relés, algo que no se puede dar porque estos relés controlan varios motores y sus sentidos de giro, y provoca que salten los diferenciales.

Inclusive reseteando Arduino, no se soluciona el problema, la única solución que de momento funciona es desconectar el cable USB y volver a conectar.

Os pongo parte del código (no puedo incluir más de 9500 caracteres en el post):

#include <Serial.h>
#include <IRremote.h>

//Constantes
const int namurIpre = 30; 
const int namurDpre = 28; 
const int namurImov = 26;
const int namurDmov = 32; 
const int namurAliEntrada = 25; 
const int namurAliSalida = 27; 
const int rele01 = 41; 
const int rele02 = 42; 
const int rele03 = 43; 
const int rele04 = 44; 
const int rele05 = 45;
const int rele06 = 46;
const int rele07 = 47;
const int rele08 = 48;
const int resetear = 10;
const int RECV_PIN = 12; // Entrada de mando a distancia

//Variables
byte dataOut[52]; 
byte dataIn; 
byte setState[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 
boolean responder = false;
unsigned int contador = 0; 
int estadoNamurIzq = 0; 
int estadoNamurIzqAnterior = 0; 
int estadoNamurDer = 0; 
int estadoNamurDerAnterior = 0;
unsigned long tiempoNamurIzq = 0; 
unsigned long tiempoNamurIzqAnterior = 0;
unsigned long tiempoNamurIzqPulso = 0; 
unsigned int tiempoNamurDer = 0; 
unsigned int tiempoNamurDerAnterior = 0; 
unsigned int tiempoNamurDerPulso = 0; 
int lectura = 0;
IRrecv irrecv(RECV_PIN); 
decode_results results; 
unsigned long control = 2263073215; 
unsigned long dato; 
boolean dentro = false; 
byte mandoByteAlto = 0; 
byte mandoByteBajo = 0; 
unsigned int AD1 = 0; 
unsigned int AD2 = 0;
unsigned int AD3 = 0; 
unsigned int AD4 = 0; 
unsigned int AD5 = 0; 
unsigned int AD6 = 0; 

//Setup
void setup(){
  pinMode(resetear, OUTPUT);
  digitalWrite(resetear, LOW);
  delay(5);
  digitalWrite(resetear, HIGH);
  pinMode(namurIpre, INPUT);
  pinMode(namurDpre, INPUT);
  pinMode(namurImov, INPUT);
  pinMode(namurDmov, INPUT);
  pinMode(rele01, OUTPUT);
  digitalWrite(rele01, HIGH);
  pinMode(rele02, OUTPUT);
  digitalWrite(rele02, HIGH);
  pinMode(rele03, OUTPUT);
  digitalWrite(rele03, HIGH);
  pinMode(rele04, OUTPUT);
  digitalWrite(rele04, HIGH);
  pinMode(rele05, OUTPUT);
  digitalWrite(rele05, HIGH);
  pinMode(rele06, OUTPUT);
  digitalWrite(rele06, HIGH);
  pinMode(rele07, OUTPUT);
  digitalWrite(rele07, HIGH);
  pinMode(rele08, OUTPUT);
  digitalWrite(rele08, HIGH);
  pinMode(RECV_PIN, INPUT);
  
  Serial.begin(19200);
  Serial1.begin(57600);
  irrecv.enableIRIn(); // Se inicializa la recepción del mando a distancia
  delay(200);
}

//Principal
void loop(){
  //Lee el puerto serie. Si es un comando, guarda la información en los registros correspondientes
  leerPuertoSerie();
  //Actualiza el estado de los motores activando y desactivando los relés correspodientes
  actualizaEstadoMotores();
  //Control contador de vueltas de namur de resbalamiento izquierdo y tiempo entre pulsos de ambos namures
  controlContadorNamur();
  //Lectura de galgas de presión provenientes de otro Arduino
  lecturaGalgas();
  //Si el PC está esperando uan respuesta, se genera y se envía
  respuesta();
  //Control para imprimir por puerto serie la trama 0x81 enviando un 1
  //imprimirPuertoSerie();
  delay(5);
}

//Subprogramas
//Escribe en el puerto serie la trama del comando 0x81
int escribirPuertoSerie(){
  Serial.write(dataOut, sizeof(dataOut));
  //Serial.write(dataOut[0]);
  return 0;
}

//Lee el puerto serie. Si es un comando, guarda la información en los registros correspondientes
int leerPuertoSerie(){
  //Se comprueba si hay datos en el puerto serie
  if (Serial.available() > 0){
    //Si hay datos, se lee el primer byte, que debe ser un 0
    dataIn = Serial.read();
    //Se lee el segundo byte, que contiene el comando de instrucción
    //dataIn = Serial.read();
    //Si el segundo byte es 0x80, son instrucciones de estado
    if (dataIn == 0x80){
      setState[2] = Serial.read(); //Segundo byte (Rele high byte)
      setState[3] = Serial.read(); //Tercer byte (Rele low byte)
      setState[4] = Serial.read(); //DAC 1      
      setState[5] = Serial.read(); //DAC 2
      setState[6] = Serial.read(); //DAC 3
      setState[7] = Serial.read(); //DAC 4
      setState[8] = Serial.read(); //CheckSum
      //Se debe responder con el comando 0x81
      responder = true;
    }
     }    
    //Se vacía el buffer del puerto serie
    Serial.flush();
  }
  return 0;
}

//StatusData Cmd 0x81 52 bytes
int statusData(){
  dataOut[0] = 0x00;
  dataOut[1] = 0x81;
  //Sensores namures (1-2)
  dataOut[2] = namurAlto();
  dataOut[3] = namurBajo();
  //Digital Input
  dataOut[4] = 0x00;
  //Remote Control
  //mandoControlRemoto();
  dataOut[5] = mandoByteAlto;
  dataOut[6] = mandoByteBajo;
  dataOut[7] = 0x00;
  dataOut[8] = 0x00;
  //Left wheel speed
  dataOut[9] = highByte(tiempoNamurIzqPulso);
  dataOut[10] = lowByte(tiempoNamurIzqPulso);
  //Rigth wheel speed
  dataOut[11] = highByte(tiempoNamurDerPulso);
  dataOut[12] = lowByte(tiempoNamurDerPulso);
  //Left wheel count
  dataOut[13] = highByte(contador);
  dataOut[14] = lowByte(contador);
  //Left motor speed
  dataOut[15] = 0x00;
  dataOut[16] = 0x00;
  //Rigth motor speed
  dataOut[17] = 0x00;
  dataOut[18] = 0x00;
  //AD1
  dataOut[19] = highByte(AD1);
  dataOut[20] = lowByte(AD1);
  //AD2
  dataOut[21] = highByte(AD2);
  dataOut[22] = lowByte(AD2);
  //AD3
  dataOut[23] = highByte(AD3);
  dataOut[24] = lowByte(AD3);
  //AD4
  dataOut[25] = highByte(AD4);
  dataOut[26] = lowByte(AD4);
  //AD5
  dataOut[27] = highByte(AD5);
  dataOut[28] = lowByte(AD5);
  //AD6
  dataOut[29] = highByte(AD6);
  dataOut[30] = lowByte(AD6);
  //AD7
  dataOut[31] = 0x00;
  dataOut[32] = 0x00;
  //AD8
  dataOut[33] = 0x00;
  dataOut[34] = 0x00;
  //AD9
  dataOut[35] = 0x00;
  dataOut[36] = 0x00;
  //AD10
  dataOut[37] = 0x00;
  dataOut[38] = 0x00;
  //AD11
  dataOut[39] = 0x00;
  dataOut[40] = 0x00;
  //AD12
  dataOut[41] = 0x00;
  dataOut[42] = 0x00;
  //Left wheel speed bit 31-24
  dataOut[43] = 0x00;
  //Left wheel speed bit 23-16
  dataOut[44] = 0x00;
  //Left wheel speed bit 15-8
  dataOut[45] = 0x00;
  //Left wheel speed bit 7-0
  dataOut[46] = 0x00;
  //Rigth wheel speed bit 31-24
  dataOut[47] = 0x00;
  //Rigth wheel speed bit 23-16
  dataOut[48] = 0x00;
  //Rigth wheel speed bit 15-8
  dataOut[49] = 0x00;
  //Rigth wheel speed bit 7-0
  dataOut[50] = 0x00;
  //CheckSum Sum(n Bytes) XOR 0xFF
  dataOut[51] = 0x00;
  int i;
  for(i=0; i<sizeof(dataOut)-1; i++){
    dataOut[52] = dataOut[52] + dataOut[i];
  }
  dataOut[52] = dataOut[52] ^ 0xFF; //XOR 0xFF;
  //Return
  return 0;
}

//Actualiza el estado de los motores activando y desactivando los relés correspodientes
int actualizaEstadoMotores(){
  //Motores en rele low byte
  if (bitRead(setState[3], 0) == 1){ //Relé 01
    digitalWrite(rele01, LOW);
  }
  else{
    digitalWrite(rele01, HIGH);
  }
  if (bitRead(setState[3], 1) == 1){ //Relé 02
    digitalWrite(rele02, LOW);
  }
  else{
    digitalWrite(rele02, HIGH);
  }
  if (bitRead(setState[3], 2) == 1){ //Relé 03
    digitalWrite(rele03, LOW);
  }
  else{
    digitalWrite(rele03, HIGH);
  }
  if (bitRead(setState[3], 3) == 1){ //Relé 04
    digitalWrite(rele04, LOW);
  }
  else{
    digitalWrite(rele04, HIGH);
  }
  if (bitRead(setState[3], 4) == 1){ //Relé 05
    digitalWrite(rele05, LOW);
  }
  else{
    digitalWrite(rele05, HIGH);
  }
  if (bitRead(setState[3], 5) == 1){ //Relé 06
    digitalWrite(rele06, LOW);
  }
  else{
    digitalWrite(rele06, HIGH);
  }
  if (bitRead(setState[3], 6) == 1){ //Relé 07
    digitalWrite(rele07, LOW);
  }
  else{
    digitalWrite(rele07, HIGH);
  }
  if (bitRead(setState[3], 7) == 1){ //Relé 08
    digitalWrite(rele08, LOW);
  }
  else{
    digitalWrite(rele08, HIGH);
  }
  
  return 0;
}


//Lectura de galgas de presión provenientes de otro Arduino
int lecturaGalgas(){
  if (Serial1.available() > 0) {           
      AD1 = Serial1.read();
      delay(1);
      AD1 = AD1 + (Serial1.read() * 256);
      AD2 = Serial1.read();
      delay(1);
      AD2 = AD2 + (Serial1.read() * 256);
      AD3 = Serial1.read();
      delay(1);
      AD3 = AD3 + (Serial1.read() * 256);
      AD4 = Serial1.read();
      delay(1);
      AD4 = AD4 + (Serial1.read() * 256);
      AD5 = Serial1.read();
      delay(1);
      AD5 = AD5 + (Serial1.read() * 256);
      AD6 = Serial1.read();
      delay(1);
      AD6 = AD6 + (Serial1.read() * 256);
      Serial1.flush();
    }
  return 0;    
}
  
Espero preguntas y dudas, a ver si me ayudáis a solucionar.

Un saludo,

Hola NaneBL.

Motores industriales ....? seguro que generan mucho picos a la hora de conmutar esos relees, y es eso por lo que se te bloquea el arduino, mira de colocar filtros a esos relees.

me imagino un grupo de relees que por la parte DC ya vienen con sus filtros (diodos y opto), y además con sus 2 voltages DC para el control de la maniobra, pero por la parte AC que filtros tienes para los picos?

infórmate sobre varistores y filtros snubers los cuales te absorberán esos picos en la parte AC

Saludos.

pacoooh:
Hola NaneBL.

Motores industriales ....? seguro que generan mucho picos a la hora de conmutar esos relees, y es eso por lo que se te bloquea el arduino, mira de colocar filtros a esos relees.

me imagino un grupo de relees que por la parte DC ya vienen con sus filtros (diodos y opto), y además con sus 2 voltages DC para el control de la maniobra, pero por la parte AC que filtros tienes para los picos?

infórmate sobre varistores y filtros snubers los cuales te absorberán esos picos en la parte AC

Saludos.

La verdad que aun no lo tengo conectado a los motores. Estoy haciendo pruebas. Estos relés accionarán unos contactores, y en esos contactores, van conectados los motores industriales, pero aun no están conectado a nada los relés.

Pues no se... umm se me ocurre que compruebes si el serial esta bien y si no lo finalices y lo vuelvas a arrancar a ver si suena la campana

coloca este código a ver si te funciona

.........
if (!Serial){Serial.end(); 
  Serial.begin(9600); delay(3); }

}  /FIN DEL LOOP

saludos

Hola

¿Chequeaste el consumo de energía en la placa Arduino y lo que se alimenta desde ahi?
Es que hay muchas consultas en el foro similares al tuyo: placas que se cuelgan después de un rato de andar bien.
La mayoría de las veces es el regulador de voltaje de la placa, que corta para evitar un sobrecalentamiento (y creo arranca al rato).

Saludos.

perrociego:
Hola

¿Chequeaste el consumo de energía en la placa Arduino y lo que se alimenta desde ahi?
Es que hay muchas consultas en el foro similares al tuyo: placas que se cuelgan después de un rato de andar bien.
La mayoría de las veces es el regulador de voltaje de la placa, que corta para evitar un sobrecalentamiento (y creo arranca al rato).

Saludos.

La verdad que no chequeé el consumo de energía, y estoy alimentando bastantes cosas (6 sensores hx711, 4 namures de presencia, placa de 8 relés), así que voy a crear otro circuito externo de alimentación para todos los sensores y demás, a ver si así evito el bloqueo. Os cuento como fue.

Un saludo,

La placa Arduino no puede manejar una corriente de mas de 200mA entre todas sus salidas, tiene toda la pinta de ser un caso de desconexión por sobrecarga del circuito de alimentación, como te indica Perrociego. La solución de crear un circuito paralelo de alimentación me parece que será la mejor ...no olvides unir las masas.

1 Like

Confirmo que haciendo un circuito paralelo e independiente para alimentar todos los sensores (6 galgas de peso y 4 namures de presencia) no se bloquea Arduino.

Gracias a todos. Un saludo,