Cuestion de programación, ayuda con el significado, Resuelto

digitalWrite(AP, !!(row & B00000001)); 
digitalWrite(BP, !!(row & B00000010));

¿Alguien me explica como trabaja estas dos lineas?

Si mal no entiendo son puertas lógicas pero me no entiendo lo de "!!"

row va dentro de for que se va incrementando.

La explicación es un poco compleja. Hay que tener en cuenta varias cosas.

El tipo del segundo parámetro de la función digitalWrtite() es un entero sin signo de 8 bits. Así que recibirá un valor entre 0 y 255. La función digitalWrtite() pone el pin a nivel bajo si el valor del segundo parámetro es cero, en caso contrario lo pone a nivel alto.

Si ejecutamos el siguiente programa:

void setup () {
    pinMode(LED_BUILTIN, OUTPUT); // LED_BUILTIN es una constante definida en Arduno, para el pin del LED de la placa
}

void loop() {
    digitalWrite(LED_BUILTIN, 1); // Encendemos el LED de la placa del Arduino
    delay(500);
    digitalWrite(LED_BUILTIN, 0); // Apagamos el LED de la placa del Arduino
    delay(500);
}

Podremos ver cómo parpadea el led de la placa del Arduino. El valor 1 lo enciende y el 0 lo apaga.

¿Qué pasa si cambiamos el 1 por un 128? Si lo prueban, verán que continúa parpadeando.

¿Y si el 1 lo cambiamos por 256? Si lo prueban, verán que el LED no parpadea.

¿Y con el 257? El LED parpadea.

¿Qué está pasando? ¿Porqué con los valores 1, 128 y 257 el LED parpadea, pero con los valores 256, 512 y 768; entre otros; no parpadea? Simplemente porque con esos valore no se pone el pin a nivel alto.

¿Pero no dije al principio que cualquier valor distinto a cero pondría a nivel alto la salida? Sí, lo dije, pero también dije que el parámetro es un entero sin signo de 8 bits. Y que eso significaba que el valor iba entre 0 y 255. Bien, cuando se le pasa un valor mayor que 255, en realidad estamos tratando de pasarle un valor que necesita más de 8 bits para representarlo, así que hay una parte que “sobra” porque sólo disponemos de 8 bits. Bien, en ese caso se queda con el valor de los 8 bits menos significativos, el resto “desaparecen”. Los 8 bits menos significativos del valor 256 están todos a cero, con lo que la función recibe un cero. De hecho la función recibirá un cero si le ponemos como segundo parámetro un valor múltiplo de 256. Por eso los valores 256, 512 y 768 no encienden el LED. Y ese es “el problema” que se quiere resolver con la doble exclamación !!

Una vez entendido el problema, pasemos a explicar la solución. Debemos saber que en C/C++ el tipo boolean se representa en 8 bits y que adquiere únicamente los valores 0 para falso y 1 para verdadero. Así que si le asignamos el valor 256 a una variable de tipo boolean, esta variable tendrá el valor 1. No el valor del bit menos significativo de 256, sino 1, porque 256 es distinto de cero.

El operador ! retorna negado el valor lógico de lo que tenga a su derecha y retorna un valor de tipo boolean. Así que el valor de !256 es 0 porque el valor lógico de 256 es “verdadero” por ser distinto de cero y la negación de “verdadero” es “falso”, cuyo valor es 0. ¿Y qué pasa ahora si volvemos a negar el valor devuelto? Pues que tenemos el valor lógico “original”: así que el valor de !!256 es por tanto 1. De esta forma convertimos en un 1 cualquier valor distinto de 0, sin importar el “tamaño” del valor. Mientras que !!0 vale 0 igualmente.

Esa es la utilidad de la doble exclamación !!. Curiosamente, en el ejemplo puesto en la consulta, no hace falta utilizar este “truco” porque los valores nunca serán mayores que 2. Supongo que quien lo puso originalmente lo haría por costumbre. Más vale prevenir que curar. De hecho yo he tenido este problema, aún siendo conocedor de ello, por no haber tenido en cuenta que el valor con el que trabajaba “desbordaba” a la variable que lo recibía. Esta no es la única solución, también se podría utilizar el operador ternario ? : que puede resultar un poco más claro (al menos para los que conocen este operador). Utilizando el ejemplo de la consulta:

digitalWrite(AP, (row & B00000001) ? HIGH : LOW);
digitalWrite(BP, (row & B00000010) ? HIGH : LOW);

Si no se sabe cómo funciona el operador ternario, no hay más que buscar en Google “operador ternario c”.

Espero haber aclarado la duda.

@Lurdab
La función digitalWrite(), maneja 2 parámetros. El primero es el numero del pin digital sobre el que debe actual (AP y BP).

El segundo debe ser HIGH o LOW. El sinonimo de LOW es 0 y el de HIGH es todo los numero diferentes de cero.

Luego tenemos una expresion con doble negacion, es decir que el valor entre parentesis se comporta exactamente igual como el LOW y HIGH. Donde para n>0 !!n = 1.

Finalmente tenemos el operador And bit a bit.

a. En el primer caso tiene un numero variable (row) que le aplicas B00000001 en otras palabras si el row es par (Bxxxxxxx0) el resultado es 0 (LOW) y si es impar (Bxxxxxxx1) el resultado es 1 (HIGH).

b. El el segundo caso lo que quieres trabajar el con el penultimo bit gracias a B00000010 de modo que los numero que usen ese bit (2,3,6,7) daran es 2 (HIGH), el resto 0 (LOW).

Ejecuta este ejemplo para que te quede claro:

void setup() {
   Serial.begin(9600);
   for (byte n=0; n<10; n++){
      Serial.print(n);
      Serial.print(" = ");
      Serial.print(n & B00000001);
      Serial.print(", ");
      Serial.println(n & 0B00000010);
   }
}

void loop() {
   //Nada
}

Una cosa que se me olvidó comentar antes, pero que debería de haber quedado claro, es que si para encender el LED en lugar de poner 256 ponemos !!256, entonces sí que parpadeará.

    digitalWrite(LED_BUILTIN, !!256); // Encendemos el LED de la placa del Arduino

Otra forma de solucionar el problema es convertir el valor a boolean comparando el valor con cero:

    digitalWrite(LED_BUILTIN, 256 != 0); // Encendemos el LED de la placa del Arduino
digitalWrite(AP, (row & B00000001) != 0);
digitalWrite(BP, (row & B00000010) != 0);

Ojo. Para evitar posibles problemas con números negativos, hay que hacer la comparación != 0 (distinto de cero) y no hacer > 0 (mayor que cero). Porque un número negativo ha de ser considerado como un valor lógico "verdadero".

Muchas gracias por la explicacion, es mas o menos lo que pensaba pero ahora esta mucho mas claro.

Gracias a IgnoranteAbsoluto y Kike_GL

Continuare investigando mi modulo ya que esto es parte de una ejemplo para controlar una matrix rgb tipo panel donde en lugar de tener ABC de pines de control de filas solo tengo AB y me esta sacando un poco loco......