Comparar array en condiconal if

Saludos, Intento simplificar un condicional if con un array, pero solo lee una posición concreta del array..

Gracias.

#include <LCD.h>
#include <LiquidCrystal_I2C.h>
 #include "DHT.h"
 #define DHTPIN 2          //sensor dht11
 #define DHTTYPE DHT11
 
 DHT dht(DHTPIN, DHTTYPE);

#include  <virtuabotixRTC.h>  //Libreria RTC
#include <LiquidCrystal_I2C.h>

#define I2C_ADDR 0x27 //LCD i2c stuff
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7

LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

//Wiring SCLK -> 6, I/O -> 7, CE -> 8
//Or     CLK -> 6 , DAT -> 7, Reset -> 8  //conexiones RTC

virtuabotixRTC myRTC(5, 6, 7); //If you change the wiring change the pins here also

//dht_3.3v
const int fan1 = 8;       //rele1
const int lumin = 12;     //rele2
int H = 0;

int R2 = 0;

void setup() {
  Serial.begin(9600);
  lcd.begin (16,2); //Initialize the LCD
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home ();
   //myRTC.setDS1302Time(35, 30, 22, 6, 8, 10, 2021);  //Here you write your actual time/date as shown above 
                                                   //but remember to "comment/remove" this function once you're done as I did
                                                   //The setup is done only one time and the module will continue counting it automatically
  //pinMode(BOTON,INPUT);
  
  pinMode(fan1, OUTPUT); //salida ventilador rele1
  pinMode(lumin, OUTPUT); // Luces rele2
  dht.begin();
  
}

void loop() 

{
  
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);

      if (isnan(h) || isnan(t) || isnan(f)) {
       Serial.println("Error obt dat del sensor DHT11");
       return;
      }
    
       {if (t <=25 && R2 == 0)
     digitalWrite(fan1, HIGH);  // apagado
   else 
     digitalWrite(fan1, LOW), (R2 = R2 + 1);  // encendido
 
        }
       
       {if (R2 == 3600)
          (R2 = 0);
        }
        H = myRTC.hours;
        Serial.print(H);
          //int X[13]={0,1,2,3,4,5,18,19,20,21,22,23};  //ARRAY 12 HORAS 
             
    {if (H == 1 || H == 2 || H == 3 || H == 4 || H == 5 || H == 18 || H == 19 || H == 20 || H == 21 || H == 22 || H == 23 || H == 0)  // INTENTO SIMPLIFICAR ESTO (12 HORAS)
    
           //{if (H == X[13])  // ESTE ES EL ARRAY QUE INTENTO UTILIZAR 
       
        digitalWrite(lumin, HIGH),Serial.print("apagado");   // APAGADO
      else 
        digitalWrite(lumin, LOW),Serial.print("encendido");    // ENCENDIDO
     }

     
  lcd.clear(); //Here after clearing the LCD we take the time 
  //from the module and print it on the screen with usual LCD functions
 myRTC.updateTime();
  lcd.setCursor(0,0);
  lcd.print(myRTC.dayofmonth);
  lcd.print("/");
  lcd.print(myRTC.month);
  lcd.print("/");
  lcd.print(myRTC.year);
  lcd.print("-");
  lcd.print(R2);
  lcd.setCursor(0,1);
  lcd.print(t);
  lcd.print("-");
  lcd.print(myRTC.hours);
  lcd.print(":");
  lcd.print(myRTC.minutes);
  lcd.print(":");
  lcd.print(myRTC.seconds);
  delay(1000);
}

Esto debería funcionar.
No me di cuenta de tu array y yo lo definí con otro nombre, lo llamé horas

// definido como global.
int horas[] = {1,2,3,4,5,18,19,20,21,22,23,0};

En este caso no le puse dimensión pero si cuentas, empezando por 0 llegas a 11, por lo que debes poner 12.

H = myRTC.hours;

    Serial.print(H);

    //int X[13]={0,1,2,3,4,5,18,19,20,21,22,23};  //ARRAY 12 HORAS

    for (int i; i<sizefo(H); i++){
        if (horas[i] == H) { // INTENTO SIMPLIFICAR ESTO (12 HORAS)
            digitalWrite(lumin, HIGH);
            Serial.print("apagado"); // APAGADO
        }
        else {
            digitalWrite(lumin, LOW);
            Serial.print("encendido"); // ENCENDIDO
        }
    }

