¿Cómo funciona la función shiftOut internamente? (explicación sobre el código fuente)

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

  • !!(val & (1 << i)) es la parte más compleja de este código. Si entiende esto, entonces ¿cuál es la parte que hace no ¿entiendes?
  • @ edgar-bonet En realidad, esta era la pregunta. Puedo ver que de alguna manera calcula el valor de bit, pero no ' no entendí cómo hace esto.
  • ¿Entiendes el comportamiento de la función shiftOut? Quiero decir, entiendes que ' ll shift out un valor (en forma binaria) y le dará un pulso de reloj junto con él.

Respuesta

Asumiré bitOrder == LSBFIRST.

  • i es el número de bit, es decir, el «índice» del siguiente bit a escribir
  • 1 es 00000001 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 binario 00000001 desplazado a la izquierda en i posiciones, es decir, algo como 0...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», donde any_bit & 0 es cero y any_bit & 1 es any_bit
  • val & (1 << i) es 0...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() toma uint8_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 a shiftOut().
  • @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 de HIGH. Aparentemente, el autor de shiftOut() no quería depender de este comportamiento y, en su lugar, quería llamar siempre a digitalWrite() con 0 (es decir, LOW) o 1 (HIGH).

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *