Best way to read a pin's value to either zero or 1?

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right now, I am doing the below to get a boolean value of a pin, PIN B3, in this case. There has to be a better way :-)

// TODO: Better way to read a PIN a value.
    // Read a bit from PB3 and shift it properly.
    uint8_t value = PINB & _BV(PB3);
    if (value) {
      value = 1;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A better way .

if ( PINB & PB3 ) // Just 1 line of asm
         
          value = 1;

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can think of a few ways to do this, one way is:

uint8_t value = (PINB & _BV(PB3)) ? 1 : 0;

You might find that the same object code is created. I would go with what makes more sense to you when you read it.

Randy

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
A better way .
No, a totally wrong way. Besides the "PINB & PB3" (instead of "PINB & (1<<PB3)"), how can your construct set value to 0?

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Define better.
Here's one way

uint8_t value = !!(PINB & _BV(PB3)); 

But that's kind of ugly.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

2 rookie mistakes... well, guess I'll go back to sleep. :oops:

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But that's kind of ugly.

Au contraire - I think it's a beautiful solution - so do many of the authors of Linux - the kernel code is peppered with that construct.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

K5HJ wrote:
I can think of a few ways to do this, one way is:

uint8_t value = (PINB & _BV(PB3)) ? 1 : 0;

You might find that the same object code is created. I would go with what makes more sense to you when you read it.

I'm fond of
uint8_t value=!!(PINB & _BV(3);

In principle, they are equivalent,
but sometimes the code generated is not the same.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or simply:

uint8_t value = (PINB & _BV(PB3)) != 0;

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint8_t value = (PINB & _BV(PB3)) != 0;

I don't get how that works.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would argue that the only 100% correct versions are those that explicitly set the value to one when the pin is high. All constructions that use boolean constructs are likely ( almost certain ) but not required to return a value 1 as true. Therefore,

uint8_t value = ( PINB & ( 1 << PB3 ) ) ? 1 : 0;

is guaranteed to result in 1 and 0 while,

uint8_t value = !!( PINB & ( 1 << PB3 ) );

is not. In practice this is unlikely to be an issue of course, as 0 and 1 are almost standard logical values; but in the interests of correctness....

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckeemj wrote:
I would argue that the only 100% correct versions are those that explicitly set the value to one when the pin is high. All constructions that use boolean constructs are likely ( almost certain ) but not required to return a value 1 as true. Therefore,

uint8_t value = ( PINB & ( 1 << PB3 ) ) ? 1 : 0;

is guaranteed to result in 1 and 0 while,

uint8_t value = !!( PINB & ( 1 << PB3 ) );

is not. In practice this is unlikely to be an issue of course, as 0 and 1 are almost standard logical values; but in the interests of correctness....

Wrong.
The return values of all operators are well defined by the C standard.

E.g. in case of the '!':

Quote:
The result of the logical negation operator ! is 0 if the value of its operand compares
unequal to 0, 1 if the value of its operand compares equal to 0.The result has type int.
The expression !E is equivalent to (0==E).

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:

uint8_t value = (PINB & _BV(PB3)) != 0;

I don't get how that works.

"!=" is an operator like any other (+, -, ...) and has a well defined return value. The operator returns 0 if both operants are equal, and 1 otherwise.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In C99/gnu99 modes, one could also cast the result to _Bool.

I don't know/don't care how does the compiler/optimizer cope with this.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unebonnevie wrote:
Right now, I am doing the below to get a boolean value of a pin, PIN B3, in this case. There has to be a better way :-)

// TODO: Better way to read a PIN a value.
    // Read a bit from PB3 and shift it properly.
    uint8_t value = PINB & _BV(PB3);
    if (value) {
      value = 1;
    }

Ok, folks...Thanks for all responses. I thought of one solution.


// The left-shift, that is, the >> operator, will shift the number of
// bits to right to make the final value zero or 1.
uint8_t value = (PINB & _BV(PB3)) >> PB3;

I think the above should do it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
indianajones11 wrote:

uint8_t value = (PINB & _BV(PB3)) != 0;

I don't get how that works.

"!=" is an operator like any other (+, -, ...) and has a well defined return value. The operator returns 0 if both operants are equal, and 1 otherwise.

This is a nice solution, too. I prefer the above solution from indianajones11 more than mine, which posted above, because it's less pin specific. :P

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That wasn't indianajones11's solution. It was suggested by Koshchi. But that's probably the solution i wold choose too. Pretty readable and will probably generate efficient code (as many of the other suggestions, but I'm not sure about your last ;-)).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unebonnevie wrote:


// The left-shift, that is, the >> operator, will shift the number of
// bits to right to make the final value zero or 1.
uint8_t value = (PINB & _BV(PB3)) >> PB3;

I think the above should do it.

But it does the comparison and then shift the bit to wanted position. So in my opinion, it is not the best, while it does do what you want.

You seem to want just 0 and 1 for FALSE and TRUE, while that is just as same as to use 0 or nonzero. So most of my code might be like this:


uint8_t flag;

flag=PINB&(1<<PB3);

if (flag) {xxx();} else {yyy();}

if (!flag) {zzz();} else {qqq();}

but the downside is that I can't print the value to screen or serial port nicely as with just 0/1.

usart_xmit('0'+flag); // flag 0 or 1 prints '0' or '1'
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
but the downside is that I can't print the value to screen or serial port nicely as with just 0/1.
But you can use:

usart_xmit('0'+(flag != 0));

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
Wrong.
The return values of all operators are well defined by the C standard.

See... that's one of the things I love about C. No matter what you think you know, it certainly isn't everything, and it might even be wrong. Alas, that is something I should probably know... oh wait, I do... now.

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why be so constraining to have the value be exactly 0 or 1? Why not construct it so that it is (zero) or (not zero). Then, you could do

uint8_t value = (PINB & _BV(PB3));

Makes it simple. Many C implementations accept (not zero) as the boolean TRUE; bet gcc does.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
Why be so constraining to have the value be exactly 0 or 1? Why not construct it so that it is (zero) or (not zero). Then, you could do

uint8_t value = (PINB & _BV(PB3));

Makes it simple. Many C implementations accept (not zero) as the boolean TRUE; bet gcc does.

Nonzero as true is required by C standards.
That said, sometimes one wants to do arithmetic with the result.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Agree on arithmetic use. However, that does not appear to be the case in this application.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net