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 @anon90500195 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 @anon90500195 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.