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
.
-
i
to numer bitu, tj. „indeks” następnego zapisywanego bitu -
1
to00000001
binarnie -
<<
to operator przesunięcia w lewo. Zwraca swój pierwszy argument przesunięty w lewo o tyle pozycji, ile wskazuje drugi argument -
1<<i
jest binarny00000001
przesunięte w lewo oi
pozycje, 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 & 0
to zero, aany_bit & 1
toany_bit
-
val & (1 << i)
to0...0(i-th bit of val)0...0
binarnie, 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')
=1
If 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 out
wartość (w formie binarnej) i wraz z nią poda impuls zegarowy.