Problemas con código para una tarjeta de fabricador de hielo

que tal gente, me encuentro con un problema en un código y necesito su ayuda

no puedo hacer que el programa haga la secuencia como debe aqui les dejo el proyecto

Tarjeta para fabricador de hielo

Se tiene un fabricador de hielo marca Manitowoc modelo QM30 el cual no tiene tarjeta de control por ende se decide fabricar ya que la misma no se encuentra o es muy costosa.
El mismo posee:
1 compresor
1 Bomba de agua – 1 Ventilador (trabajando en paralelo controlados por un relay)
1 Válvula solenoide de gas – 1 Válvula solenoide de agua (trabajando en paralelo controlados por un relay)
1 Termistor NTC de 10k
1 switch de 3 posiciones ( ON – OFF - WASH)
1 Termostato

Se desea que un controlador Atmega322p haga lo siguiente:

  1. Revisión del Termistor, si el termistor está en mal estado entonces arroje un error con 3 pitidos continuos, si no que siga al siguiente paso.
  2. verificación de la posición de switch si esta en OFF el equipo permanecerá apagado, si esta en wash procederá a activar solo la bomba de agua y las válvulas solenoide de gas-agua durante 20 min para que el usuario realice el mantenimiento del mismo, posteriormente se apague la bomba de agua, las válvulas y emita un sonido indicando que el ciclo a finalizado.
  3. Si el switch está en ON entonces:
    • Verifique el termostato, si está en OFF (ABIERTO) el equipo permanecerá en standby de lo contrario, si esta ON (CERRADO) pasara al siguiente paso
    • INITIAL STAR UP
    • Encienda solo la válvula de gas – agua
    • Espere 2.9 min
    • Active el compresor y bomba de agua.
    • Espere 5 segundos y apague la válvula gas – agua (PARA INICIAR EL CICLO DE FABRICACIÓN DE HIELO)
    • Cuando la temperatura alcance los 0 °C el punto donde los cubos de hielo están bien formados entonces:
    • Apague la bomba de agua
    • Espere 2 segundos y encienda la válvula de Gas –Agua (esto hace que se despeguen los cubos de hielo y caigan a la bandeja).
    • Cuando la temperatura llegue a 12 °C Apague la válvula de gas - agua
    • Espere 2 segundos y encienda la bomba de agua (reiniciando el ciclo de fabricación de hielo)
    • Este siclo se mantendrá mientras que el termostato este en ON (CERRADO) al pasar a OFF (ABIERTO. Esto indica que la bandeja de hielo está llena ) el equipo se apagara hasta que se vuelva a cerrar dicho termostato cuando esto suceda volverá nuevamente al siclo del INITIAL STAR UP

El problema es que no puedo hacer que el programa haga la secuencia como debe en el inicio o initial star up hace los cambios muy rápido, quisiera de su ayuda para ver en que me estoy equivocando o que me falta de la programación, creo que es por la funcion while que no la e escrito bien. se que aun le falta al codigo pero puse este para que vean cual es el código en el que estoy trabajando. si lo pueden revisar y orientarme se los agradecería

Aqui les dejo el codigo

#include <math.h>

int ThermistorPin = 0;
int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
int counter;

void setup()
{
  Serial.begin(9600);
  pinMode(11, OUTPUT);  //Buzer
  pinMode(12, OUTPUT);  //Valvula de gas
  pinMode(8, OUTPUT);   //Compresor
  pinMode(13, OUTPUT);   //Bomba de agua   
  pinMode(A0, INPUT);    //Termistor
  pinMode(2, OUTPUT);   //Termostato
}

void loop()
{
  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  Tc = T - 273.15;
  Tf = (T * 9.0)/ 5.0 + 32.0;
  
  Serial.println();
  Serial.print("TEMPERATURA = ");
  Serial.print(Tc);
  Serial.println(" c");
  
   
  analogRead(ThermistorPin);
  
   if (Tc <= -20 || Tc >= 50) {
    tone(11, 554, 300); // play tone 61 (C#5 = 554 Hz)
    delay(200); // Wait for 200 millisecond(s)
    noTone(11);
    delay(200); // Wait for 200 millisecond(s)
    tone(11, 523, 300); // play tone 60 (C5 = 523 Hz)
    delay(200); // Wait for 200 millisecond(s)
    noTone(11);
    delay(200); // Wait for 200 millisecond(s)
    tone(11, 523, 300); // play tone 60 (C5 = 523 Hz)
    delay(200); // Wait for 200 millisecond(s)
    noTone(11);
    delay(1000); // Wait for 1000 millisecond(s)
  } else {
    while (digitalRead(2) == HIGH) {
      digitalWrite(12, HIGH);
      delay(10000); // Wait for 10000 millisecond(s)
      digitalWrite(8, HIGH);
      digitalWrite(13, HIGH);
      delay(5000); // Wait for 5000 millisecond(s)
      digitalWrite(12, LOW);
      while (digitalRead(2) == HIGH) {
        while (analogRead(ThermistorPin) < (Tc < 1)) {
          if (Tc > 1) {
            digitalWrite(13, HIGH);
            Serial.println("Temperatura =");
            Serial.print(Tc);
          }
        }
        while (Tc == 1 && Tc < 12) {
          if (Tc == 1 && Tc < 12) {
            digitalWrite(13, LOW);
            digitalWrite(12, HIGH);
            Serial.println("Temperatura =");
            Serial.print(Tc);
          }
        }
      }
      digitalWrite(8, LOW);
      digitalWrite(12, LOW);
      digitalWrite(13, LOW);
      delay(100); // Wait for 100 millisecond(s)
    }
  }
}

Hola, bienvenido al foro!! :wink: Leer tu código y tus exigencias para comprenderlas requieren cierto tiempo, del cual en estos momentos, no dispongo. :frowning: Sin embargo, sí me gustaría arrojarte una sugerencia que he visto rápido que puedes cambiar.

Entiendo que la comprobación de la sonda de temperatura es para cuando arranca el equipo. En tal caso, ¿por qué no lo pones este paso en el void setup? Así cada vez que arranques la máquina comprobará la sonda una única vez y te ahorras esa comprobación permanente de la sonda. No suelo usar las entradas analógicas, pero me consta que no es necesario declararlas para usarlas. :wink:

Los comentarios que hago simplemente resaltan fallos de código nada mas.

  1. Comprobación del termistor no esta hecha.

  2. pinMode(A0, INPUT); //Termistor no hace falta de ningún modo ponerlo como entrada digital y luego usarlo como entrada analógica.

  3. analogRead(ThermistorPin); solo no sirve para nada.

  4. Tf no lo usas entonces para que lo calculas? // Copiado y pegado demostrado.

  5. Tanto delay() lleva el programa a un fracaso inmediato, perdida de situaciones a verificar/controlar
    Jamas en un sistema de control puedes y/o debes usar delay(). Reemplazo millis()
    Ve a Documentcacion => Indice de temas tutoriales => millis()

   tone(11, 554, 300); // play tone 61 (C#5 = 554 Hz)
    delay(200); // Wait for 200 millisecond(s)
    noTone(11);
    delay(200); // Wait for 200 millisecond(s)
    tone(11, 523, 300); // play tone 60 (C5 = 523 Hz)
    delay(200); // Wait for 200 millisecond(s)
    noTone(11);
    delay(200); // Wait for 200 millisecond(s)
    tone(11, 523, 300); // play tone 60 (C5 = 523 Hz)
    delay(200); // Wait for 200 millisecond(s)
    noTone(11);
    delay(1000); // Wait for 1000 millisecond(s)

Esto son muchos milisegundos de perdida de tiempo 2 segundos exactamente.

luego hay otras cosas como estas

delay(10000); // Wait for 10000 millisecond(s)

y para empeorarla tienes ciclos cerrados como este

