Wie funktioniert die shiftOut-Funktion intern? (Erklärung zum Quellcode)

7

Ich habe den shiftOut()Funktionscode in untersucht wiring_shift.cund nicht ganz verstanden, was in der digitalWrite-Funktion vor sich geht. Ich sehe, !!(val & (1 << i))nimmt den Bitwert von, valaber wie genau funktioniert es?

Die ganze Funktion ist unten.

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);        
    }
}
wizofwor
quelle
!!(val & (1 << i))ist der komplexeste Teil dieses Codes. Wenn Sie dies verstehen, welchen Teil verstehen Sie dann nicht ?
Edgar Bonet
@ Edgar-Bonet Eigentlich war das die Frage. Ich kann sehen, dass es irgendwie den Bitwert berechnet, aber ich habe nicht verstanden, wie es das macht.
Wizofwor
Sie verstehen das Verhalten der shiftOut-Funktion? Ich meine, Sie verstehen, dass es shift outein Wert sein wird (in binärer Form). Und wird einen Takt dazu geben.
Paul

Antworten:

9

Ich werde annehmen bitOrder == LSBFIRST.

  • i ist die Bitnummer, dh der „Index“ des nächsten zu schreibenden Bits
  • 1ist 00000001binär
  • <<ist der Shift-Left-Operator. Das erste Argument wird um so viele Positionen nach links verschoben, wie im zweiten Argument angegeben
  • 1<<iist binär 00000001um iPositionen nach links verschoben , dh so etwas wie 0...010...0, wobei sich die einzelne 1 in der i-ten Position befindet und von rechts zählt (ganz rechts ist Position 0)
  • &ist der "bitweise und Operator", wobei any_bit & 0Null ist und any_bit & 1istany_bit
  • val & (1 << i)ist 0...0(i-th bit of val)0...0binär, wobei sich das i-te Bit von val an der i-ten Position des Ergebnisses befindet
  • !! ist eine doppelte Negation: Sie wandelt Null in Null und jeden Wert ungleich Null in Eins um
  • !!(val & (1 << i)) ist entweder 0 oder 1 und ist genau das i-te Bit von val
Edgar Bonet
quelle
Lassen Sie mich zusammenfassen, was ich verstehe. Nehmen wir an val = '10010111'; for i=2 !!(val & (1 << i))= !!('10010111' & '00000100')= !!('00000100')= 1 Wenn i = 3 !!(val & (1 << i))= !!('10010111' & '00001000')= !!('00000000')=0
wizofwor
Das ist richtig!
Edgar Bonet
Und das bedeutet, wenn ich shiftOut Daten mit 16 Bit oder mehr gebe, werden niedrigstwertige 8 Bit gesendet und der Rest ignoriert.
Wizofwor
1
shiftOut()nimmt uint8_tDaten. Wenn Sie es mit einem 16-Bit-Argument aufrufen, entfernt der Compiler implizit die 8 höchstwertigen Bits vor dem eigentlichen Aufruf von shiftOut().
Edgar Bonet
1
@SteveMcDonald: Ja, die Ausgabe wäre ohne die doppelte Negation dieselbe, da jeder Wert ungleich Null (nicht nur 1) als Bedeutung digitalWrite()interpretiert wird . Anscheinend wollte sich der Autor von nicht auf dieses Verhalten verlassen und wollte stattdessen immer entweder mit 0 (dh ) oder 1 ( ) anrufen . HIGHshiftOut()digitalWrite()LOWHIGH
Edgar Bonet