Estaba examinando shiftOut() código de función en wiring_shift.c y no entendí muy bien lo que está sucediendo en la función digitalWrite. Veo que !!(val & (1 << i)) está tomando el valor de bit de val pero, ¿cómo funciona exactamente?
La función completa está a continuación.
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) { uint8_t i; for (i = 0; i < 8; i++) { if (bitOrder == LSBFIRST) digitalWrite(dataPin, !!(val & (1 << i))); else digitalWrite(dataPin, !!(val & (1 << (7 - i)))); digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW); } }
Comentarios
Respuesta
Asumiré bitOrder == LSBFIRST.
-
ies el número de bit, es decir, el «índice» del siguiente bit a escribir -
1es00000001en binario -
<<es el operador de desplazamiento a la izquierda. Devuelve su primer argumento desplazado a la izquierda tantas posiciones como lo indique el segundo argumento -
1<<ies binario00000001desplazado a la izquierda eniposiciones, es decir, algo como0...010...0, donde el 1 individual está en la posición i-ésima contando desde la derecha siendo la posición 0) -
&es el «bit a bit y el operador», dondeany_bit & 0es cero yany_bit & 1esany_bit -
val & (1 << i)es0...0(i-th bit of val)0...0en binario, donde el i-ésimo bit de val está en la i-ésima posición del resultado -
!!es una doble negación: convierte cero a cero y cualquier valor distinto de cero a uno -
!!(val & (1 << i))es 0 o 1, y es exactamente el i-ésimo bit de val
Comentarios
- permítanme resumir lo que entiendo. Supongamos
val = '10010111';for i=2!!(val & (1 << i))=!!('10010111' & '00000100')=!!('00000100')=1Si i es = 3!!(val & (1 << i))=!!('10010111' & '00001000')=!!('00000000')=0 - ¡Esto es correcto!
- Y esto significa que si doy 16 bits o más de datos para desplazar, enviará los 8 bits menos significativos e ignorará el resto.
-
shiftOut()tomauint8_tdatos. Si lo llama con un argumento de 16 bits, el compilador eliminará implícitamente los 8 bits más significativos antes de la llamada real ashiftOut(). - @SteveMcDonald: Sí, la salida sería la misma sin la doble negación, porque
digitalWrite()interpreta cualquier no valor cero (no solo 1) en el sentido deHIGH. Aparentemente, el autor deshiftOut()no quería depender de este comportamiento y, en su lugar, quería llamar siempre adigitalWrite()con 0 (es decir,LOW) o 1 (HIGH).
!!(val & (1 << i))es la parte más compleja de este código. Si sí entiende esto, entonces ¿cuál es la parte que hace no ¿entiendes?shift outun valor (en forma binaria) y le dará un pulso de reloj junto con él.