Zkoumal jsem shiftOut()
funkční kód v wiring_shift.c
a úplně jsem nepochopil, co se děje ve funkci digitalWrite. Vidím, že !!(val & (1 << i))
bere bitovou hodnotu z val
ale jak přesně to funguje?
Celá funkce je níže.
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); } }
Komentáře
Odpověď
Předpokládám bitOrder == LSBFIRST
.
-
i
je číslo bitu, tj. „index“ dalšího bitu, který se má zapsat -
1
je00000001
v binární podobě -
<<
je operátor posunu vlevo. Vrátí svůj první argument posunutý doleva o tolik pozic, kolik naznačuje druhý argument -
1<<i
je binární00000001
posunuto doleva oi
pozice, tj. něco jako0...010...0
, kde je singl 1 v i-té pozici počítající zprava (úplně vpravo) pozice 0) -
&
je „bitový a operátor“, kdeany_bit & 0
je nula aany_bit & 1
jeany_bit
-
val & (1 << i)
je0...0(i-th bit of val)0...0
v binární podobě, kde i-tý bit val je v i-té pozici výsledku -
!!
je dvojitá negace: it převede nulu na nulu a jakoukoli nenulovou hodnotu na jednu -
!!(val & (1 << i))
je buď 0 nebo 1 a je přesně i-tým bitem val
Komentáře
- dovolte mi shrnout, čemu rozumím. Předpokládejme
val = '10010111'
;for i=2
!!(val & (1 << i))
=!!('10010111' & '00000100')
=!!('00000100')
=1
Pokud je i = 3!!(val & (1 << i))
=!!('10010111' & '00001000')
=!!('00000000')
=0
- To je správné!
- A to znamená, že pokud na shiftOut dám 16bitová nebo delší data, pošle nejméně významných 8 bitů a zbytek bude ignorovat.
-
shiftOut()
vezmeuint8_t
data. Pokud jej zavoláte 16bitovým argumentem, kompilátor implicitně odstraní 8 nejvýznamnějších bitů před skutečným volánímshiftOut()
. - @SteveMcDonald: Ano, výstup by byl stejný bez dvojí negace, protože
digitalWrite()
interpretuje jakékoli jiné než nulová hodnota (nejen 1) znamenáHIGH
. AutorshiftOut()
se zjevně nechtěl spoléhat na toto chování a místo toho chtěl vždy volatdigitalWrite()
buď s 0 (tj.LOW
) nebo 1 (HIGH
).
!!(val & (1 << i))
je nejsložitější částí tohoto kódu. Pokud tomu rozumíte , pak jaká je vaše část, ne rozumět?shift out
hodnota (v binární formě). A spolu s ní dá hodinový puls.