Using bitwise not ( ~) : SOLVED

I was trying to use the bitwise NOT ( ~ ) to flip a bit for every iteration of a loop. But it does not work as expected whereas the bitwise XOR ( ^) works. See code below - I know I am making a mistake but not sure what...

void loop(void)
{
   bool static LED_State = 0;

 
   LED_State =  1^LED_State ;    // This blinks the LED.

   //LED_State =  ~LED_State ;      // This does not blink the LED 

  digitalWrite( Ch1_OKLed, LED_State); 


  delay(500);
}

Why use bitwise not on a boolean?
Why not logical not?

You have to use logical not '!'.

This is the correct form:

void loop(void)
{
   bool static LED_State = 0;

 
   LED_State =  !LED_State ;    // This blinks the LED.

  digitalWrite( Ch1_OKLed, LED_State); 


  delay(500);
}

Regards

The logical 0 wants all bits 0.
What happens when you do this:
~0b0101

This works

const byte ledPin = 13;

void setup()
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  boolean static LED_State = 0;
  LED_State =  (byte) ~LED_State ;
  digitalWrite(ledPin, LED_State);
  delay(500);
}

UKHeliBob:
This works

const byte ledPin = 13;

void setup()
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  boolean static LED_State = 0;
  LED_State =  (byte) ~LED_State ;
  digitalWrite(ledPin, LED_State);
  delay(500);
}

I am unable to understand this :

LED_State = (byte) ~LED_State ; // Why does it have to be cast ?

While using the Keil compiler for the 8051 MCU, following statement was quite valid for the "bit" variable type ( which i think is equivalent to the boolean ?)

bit LED_State = 0;

LED_State = ~LED_State ;

Just raising this since both Arduino IDE and Keil IDE are compatible with C .

LED_State =  (byte) ~LED_State ;  // Why does it have to be cast ? I don't know. It was an experiment but try this

boolean test = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(test, BIN);
  Serial.println(~test, BIN);
  Serial.println((byte)~test, BIN);  
}

void loop()
{
}

What do you get without the cast ?

UKHeliBob:

LED_State =  (byte) ~LED_State ;  // Why does it have to be cast ?

I don't know. It was an experiment but try this

boolean test = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(test, BIN);
  Serial.println(~test, BIN);
  Serial.println((byte)~test, BIN); 
}

void loop()
{
}



What do you get without the cast ?

This is what i got and am now fully confused as to whats happening :wink: How on earth a single bit become a 32 bit long ??

0
11111111111111111111111111111111
11111111

Because ~0 is a 32 bit long 1

You have an int that is made of 32 number zero
If you do this ~ you change all the bit inside it so you get 32 number one

How on earth a single bit become a 32 bit long ??

It did not start as a single bit. booleans are 8 bits, ie a byte.

UKHeliBob:
It did not start as a single bit. booleans are 8 bits, ie a byte.

Still doesn't explain how it became 32 bits, I would have expected it to be an int, which should have displayed -1.

All of these are abusing the digitalWrite() API.

The digitalWrite() API is defined as:

digitalWrite(pin, value);

Where value is either HIGH or LOW.
The API is not defined to allow value to be anything else like zero/non-zero or 0/1
While currently the values of HIGH and LOW happen to be 1 and 0, they are not require not require to be those values. So to take advantage of that internal implementation knowledge is abusing the API since the API function is defined as using HIGH or LOW and the behavior of any other value is undefined.
Also, depending on the implementation of the digitalWrite() code, the code may check for LOW or HIGH and default to assuming the other.
i.e. if the code checked for LOW then any non-zero value would work instead of HIGH to create a high level pin output.
However, if the code checked for HIGH then a high level output would only be achieved for the single value of HIGH and any other value like zero or any other non zero value would result in a low pin.

This is why taking advantage of internal implementation knowledge is bad programming practice that should be avoided when possible.

The proper way to handle this would be use only use HIGH and LOW and then use something like an inline ternary to set the value based on value of LED_State.

i.e.
modify your LED_State variable any way you want that creates a zero/non zero value, then use:

digitalWrite(ledPin, LED_State ? HIGH : LOW);

which ensures that only HIGH and LOW are ever used as the value parameter.

--- bill

Delta_G:
Print did that. Go look at the source for print and it will all become clear.

Found it.

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

That makes sense then.

if x is declared as a "bool", then both "x = ~True" and "x = ~False" evaluate to "True." The compiler notices this, and produces no code that actually toggles the value. It will work fine if the LEDState is byte or integer.

(~ 0 is 0xFF, which evaluates to True (1) when assigned to a bool.
~1 is 0xFE, which evaluates to True (1) when assigned to a bool.
You wouldn't get this behavior in, say, a C program that typedef'ed a "bool" as a synonym for "byte" or something, but C++ has bool as a distinct type.)

Using bitwise negate on a boolean makes about as much sense as using it on a float..... Never make assumptions about the implementation of undocumented features in a language. It's just begging for trouble. Use the language as documented, and you'll very rarely have problems.

Patient: "Doctor, it hurts when I do this."
Doctor: "Then don't do that!"

Regards,
Ray L.

It IS documented (see the stackoverflow link.) It promote to an int, does the bitwise operation, and then the assignment converts back to a bool (0 or 1, only.)

Thanks to all those who posted to clarify ... there were some hints to never do undocumented things. Sadly most time the problem is "I do not know that I do not know !! "

The explanations by pberrybap and westfw were in particular easy to follow.

And I couldn't help smile when I replaced "do this" and "do that " by "walk" in Doctor -Patient conversation !!

westfw:
It IS documented (see the stackoverflow link.) It promote to an int, does the bitwise operation, and then the assignment converts back to a bool (0 or 1, only.)

digitalWrite is documented to take either LOW or HIGH as the value argument. Passing a byte with any other value is undocumented. It might, or might not, accept either 0x01 and/or 0xfe as the same thing as HIGH, and might, or might not, accept 0x00 and/or 0xfe as the same thing as LOW.

In any case, doing bitwise negate on a boolean is just dumb. That si what logical negate is for.

Regards,
Ray L.