Jag undersökte shiftOut()
funktionskod i wiring_shift.c
och jag förstod inte riktigt vad som händer i digitalWrite-funktionen. Jag ser att !!(val & (1 << i))
tar bitvärdet från val
men hur fungerar det exakt?
Hela funktionen är nedan.
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); } }
Kommentarer
Svar
Jag antar bitOrder == LSBFIRST
.
-
i
är bitnumret, dvs ”index” för nästa bit som ska skrivas -
1
är00000001
i binär -
<<
är skift till vänster. Det returnerar sitt första argument skiftat åt vänster med så många positioner som indikeras av det andra argumentet -
1<<i
är binärt00000001
förskjutas åt vänster avi
positioner, dvs något som0...010...0
, där singeln 1 är i den i: e positionen räknas från höger (längst till höger vara position 0) -
&
är ”bitvis och operatör”, därany_bit & 0
är noll ochany_bit & 1
ärany_bit
-
val & (1 << i)
är0...0(i-th bit of val)0...0
i binär, där den i: e biten av val är i den i: e positionen av resultatet -
!!
är en dubbel negation: det konverterar noll till noll och alla icke-nollvärden till ett -
!!(val & (1 << i))
är antingen 0 eller 1, och är exakt den i-biten av val
Kommentarer
- låt mig sammanfatta vad jag förstår. Låt oss anta
val = '10010111'
;for i=2
!!(val & (1 << i))
=!!('10010111' & '00000100')
=!!('00000100')
=1
Om jag är = 3!!(val & (1 << i))
=!!('10010111' & '00001000')
=!!('00000000')
=0
- Det här är korrekt!
- Och det betyder att om jag ger 16bit eller längre data att skifta, det skickar minst 8 bitar och ignorerar resten.
-
shiftOut()
taruint8_t
data. Om du kallar det med ett 16-bitars argument tar kompilatorn implicit bort de 8 viktigaste bitarna före det faktiska samtalet tillshiftOut()
. - @ SteveMcDonald: Ja, produktionen skulle vara densamma utan den dubbla negationen, eftersom
digitalWrite()
tolkar någon icke- nollvärde (inte bara 1) som betyderHIGH
. Uppenbarligen ville författaren tillshiftOut()
inte förlita sig på detta beteende och ville istället alltid ringadigitalWrite()
med antingen 0 (dvs.LOW
) eller 1 (HIGH
).
!!(val & (1 << i))
är den mest komplexa delen av den här koden. Om du gör förstår detta, vad är det då du gör inte förstår?shift out
ett värde (i binär form) Och kommer att ge en klockpuls tillsammans med det.