while (Tc == 1 && Tc < 12) {
          if (Tc == 1 && Tc < 12) {
            digitalWrite(13, LOW);
            digitalWrite(12, HIGH);
            Serial.println("Temperatura =");
            Serial.print(Tc);
          }
        }

en los que dejas de prestar atención a todo lo demás hasta alcanzar el rango de temperatura.

Se comprende la idea pero mal realizado.

Va enfoque nuevo

Edito: Consulta como es la conexión del NTC y la R1. Cual esta conectada a GND?

Aca esta mi versión usando milli() y máquina de estado.
La opción WASH no esta hecha porque no se que valor puede tomar el switch ademas de HIGH LOW al que tu llamas WASH.

#include <math.h>
#define V_ABIERTO       1000
#define V_CORTO           50

const byte ThermistorPin = A0;
const byte Termostato    = 2;
const byte swPin         = 3;
const byte Compresor     = 8;
const byte Buzzer         = 11;
const byte Valvula       = 12;
const byte Bomba         = 13;

float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

int Vo;
unsigned long start, visualizo;
boolean flag = false, status;
byte estado = 0;

void fallaNTC();
float temperaturaNTC();

void setup() {

  Serial.begin(9600);
  pinMode(Termostato, OUTPUT);   //Termostato
  pinMode(Compresor, OUTPUT);   //Compresor
  pinMode(Buzzer, OUTPUT);  //Buzzer
  pinMode(Valvula, OUTPUT);  //Valvula de gas
  pinMode(Bomba, OUTPUT);   //Bomba de agua   
  Vo = analogRead(ThermistorPin);  // leo estado de termistor

  // supongo NTC a GND o sea tengo 10k a 25C a masa.
  // Si esta abierto, tendre 5V
  // si esta en corto tendre 0V
  if (Vo > V_ABIERTO) { // establecer el valor de V_UMBRAL que determina Termistor abierto
      Serial.println("Termistor Abierto.");
      flag = true;
  }
  if (Vo < V_CORTO) {
      Serial.println("Termistor en Corto.");
      flag = true;
  }

  // en el setup los delays no tienen importancia.
  // por eso los uso como tu los tenías.
  if (flag) {
      while(1)
        fallaNTC(); // no inicia funcionamiento y se escuchara buzzer hasta que NTC sea
                    // reemplazado.
  }
}

void loop() {

  status = digitalRead(swPin);
  
  // muestro cada 1 seg la temperatura
  if (millis() - visualizo > 1000UL) {
      Serial.print("Tmp = ");
      Serial.print(temperaturaNTC());
      Serial.println(" C");
      visualizo = millis();
  }

  if (status) { // ON => 
      switch (estado) {
        case 0: // Encienda solo la válvula de gas - agua  
                digitalWrite(Valvula, HIGH);
                start = millis();
                estado = 1;
                break;
        case 1: if (millis() - start > 174000UL) { // 2.9min = 2.9 x 60 = 174 x 1000 mseg
                // Active el compresor y bomba de agua.          
                digitalWrite(Compresor, HIGH);
                digitalWrite(Bomba, HIGH);
                estado = 2;
                start = millis();
                }
                break;
        case 2: // Espere 5 segundos y apague la válvula gas - agua (PARA INICIAR EL CICLO DE FABRICACIÓN DE HIELO)
                if (millis() - start > 5000UL) { // 5 segundos
                    digitalWrite(Valvula, LOW);  // INICIAR EL CICLO DE FABRICACIÓN DE HIELO
                    estado = 3;
                }
                break;
        case 3: if (temperaturaNTC() < 0.10) { // supongo alcanzó el 0.0 C
                    digitalWrite(Bomba, LOW);
                    estado = 4;
                    start = millis();
                }
                break;
        case 4: if (millis() - start > 2000UL) { // 2 segundos
                    digitalWrite(Valvula, HIGH); // valvula encendida
                    estado = 5;
                }
                break;
        case 5: if (temperaturaNTC() >= 12.0) {
                    digitalWrite(Valvula, LOW); // valvula apagada retirar cubos
                    estado = 6;
                    start =  millis();
                }
                break;
        case 6: if (millis() - start > 2000UL) { // 2 segundos
                    // inicio proceso de fabricacion de hielo
                    estado = 3;
                }
                break;
      } // fin del switch case
  } // fin del if
  // falta posicon WASH no se que estado es ese en el switch?
}

void fallaNTC() {
  tone(Buzzer, 554, 300); // play tone 61 (C#5 = 554 Hz)
  delay(200); // Wait for 200 millisecond(s)
  noTone(Buzzer);
  delay(200); // Wait for 200 millisecond(s)
  tone(Buzzer, 523, 300); // play tone 60 (C5 = 523 Hz)
  delay(200); // Wait for 200 millisecond(s)
  noTone(Buzzer);
  delay(200); // Wait for 200 millisecond(s)
  tone(Buzzer, 523, 300); // play tone 60 (C5 = 523 Hz)
  delay(200); // Wait for 200 millisecond(s)
  noTone(Buzzer);
  delay(1000); // Wait for 1000 millisecond(s)
}

float temperaturaNTC() {
  
  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  Tc = T - 273.15;
  return Tc;
}

Esfinterman: muchas gracias por tu comentario te cuento que si seria bueno poner la comprobación de la sonda en el setup pero también es requisito que en cualquier parte de los ciclos este detecte una falla en el código, y se que tengo que corregir bastante el código.
También lo que dices de las entradas Analogicas es cierto voy a corregir eso y después comento por aquí mismo, nuevamente muchas gracias por tu aporte saludos

surbyte: te confieso que el código no esta completo solo hice algo rápido por que lo que estoy es probando como funcionara el ciclo de congelación y descongelacion que es en si lo que me tiene enredado pero déjame decirte que tienes TODA LA RAZÓN en lo que me has expuesto en tus comentarios

1 lo de los delay totalmente de acuerdo contigo y si te soy sincero no sabia como optimizar el código para no escribir tantas lineas

2 entradas analógicas si es verdad

3 analogRead(ThermistorPin) estaba intentando que el me leyera el pin A0 para que ejecutara una función en base a eso e imprima luego la temperatura.

4 tf si pensé en usarla en un principio solo por razones didácticas y aprender en el proceso.

5 en este punto es donde estoy me estoy partiendo la cabeza ya que ahí se quedaba el programa y no hacia mas nada, claro después que escribí este post lo corregí pero aun tiene algunos defectos.

6 Te cuento que no soy un experto con arduino y su programación aunque hace muchos años aprendí programación con pascal pero nunca aplique los conocimientos y ya gran parte se me a olvidado, pero ya desde hace un tiempo e estado retomando la programacion por que me gusta y es lo que quiero hacer ahora

Y mi idea no es que alguien me haga el código y me lo de, no, yo quiero hacerlo y aprender en el proceso, se que me falta mucho por aprender pero ahí voy poco a poco pero seguro, ya e hecho varios programas pero son sencillo

pero muy agradecido con tus correcciones ya me pongo a trabaja y a Estudiar todo lo me que me mandaste, de verdad muchas gracias saludos

y otra cosa como se califica a alguien aqui? si es que se hace disculpen la ignorancia pero soy nuevo en el foro

Arcangel159:
y otra cosa como se califica a alguien aqui? si es que se hace disculpen la ignorancia pero soy nuevo en el foro

Hola,
Tienes que pinchar en "Add", al lado de "karma" (esto añade un "punto" al karma, que sería la valoración del forero).
Saludos

Hola otra vez,
No tengo tiempo para revisar todo el código (que, por otra parte, tiene buena pinta).
La especificación está bastante bien redactada (y clara), aunque, inevitablemente, surgirán modificaciones, "mejoras", etc.
Te recomiendo que estudies como funciona un autómata de estados; la secuencia que planteas depende de varios inputs y/o timers: la implementación será mucho más fácil con el autómata.
El congelador: ¿lo tienes funcionando actualmente en "manual"?. ¿Funciona el cuadro eléctrico?.
Saludos

