Arduino a bloquear / reiniciar por si

Boa noite!

Estou a fazer uma montagem para brincar com uma caldeira de vapor. Nesse contexto, tenho uma sonda que leio com o arduino, converto para uma gama de 0 a 5V para controlar a entrada de água. Para os niveis de segurança e resistencia de aquecimento, uso entradas e saídas digitais.
O código que fiz inicialmente, funciona e faz o esperado. No entanto, suponho que deve ter uma falha qualquer que não consigo identificar, uma vez que o arduino está a reiniciar ou bloquear (já o fez com o aquecimento ligado e fez abrir a valvula de segurana) com o visor a ficar maluco ou "freeze".
O código está em anexo. Se alguém me puder dar umas dicas, agradeço.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display



int nivel;
int valor;
float voltage;
void setup()
{
  lcd.init();
  lcd.backlight();

  pinMode(2,  INPUT_PULLUP); // nivel baixo ok
  pinMode(3,  INPUT_PULLUP); //pressostato

  pinMode(7, OUTPUT);  // Rele Bomba Agua
  pinMode(8, OUTPUT);  // Rele Bomba Agua
  pinMode(9, OUTPUT);  // Rele Bomba Agua
  pinMode(10, OUTPUT); // Aquecimento
  pinMode(11, OUTPUT); // Aquecimento
  pinMode(12, OUTPUT); // Aquecimento
  pinMode(6, OUTPUT); // Verde
  digitalWrite(7, HIGH); // Rele Bomba Agua
  digitalWrite(8, HIGH); // Rele Bomba Agua
  digitalWrite(9, HIGH); // Rele Bomba Agua
  digitalWrite(10, HIGH);// Aquecimento
  digitalWrite(11, HIGH);  // Aquecimento
  digitalWrite(12, HIGH); // Aquecimento
  digitalWrite(6, HIGH); //LED Verde
  lcd.setCursor(0, 0);
  lcd.print("Caldeira II");
  lcd.setCursor(0, 1);
  lcd.print("Software-Jan2019");
  delay(1000);


}
void loop()
{

  int nivel = digitalRead(3);
  int pressao = digitalRead(2);
  int valor = analogRead(A0);
  float voltage = valor * (5.0 / 1020.0);
  if (nivel == LOW)
  {
    operacao();
  }
  else
  {
    stopseguranca();
    //    digitalWrite(7, LOW); // Rele Bomba Agua
    //    digitalWrite(8, LOW); // Rele Bomba Agua
    //    digitalWrite(9, LOW); // Rele Bomba Agua
    //    digitalWrite(10, HIGH);// Aquecimento
    //    digitalWrite(11, HIGH);  // Aquecimento OFF
    //    digitalWrite(12, HIGH); // Aquecimento OFF
    //    digitalWrite(6, HIGH); //LED Verde OFF
    //    lcd.clear();
    //    lcd.setCursor(0, 0);
    //    lcd.print("Nivel inseguro");
    //    lcd.setCursor(0, 1);
    //    String datastring = "Disabled " + String(voltage) + " V";
    //    lcd.print(datastring);
    //    delay(1000);

  }
}


//////////////////////////////////////////////////////////////////////////////
///////////////////Funções auxiliares/////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void operacao ()
{
  int nivel = digitalRead(3);
  int pressao = digitalRead(2);
  int valor = analogRead(A0);
  float voltage = valor * (5.0 / 1020.0);
  if (voltage < 3.1)
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Entrada de agua");
    meteagua();
    if (pressao == LOW)
    {

      lcd.setCursor(0, 1);
      String datastring = "A aquecer " + String(voltage) + " V";
      lcd.print(datastring);
      aquece ();

    }
    else
    {
      lcd.setCursor(0, 1);
      String datastring = "Aqueci/off " + String(voltage) + "V";
      lcd.print(datastring);
      stopaquece();

    }
    meteagua();

  }
  else
  {
    lcd.clear();
    lcd.print("Nivel alto oK");
    stopagua();
    if (pressao == LOW)
    {
      lcd.setCursor(0, 1);
      String datastring = "A aquecer " + String(voltage) + " V";
      lcd.print(datastring);
      aquece();
    }
    else
    {
      lcd.setCursor(0, 1);
      String datastring = "Aqueci/off " + String(voltage) + "V";
      lcd.print(datastring);
      stopaquece();
    }
    stopagua();

  }

}
void aquece () {
  digitalWrite(10, LOW);  // Aquecimento On
  digitalWrite(11, LOW); // Aquecimento On
  digitalWrite(12, LOW); //LED Verde On
  delay (1000);
}

void meteagua()
{
  digitalWrite(7, LOW); // Rele Bomba Agua
  digitalWrite(8, LOW); // Rele Bomba Agua
  digitalWrite(9, LOW); // Rele Bomba Agua
  digitalWrite(6, HIGH); //LED Verde OFF
  delay (1000);
}
void stopaquece () {
  digitalWrite(10, HIGH);  // Aquecimento On
  digitalWrite(11, HIGH); // Aquecimento On
  digitalWrite(12, HIGH); //LED Verde On
  delay (1000);
}

void stopagua()
{
  digitalWrite(7, HIGH); // Rele Bomba Agua
  digitalWrite(8, HIGH); // Rele Bomba Agua
  digitalWrite(9, HIGH); // Rele Bomba Agua
  digitalWrite(6, LOW); //LED Verde OFF
  delay (1000);
}

void stopseguranca () {
  digitalWrite(10, HIGH);  // Aquecimento Off
  digitalWrite(11, HIGH); // Aquecimento off
  digitalWrite(12, HIGH); //LED Verde off
  lcd.clear();
  lcd.print("Nivel inseguro");
  lcd.setCursor(0, 1);
  lcd.print("falha de nivel");
  digitalWrite(7, LOW); // Rele Bomba Agua
  digitalWrite(8, LOW); // Rele Bomba Agua
  digitalWrite(9, LOW); // Rele Bomba Agua
  digitalWrite(6, HIGH); //LED Verde OFF
  delay (1000);

}

Como estás a controlar a válvula ou o aquecimento?
Relés?

Como estás a alimentar a placa?

A saída é com 2 relés (ligados em série para que se um colar, o outro interrompa), para cada função em separado.
A placa é alimentada com um carregador de telemóvel de 5V 2A.
A obtenção dos níveis é efectuada com 2 relés de nível (antes, o nível mais alto era obtido uma sonda de 0 a 5V).

O Novo código, mais simples e com menos saídas:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

int pressao;
int nivelbaixo;
int nivelalto;

void setup()
{
  lcd.init();
  lcd.backlight();
  pinMode(3,  INPUT_PULLUP); //pressostato
  pinMode(4,  INPUT_PULLUP); // Nível baixo oko
  pinMode(5,  INPUT_PULLUP); // nivel Alto

  pinMode(8, OUTPUT);  // Rele Bomba Agua
  pinMode(9, OUTPUT);  // Rele Bomba Agua
  pinMode(10, OUTPUT); // Aquecimento
  pinMode(11, OUTPUT); // Aquecimento


  digitalWrite(8, HIGH); // Rele Bomba Agua
  digitalWrite(9, HIGH); // Rele Bomba Agua
  digitalWrite(10, HIGH);// Aquecimento
  digitalWrite(11, HIGH);  // Aquecimento

  lcd.setCursor(0, 0);
  lcd.print("Caldeira II");
  lcd.setCursor(0, 1);
  lcd.print("Software-Jan2019");
  delay(1000);


}


//////////////////////////////////////////////////////////////////////////////
///////////////////Funções auxiliares/////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

void operacao ()
{
  int pressao = digitalRead(3);
  delay(100);
  int nivelbaixo = digitalRead(4);
  delay(100);
  int nivelalto = digitalRead(5);
  delay(100);
  if (nivelalto == HIGH)
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Agua a entrar");
    meteagua();
    if (pressao == LOW)
    {

      lcd.setCursor(0, 1);
      lcd.print("Aquecimento ON");
      aquece ();

    }
    else
    {
      lcd.setCursor(0, 1);

      lcd.print("Aquecimento OFF");
      stopaquece();

    }

  }
  else
  {
    lcd.clear();
    lcd.print("Bomba STOP OK");
    stopagua();
    if (pressao == LOW)
    {
      lcd.setCursor(0, 1);
      lcd.print("Aquecimento ON");
      aquece();
    }
    else
    {
      lcd.setCursor(0, 1);
      lcd.print("Aquecimento OFF");
      stopaquece();
    }

  }

}
void aquece () {
  digitalWrite(10, LOW);  // Aquecimento On
  digitalWrite(11, LOW); // Aquecimento On

  delay (1000);
}

void meteagua()
{ digitalWrite(8, LOW); // Rele Bomba Agua
  digitalWrite(9, LOW); // Rele Bomba Agua

  delay (1000);
}
void stopaquece () {
  digitalWrite(10, HIGH);  // Aquecimento On
  digitalWrite(11, HIGH); // Aquecimento On

  delay (1000);
}

void stopagua()
{

  digitalWrite(8, HIGH); // Rele Bomba Agua
  digitalWrite(9, HIGH); // Rele Bomba Agua

  delay (1000);
}




//////////////////////////////////////////////////////////////////////////////
///////////////////Funções main /////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////




void loop()
{
  int pressao = digitalRead(3);
  delay(100);
  int nivelbaixo = digitalRead(4);
  delay(100);
  int nivelalto = digitalRead(5);
  delay(100);
  if (nivelbaixo == LOW) // tem de estar shuntado para funcionar
  {
    operacao();
  }
  else
  {
    digitalWrite(10, HIGH);  // Aquecimento Off
    digitalWrite(11, HIGH); // Aquecimento off

    lcd.clear();
    lcd.print("Sistema Desactivo");
    lcd.setCursor(0, 1);
    lcd.print("Entrar mta agua");

    digitalWrite(8, LOW); // Rele Bomba Agua
    digitalWrite(9, LOW); // Rele Bomba Agua

    delay (1000);
  }
}

Experimenta colocar condensadores na alimentação que tens.

O que costuma acontecer (e aparecem posts aqui de 3 em 3 meses sobre isso), é que ao comutar, o relé consome um pico de corrente que faz a tensão baixar e cria confusão no Arduino.

Ainda pensei que pudesse ser alguma incoerencia do código, que pudesse estar a fazer alguma leitura de valores com algum overflow devido a mau debouncing. Por outro lado, poderia ser ruído na entrada do sinal e por isso fiz um filtro RC passa-baixo para tentar limitar o ruído, com 270 Ohm e 1uF, o que dá uns 70Hz de freq de corte, mas n tive sorte. Agora vou experimentar uma fonte 9V e alimentar pelo JACK. Tenho uma outra dúvida, mas vou abrir outra thread.

se fonte de 9V é uma pilha, escusas de experimentar. Não vai funcionar.

bubulindo:
se fonte de 9V é uma pilha, escusas de experimentar. Não vai funcionar.

9V 1A é de uma box Octal das antigas.
(ainda não tive tempo de voltar a mexer nisso, mas logo que tenha feedback, actualizo).