Otra cosa mal programada era esta

digitalWrite(lumin, HIGH),Serial.print("apagado");  

No se que invento es este, pero

digitalWrite(pin, valor);

termina con un ;

Serial.print("cartel");

es otro

Entiendo que preguntó como hacerlo con una array pero...
¿No sería más sencillo

if((H >= 0 && H <= 5) || (H >= 18 && H <= 23)) {

?

Saludos

1). digitalWrite(lumin, HIGH),Serial.print("apagado")
en este caso necesito ver por monitor serial cuando se apaga un rele , que normalmente esta encendido.

2). Ya intente definir el array como global y no funciona.

3). El array[13], se debe declarar con un digito de mas para guardar espacio del caracter "nulo".

4). En el condicional (H >= 18 && H <= 23) , un numero como 6,7,8,9 etc.. son menores que 23 y sale de la primera condicion...

No. Compara si el número está entre 18 y 23, inclusive.

El condicional completo se interpreta
Si H vale entre 0 y 5 ó entre 18 y 23 entonces...

Agrego: Te adjunto la tabla de verdad del condicional.
En verde el primer término, en rojo el segundo, en naranja el resultado del condicional

Como ves, valores entre 6 y 17 o superiores a 23, dan falso, o sea, no cumplen la condición.

Saludos

PD: Corregí la sentencia porque faltaba el paréntesis de cierre

Es un array de enteros, ¿de cuál "caracter nulo" hablas?

Y no va a funcionar porque @Surbyte olvidó salir del for() si se cumple el if().

Saludos

Agrega esto

       if (horas[i] == H) { // INTENTO SIMPLIFICAR ESTO (12 HORAS)
            digitalWrite(lumin, HIGH);
            Serial.print("apagado"); // APAGADO
            break;
        }

Empecemos aclarando un par de cosas. @rgrlopez está haciendo un uso un tanto raro de las llaves cuando pone un if, al poner todo el if entre un par de llaves:

    {if (t <=25 && R2 == 0)
      digitalWrite(fan1, HIGH);  // apagado
    else
      digitalWrite(fan1, LOW), (R2 = R2 + 1);  // encendido
    }

Lo crean o no, en este caso, eso es lo mismo que esto:

    if (t <=25 && R2 == 0)
      digitalWrite(fan1, HIGH);  // apagado
    else
      digitalWrite(fan1, LOW), (R2 = R2 + 1);  // encendido

Y ambos son lo mismo que esto:

    if (t <=25 && R2 == 0) {
      digitalWrite(fan1, HIGH);  // apagado
    }
    else {
      digitalWrite(fan1, LOW), (R2 = R2 + 1);  // encendido
    }

Las llaves sirven para definir un bloque de código, y en el primer caso, hay un bloque de código en el que tiene en su interior un if idéntico al del segundo caso. Lo que el del segundo caso, ni está dentro de un bloque de código ni tiene bloques de código, sólo una sentencia que ejecuta si se cumple y otra que se ejecuta si no se cumple el if.
El tercer caso es un if que tiene un bloque de código con una sentencia que se ejecuta si se cumple y otro bloque de código con una sentencia que se ejecuta si no se cumple. En este caso no hace falta indicar ningún bloque de código en ningún caso, porque sólo se necesita una simple sentencia en el caso de cumplirse la condición e igualmente una en el caso de no cumplirse. Si hubiera de ejecutar más de una sentencia según la condición, entonces sí que hemos de agruparlas dentro de un bloque usando los corchetes. Ejemplo:

  if (encendido) {  // Verificamos si ha de estar encendido o apagado
    digitalWrite(lumin, LOW);
    Serial.print("encendido"); // ENCENDIDO
  }
  else {
    digitalWrite(lumin, HIGH);
    Serial.print("apagado");   // APAGADO
  }

