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);        
    }
}

!!(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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.