Sprawdzałem kod funkcji shiftOut() w wiring_shift.c i nie całkiem rozumiem, co się dzieje w funkcji digitalWrite. Widzę, że !!(val & (1 << i)) pobiera wartość bitową z val ale jak to dokładnie działa?
Cała funkcja jest poniżej.
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); } }
Komentarze
Odpowiedź
I „będę zakładać bitOrder == LSBFIRST.
-
ito numer bitu, tj. „indeks” następnego zapisywanego bitu -
1to00000001binarnie -
<<to operator przesunięcia w lewo. Zwraca swój pierwszy argument przesunięty w lewo o tyle pozycji, ile wskazuje drugi argument -
1<<ijest binarny00000001przesunięte w lewo oipozycje, tj. coś w rodzaju0...010...0, gdzie pojedyncza 1 znajduje się na i-tej pozycji, licząc od prawej będący pozycją 0) -
&to „operator bitowy i”, gdzieany_bit & 0to zero, aany_bit & 1toany_bit -
val & (1 << i)to0...0(i-th bit of val)0...0binarnie, gdzie i-ty bit val znajduje się na i-tej pozycji wyniku -
!!jest podwójną negacją: to konwertuje zero na zero i dowolną wartość niezerową na jeden -
!!(val & (1 << i))wynosi 0 lub 1 i jest dokładnie i-tym bitem val
Komentarze
- pozwólcie mi podsumować to, co rozumiem. Załóżmy, że
val = '10010111';for i=2!!(val & (1 << i))=!!('10010111' & '00000100')=!!('00000100')=1If i is = 3!!(val & (1 << i))=!!('10010111' & '00001000')=!!('00000000')=0 - Zgadza się!
- A to oznacza, że jeśli dam 16-bitowe lub dłuższe dane do shiftOut, wyśle najmniej znaczących 8 bitów i zignoruje resztę.
-
shiftOut()pobiera daneuint8_t. Jeśli wywołasz to z 16-bitowym argumentem, kompilator niejawnie usunie 8 najbardziej znaczących bitów przed rzeczywistym wywołaniemshiftOut(). - @SteveMcDonald: Tak, wynik byłby taki sam bez podwójnej negacji, ponieważ
digitalWrite()interpretuje dowolne nie- wartość zerowa (nie tylko 1) w znaczeniuHIGH. Najwyraźniej autorshiftOut()nie chciał polegać na tym zachowaniu i zamiast tego chciał zawsze wywoływaćdigitalWrite()z 0 (tj.LOW) lub 1 (HIGH).
!!(val & (1 << i))to najbardziej złożona część tego kodu. Jeśli rozumiesz to, co robisz, nie rozumiesz?shift outwartość (w formie binarnej) i wraz z nią poda impuls zegarowy.