Pero si es cierto lo que digo, ¿porqué te funciona esto?:

    {if (H == 1 || H == 2 || H == 3 || H == 4 || H == 5 || H == 18 || H == 19 || H == 20 || H == 21 || H == 22 || H == 23 || H == 0)
        digitalWrite(lumin, HIGH),Serial.print("apagado");   // APAGADO
    else 
        digitalWrite(lumin, LOW),Serial.print("encendido");    // ENCENDIDO
    }

Pues porque eso es lo mismo que esto:

    if (H == 1 || H == 2 || H == 3 || H == 4 || H == 5 || H == 18 || H == 19 || H == 20 || H == 21 || H == 22 || H == 23 || H == 0)
        digitalWrite(lumin, HIGH),Serial.print("apagado");   // APAGADO
    else 
        digitalWrite(lumin, LOW),Serial.print("encendido");    // ENCENDIDO

Alguno pensará que habría que encerrar entre corchetes el digitalWrite(lumin, HIGH),Serial.print("apagado"); porque son dos sentencias y el digitalWrite(lumin, LOW),Serial.print("encendido"); porque también son dos sentencias. Pues no, no son dos sentencias, digitalWrite(lumin, HIGH),Serial.print("apagado"); es una sóla sentencia. Esa “sentencia” es una lista de elementos separada por comas… bueno, una lista compuesta por los dos elementos digitalWrite(lumin, HIGH) y Serial.print("apagado"), separados por una coma. Fíjense que en el segundo elemento no he puesto el punto y coma del final, porque el punto y coma no forma parte de la lista, sino que es el delimitador del final de sentencia. Por eso funciona como espera @rgrlopez. No se trata de una cosa mal programada como comenta @Surbyte. Eso sí, digamos que es “una mala praxis” el empleo de la coma en este caso, pero es la forma que seguramente encontró @rgrlopez de que le funcionara como él quería, debido al uso adecuado de los corchetes.

La forma más adecuada de poner el if es usando las llaves adecuadamente (un bloque para las sentencias que se han de ejecutar si se cumple y otro para las sentencias que se han de ejecutar si no se cumple la condición), así como el uso del punto y coma en lugar de la coma.

    if (H == 1 || H == 2 || H == 3 || H == 4 || H == 5 || H == 18 || H == 19 || H == 20 || H == 21 || H == 22 || H == 23 || H == 0) {
        digitalWrite(lumin, HIGH);   // APAGADO
        Serial.print("apagado");
    }
    else {
        digitalWrite(lumin, LOW);    // ENCENDIDO
        Serial.print("encendido");
    }

De la forma que estaba originalmente, funcionar funciona, pero no es la forma ortodoxa de hacerlo y despista al resto de programadores, porque no es lo habitual hacerlo a base de comas.

La propuesta “completa” de @gatul es:

    if ((H >= 0 && H <= 5) || (H >= 18 && H <= 23)) {
        digitalWrite(lumin, HIGH);   // APAGADO
        Serial.print("apagado");
    }
    else {
        digitalWrite(lumin, LOW);    // ENCENDIDO
        Serial.print("encendido");
    }

Y debería de funcionar lo que @gatul ha propuesto.

Pero si pese a todo se quiere hacer con un array que es más fácil de mantener (si se quieren cambiar las horas sólo se ha de modificar el array sin necesidad de pensar mucho), para ello la propuesta de @Surbyte no es correcta. Primero, ha tenido un despiste al poner sizeof(H). Supongo que lo que quería poner era sizeof(horas) / sizeof(horas[0]). Eso es la cantidad de bytes de lo que ocupa todo el array horas dividido por la cantidad de bytes de lo que ocupa el primer elemento del array horas. Como la cantidad de byte que ocupa el array horas completo es el tamaño de cualquiera de uno de sus elementos multiplicado por el número de elementos que tiene el array, no hacemos más que averiguar cuántos elementos tiene a partir de los dos tamaños. Parece un trabalenguas, pero si se mira con calma se puede llegar a entender.