vffgaston:
Hola otra vez,
No tengo tiempo para revisar todo el código (que, por otra parte, tiene buena pinta).
La especificación está bastante bien redactada (y clara), aunque, inevitablemente, surgirán modificaciones, "mejoras", etc.
Te recomiendo que estudies como funciona un autómata de estados; la secuencia que planteas depende de varios inputs y/o timers: la implementación será mucho más fácil con el autómata.
El congelador: ¿lo tienes funcionando actualmente en "manual"?. ¿Funciona el cuadro eléctrico?.
Saludos

Que tal vffgaston gracias por tus comentarios cada aporte o pista que me dan es valiosa para mi y bien recibida.

El fabricador de hielo lo tengo trabajando con arduino pero con un código sencillo solo con tiempo y no se esta tomando en cuenta la medición del termistor solo calcule en cuanto tiempo se formaban bien los cubos de hielo que son 18 minutos y el tiempo de cosecha en que caen los cubos en el contenedor son 1.5min en base a eso hice un Sketch con retardos solo para ponerla a trabajar para hacer mediciones de temperatura.

con respecto a lo que me comentaste acerca de autómata de estados, ya me estoy poniendo a estudiar y e visto que para este caso es muy conveniente usarlo

Estuve estudiando un código que me aporto el amigo Surbyte, que fue pero de gran ayuda, aprendí mucho de la maquina de estado con el "switch () case" y otras cosas mas aunque todavía me quedan unas dudas que poco a poco iré disipando

le hice unas pequeñas modificaciones al código y este corre bien aunque tengo algunos inconveniente cuando entro en el "switch () case" este hace lo que se pide solo hasta que se ejecuta el "case 3" cuando el termostato se abre (LOW) inmediatamente vuelve al inicio "case 0" reiniciando el ciclo y esto lo debería hacerlo solo si el termostato esta en HIGH nuevamente, es decir no espera a que esta condición se cumpla, por aquí les dejare el código que modifique espero me den una pista para corregir ese error de ante mano muchas gracias por cualquier aporte.

las modificaciones las explico entre ## ##

#include <math.h>
#define V_ABIERTO       1000
#define V_CORTO           50

const byte ThermistorPin = A0;
const byte Termostato    = 2;
const byte swPin         = 3;                                                     // ## este pin quedaria eliminado##
const byte Compresor     = 8;
const byte Buzzer         = 11;
const byte Valvula       = 12;
const byte Bomba         = 13;

float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.446278459e-03, c2 = 1.707774885e-04, c3 = 4.438871868e-07;

int Vo;
unsigned long start, visualizo;
boolean flag = false, status, status2;                                       //##declare otra variable status2##
byte estado = 0;

void fallaNTC();
float temperaturaNTC();

void setup() {

  Serial.begin(9600);
  pinMode(Termostato, INPUT);   //Termostato                             ##(lo declare como entrada)##
  pinMode(Compresor, OUTPUT);   //Compresor
  pinMode(Buzzer, OUTPUT);      //Buzzer
  pinMode(Valvula, OUTPUT);     //Valvula de gas
  pinMode(Bomba, OUTPUT);       //Bomba de agua   
  Vo = analogRead(ThermistorPin);  // leo estado de termistor

  // supongo NTC a GND o sea tengo 10k a 25C a masa.
  // Si esta abierto, tendre 5V
  // si esta en corto tendre 0V
  if (Vo > V_ABIERTO) { // establecer el valor de V_UMBRAL que determina Termistor abierto
      Serial.println("Termistor Abierto.");
      flag = true;
  }
  if (Vo < V_CORTO) {
      Serial.println("Termistor en Corto.");
      flag = true;
  }

  // en el setup los delays no tienen importancia.
  // por eso los uso como tu los tenías.
  if (flag) {
      while(1)
        fallaNTC(); // no inicia funcionamiento y se escuchara buzzer hasta que NTC sea
                    // reemplazado.
  }
}

void loop() {

  status = digitalRead(swPin);
  status2 = digitalRead(Termostato);                                              // ##leo el pin 2(Termostato)##
  
  // muestro cada 1 seg la temperatura
  if (millis() - visualizo > 2500UL) {
      Serial.print("Tmp = ");
      Serial.print(temperaturaNTC());
      Serial.println(" C");
      visualizo = millis();
  }

  //if (status) {  ON =>   ##elimine el if que seria el estado de swPin y se hace sin tomarlo en cuenta
      switch (estado) {
        case 0: // Encienda solo la válvula de gas - agua  ciclo STAR UP
                digitalWrite(Valvula, HIGH);
                start = millis();
                estado = 1;
                break;
        case 1: if (millis() - start > 174000UL) { // 2.9min = 2.9 x 60 = 174 x 1000 mseg
                // Active el compresor y bomba de agua.          
                digitalWrite(Compresor, HIGH);
                digitalWrite(Bomba, HIGH);
                estado = 2;
                start = millis();
                }
                break;
        case 2: // Espere 5 segundos y apague la válvula gas - agua (PARA INICIAR EL CICLO DE 
                       // FABRICACIÓN DE HIELO)
                if (millis() - start > 5000UL) { // 5 segundos
                    digitalWrite(Valvula, LOW);  // INICIAR EL CICLO DE FABRICACIÓN DE HIELO
                    estado = 3;
                }
                break;
        case 3: if  (status2 <= LOW) {                        // ##aqui es donde empieza el 
                                                                            // problema en este case si el termostato se abre 
                                                                             // automaticamente vuelve al "case 0##
                    digitalWrite(Compresor, LOW);   // compresor apagado
                    digitalWrite(Bomba, LOW);       // bomba apagada 
                    digitalWrite(Valvula, LOW);     // valvula apagada
                    estado = 7;
                    start =  millis();
                }
                    else {                                        //##else para pasar a estado 4##
                       estado = 4;                                 
                }
                break;  
        case 4: if (temperaturaNTC() < -25.0) {                  //##modifique la temperatura##
                    digitalWrite(Bomba, LOW);
                    estado = 5;
                    start = millis();
                }
                break;
        case 5: if (millis() - start > 2000UL) { // 2 segundos
                    digitalWrite(Valvula, HIGH); // valvula encendida
                    estado = 6;
                }
                break;
        case 6: if (temperaturaNTC() >= 18.0) {                               //##modifique la temperatura##
                    digitalWrite(Valvula, LOW); // valvula apagada retirar cubos
                    digitalWrite(Bomba, HIGH);  // Bomba encendida        //##agregue encender bomba##
                    estado = 3;
                    start =  millis();
                }
                break;
        case 7: if (status2 >= HIGH) { // ##Agregue este case que seria donde debe esperar  hasta que el 
                                                      //termostato este en HIGH##
                    estado = 0;
                    start =  millis();
                }
                break;        
      } // fin del switch case 
  //}  fin del if
    // falta posicon WASH no se que estado es ese en el switch? ##Eliminado##
}

void fallaNTC() {
  
  tone(Buzzer, 523, 300); // play tone 60 (C5 = 523 Hz)   //##Deje solo un tono##
  delay(200); // Wait for 200 millisecond(s)
  noTone(Buzzer);
  delay(500); // Wait for 1000 millisecond(s)
}

float temperaturaNTC() {
  
  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  Tc = T - 273.15;
  return Tc;
}

Comienza con

case 3: if (status2 == LOW) {

aunque es mas fácil esto

case 3: if (!status2) {

eso debe cumplir con su tarea, si luego no funciona adecuadamente se debe a otra razón.

estado 6 y estado 7 vuelven a pasos anteriores, revisa si no esta por ahi el problema o si esta debidamente cumplido el ciclo de enfriamiento.