I were examining shiftOut()
function code in wiring_shift.c
and I didn't quite understand what is going in digitalWrite function. I see !!(val & (1 << i))
is taking the bit value from val
but how exactly it works?
The whole function is below.
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);
}
}
asked Jun 1, 2015 at 8:38
1 Answer 1
I'll assume bitOrder == LSBFIRST
.
i
is the bit number, i.e. the "index" of the next bit to write1
is00000001
in binary<<
is the shift left operator. It returns its first argument shifted left by as many positions as indicated by the second argument1<<i
is binary00000001
shifted left byi
positions, i.e. something like0...010...0
, where the single 1 is in the i-th position counting from the right (rightmost being position 0)&
is the "bitwise and operator", whereany_bit & 0
is zero andany_bit & 1
isany_bit
val & (1 << i)
is0...0(i-th bit of val)0...0
in binary, where the i-th bit of val is in the i-th position of the result!!
is a double negation: it converts zero to zero and any non-zero value to one!!(val & (1 << i))
is either 0 or 1, and is exactly the i-th bit of val
answered Jun 1, 2015 at 9:28
-
let me summarize what I understand. Let assume
val = '10010111'
;for i=2
!!(val & (1 << i))
=!!('10010111' & '00000100')
=!!('00000100')
=1
If i is = 3!!(val & (1 << i))
=!!('10010111' & '00001000')
=!!('00000000')
=0
wizofwor– wizofwor2015年06月01日 10:43:02 +00:00Commented Jun 1, 2015 at 10:43 -
This is correct!Edgar Bonet– Edgar Bonet2015年06月01日 10:48:59 +00:00Commented Jun 1, 2015 at 10:48
-
And this means if I give 16bit or longer data to shiftOut, it will send least significant 8 bits and ignore the rest.wizofwor– wizofwor2015年06月01日 10:52:07 +00:00Commented Jun 1, 2015 at 10:52
-
1
shiftOut()
takesuint8_t
data. If you call it with a 16-bit argument, the compiler will implicitly remove the 8 most significant bits before the actual call toshiftOut()
.Edgar Bonet– Edgar Bonet2015年06月01日 11:01:58 +00:00Commented Jun 1, 2015 at 11:01 -
1@SteveMcDonald: Yes, the output would be the same without the double negation, because
digitalWrite()
interprets any non-zero value (not just 1) as meaningHIGH
. Apparently, the author ofshiftOut()
did not want to rely on this behavior, and instead wanted to always calldigitalWrite()
with either 0 (i.e.LOW
) or 1 (HIGH
).Edgar Bonet– Edgar Bonet2017年10月01日 12:34:05 +00:00Commented Oct 1, 2017 at 12:34
lang-cpp
!!(val & (1 << i))
is the most complex part of this code. If you do understand this, then what is the part you do not understand?shift out
a value (in binary form). And will give a clock pulse along with it.