Por otro lado, @Surbyte no ha tenido en cuenta que basta con que encuentre una coincidencia para que deba de estar apagado, y si no encuentra ninguna ha de estar encendido. Lo que está haciendo es apagar o encender por cada uno de los elementos, dejando finalmente el estado según el último elemento. La forma correcta de hacerlo con el array debería de ser algo tal que así:

  // Definiendo el array X como static es lo mismo que si fuera global
  // Siendo static o "global" sólo se instancia (crea) una vez, no cada vez que se ejecueta el loop.
  // Como no queremos que cambie los valores del array, lo declaramos "constante" con const
  // Para facilitar posibles cambios del tamaño del array no especificamos el número de elementos "[]"
  // Para calcular el número de elementos del array, usamos (sizeof(X) / sizeof(x[0]))
  static const int X[] = {0,1,2,3,4,5,18,19,20,21,22,23};  //ARRAY 12 HORAS
  bool encendido = true; // Utilizamos una variable para saber si ha de estar encendido. A de estar encendido si no encontramos la hora H en el array
  for (size_t i = 0; i < (sizeof(X) / sizeof(X[0])); i++) { // En principio, con este bucle vamos a recorrer todos los elementos del array
    if (X[i] == H) {      // Si el elemento actual tiene el mismo valor que H
      encendido = false;  // Entonces es que ha de estar apagado
      break;              // Nos salimos del bucle porque ya no hace falta seguir comparando con el resto de elementos
    }
  }
  if (encendido) {  // Verificamos si ha de estar encendido o apagado
    digitalWrite(lumin, LOW);   // ENCENDIDO
    Serial.print("encendido");
  }
  else {
    digitalWrite(lumin, HIGH);  // APAGADO
    Serial.print("apagado");   
  }

Uso el array que trató de usar originalmente @rgrlopez, con un par de ligeras modificaciones en su declaración. Primero el empleo de static, para indicar que no quiero que se el array sea creado cada vez que se invoca al loop(). Es como si se declarara global, porque se crea e inicializa al principio del programa una sola vez, pero sólo se puede “ver” desde dentro de la función loop(), esa es la parte que difiere con respecto a una verdadera variable global. También defino el array como const ya que no espero que sus valores sean alterados en tiempo de ejecución del programa. Si se van a cambiar los valores, ha de ser en el fuente y volver a compilar. Otra cosa que difiere, es que no le indico el tamaño, no pongo ningún valor entre los corchetes [], sino que dejo que el compilador le asigne el tamaño según la cantidad de elementos que se ponga en la lista de inicialización. De esta forma se pueden añadir o quitar elementos sin preocuparse si indicamos el tamaño correcto. En este punto, aclarar que efectivamente no hay que indicar un elemento más para reservar el espacio del “carácter nulo”. El “carácter nulo” es usado como indicador de final de cadena en las cadenas de C. Ahí sí que hay que tener en cuenta que la cadena ”Hola mundo”, a pesar de tener 10 caracteres, sí que se necesita un array de 11 bytes para almacenarla, ya que lleva implícita un undécimo carácter, el “carácter nulo” cuyo valor numérico es cero. Pero cuando tratamos con arrays de otros tipos, no es necesario ese “carácter nulo” ya que controlamos el tamaño de otra manera. Y en este caso controlamos el tamaño de X con la expresión (sizeof(X) / sizeof(X[0])). Nota, no importa que el cálculo sea “algo complejo”, debido a que todos los valores de la expresión son constantes, el compilador la evalúa en el momento de compilación y en su lugar pone el valor ya calculado. Así que en tiempo de ejecución no se llama a la función sizeof() ni se hace ninguna división ya que el compilador ha sustituido todo por un 12 en este caso, o por el valor que proceda si añadimos o quitamos elementos al array.

Finalmente, como se puede ver, se utiliza la variable encendido para saber si ha de estar encendido o no. Inicialmente la configuramos como true para que si no se ha encontrado ninguna hora en el array, se sepa que se ha de encender. Pero si mientras comparamos con cada elemento del array, encontramos uno que es igual a H, entonces hacemos que encendido sea false y con el break nos salimos del bucle for aunque no se haya llegado al último elemento ya que no hace falta buscar más.

Una vez pasado el for, con la variable encendido sabemos si se ha de encender o apagar. Le he dado la vuelta al if porque ahora la condición que se ha de cumplir es que “esté encendido” cuando originalmente era “si ha de estar apagado”. Este cambio y la elección del nombre de la variable auxiliar es para hacer más legible el código.

