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
.
-
i
es el número de bit, es decir, el «índice» del siguiente bit a escribir -
1
es00000001
en 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<<i
es binario00000001
desplazado a la izquierda eni
posiciones, 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 & 0
es cero yany_bit & 1
esany_bit
-
val & (1 << i)
es0...0(i-th bit of val)0...0
en 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')
=1
Si 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_t
datos. 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 out
un valor (en forma binaria) y le dará un pulso de reloj junto con él.