Espero que se me haya entendido.

Y por si lo de las longitudes de los arrays no ha resultado creíble, prueben y analicen este programa:

void setup() {
  Serial.begin(9600);
  int X[] = {0,1,2,3,4,5,18,19,20,21,22,23};
  Serial.println(F("Cantidad de bytes que ocupa el array X completo:"));
  Serial.print("sizeof(X) = ");
  Serial.println(sizeof(X));
  Serial.println();

  Serial.println(F("Cantidad de bytes que ocupa el primer elemento del array X:"));
  Serial.print("sizeof(X[0]) = ");
  Serial.println(sizeof(X[0]));
  Serial.println();

  Serial.println(F("Cantidad de elementos del array X:"));
  Serial.print("sizeof(X) / sizeof(X[0]) = ");
  Serial.println(sizeof(X) / sizeof(X[0]));
  Serial.println();
  Serial.println();

  char t[] = "Hola mundo";
  Serial.println(F("Cantidad de bytes que ocupa la cadena/array t completo:"));
  Serial.print("sizeof(t) = ");
  Serial.println(sizeof(t));
  Serial.println();

  Serial.println(F("Cantidad de bytes que ocupa el primer elemento de la cadena/array t:"));
  Serial.print("sizeof(t[0]) = ");
  Serial.println(sizeof(t[0]));
  Serial.println();

  Serial.println(F("Cantidad de elementos de la cadena/array t (incluído el carácter nulo de final de cadena):"));
  Serial.print("sizeof(t) / sizeof(t[0]) = ");
  Serial.println(sizeof(t) / sizeof(t[0]));
  Serial.println();

  Serial.println(F("Longitud de la cadena t (cuenta hasta el carácter anterior al carácter nulo de final de cadena):"));
  Serial.print("strlen(t) = ");
  Serial.println(strlen(t));
}

void loop() {
}

Prueben a cambiar la definición de t:

  char t[] = "Hola mundo";

Indicando un tamaño de 15 elementos tal que así:

  char t[15] = "Hola mundo";

Verán que el valor de strlen(t) no cambia.

Si el compilador les deja y sólo se queja pero lo compila, prueben a poner un 10 en lugar del 15. En mi caso, el valor de strlen(t) da 24. Ese es parte del peligro de los array en C y C++, que si no se tiene cuidado hace cosas “raras” y “peligrosas”.

Sobre el uso de las mayúsculas y minúsculas en el nombre de las variables y constantes, es otro tema del que se debería de hablar.

1 Like

¿Mirá vos?
La llave antes del if() la tomé como un error de tipeo... (Ahora noto que ocurre varias veces)

Se agradece, siempre hay algo nuevo para aprender. :wink:

Saludos

Mañana implemento las nuevas propuestas ya que hoy estoy fuera del proyecto..

Muchas gracias.

Pero antes, Una pregunta de tipo hardware, resulta que el RTC hizo un reset a valores por defecto, cuando un relevador se apago.. es posible que el relevador genere un campo y afecte el RTC al estar algo cerca, unos 15 cm de distancia, o es defectuoso ? La pila es nueva.

Gracias.

No te puedo responder específicamente tu caso pero me ha pasado que el RTC3231 se reinicie por "falta de energía" siendo que la batería es nueva (y comprobado que está impecable). :thinking:

Saludos

Si, impecable y nueva. Lo curioso es que el relevador cambia mucho de estado cada que la temperatura oscila entre los valores condicionados por el if, osea que no es un error fisico constante.

Reconozco que esto ocurrió por querer responder a @gatul y veo que metí mas la pata.
Buena para @IgnoranteAbsoluto como siempre.
Y lo del sizeof() claro era hora pero ahi hice unos cambios entre su variable que no me gustaba y la mía y quedó a medio camino. Otra mala mía.

Funciona bien de la manera propuesta por @gatul, y ocupa menos espacio que el contexto completo necesario del array, Aun así seguiré explorando la funcionalidad de los array, seguramente me serán de mucha utilidad mas adelante.

Muchas gracias.
@gatul
@Surbyte
@IgnoranteAbsoluto // ++ por el nutrido comentario.

¡Ni lo dudes!

Saludos y de nada. :wink: