Help about Bitwise operations in C

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

Hi,

 

I can not understand the exact result of the following expressions. Could anybody help, please ?

 

 

 

PORTB &= ~(1 << PB7);

PORTB |= (1 << PB7);

PORTB &= ~(1 << PB7);

PORTB |= (1 << PB5);

 

 

Thanks !

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

The first one clears bit 7 (msb) of PORTB

The next one sets bit 7 of PORTB

Rinse and repeat....

 

Basically it's toggling one bit of the port

 

 

 

 

 

 

 

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

This comes up so often that one of the key articles in the Tutorial Forum here is all about it:

 

https://www.avrfreaks.net/forum/t...

 

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

 

Could you please, explain the function of each one with more  details ?

For example, how the first one set the MSB (PB7) ??? Αnd also, with that, PB0 - PB6, are not affected ???

 

 

PORTB &= ~(1 << PB7);

PORTB |= (1 << PB7);

PORTB |= (1 << PB5);

 

 

Τhank you

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

Did you read the tutorial Clawson pointed you too?

 

 

 

 

 

 

 

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

bnsavr wrote:
Could you please, explain the function of each one with more  details ?

Have you tried working it through - step by step?

 

  • What is the definition of PB7 ?
  • What does the 'C' << operator do ?
  • Put those together, what does (1 << PB7) give you?
  • What does the 'C' ~ operator do ?
  • So what, then, does ~(1 << PB7) give you ?
  • etc, etc, ...

 

See the tutorial already mentioned.

 

If you don't know what the 'C' operators do, look them up in a textbook

 

Among other 'C' learning resources, there's a free online textbook listed here: http://blog.antronics.co.uk/2011...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

Yes, I did that ! But I am still confused. For instance, (1 << PB7) will affect only bit 7 ?  If yes, why i have to use all this, instead of PORTB.7=1;

I will see again the tutorial again...

 

 

 

 

 

Thanks !

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

You can do operations similar to PORTB.7=1 if you use the right macros and typedefs, but no matter the syntax when you follow it to what's actually happening behind the scenes every alternative boils down to PORTB |= (1 << PB7) since that's just how it's done in C.  If it's any consolation it turns into a single SBI/OUT instruction once you get down to the assembly.

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

Short C don't understand :

 

 PORTB.7=1;

 

There can be made macros that hide that but they will expand to the code you show.

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

bnsavr wrote:
Yes, I did that 

Did you?

 

How about showing your answers to each of the questions?

 

If you work through it, as suggested, you should get to the answer!

 

If you want us to see where you're getting stuck, you're going to have to show your working!

 

Quote:
For instance, (1 << PB7) will affect only bit 7 ?

Think about it: again, what is the value of (1 << PB7) ?

 

Write it down - in binary.

 

Then think about what happens when you use that value in association with the bitwise 'OR' operator ...

 

why i have to use all this, instead of PORTB.7=1;

Again, think about the basic 'C' syntax here:

 

The dot operator is used to access elements of a struct - isn't it?

 

So that is only going to work if you have PORTB defined as a struct.

 

But note that some compilers have a special extension to the standard language which is specifically for accessing individual bits of IO ports.

 

But, again, this is an extension to the language - it is not standard and will not work on all compilers.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rezer wrote:
You can do operations similar to PORTB.7=1 if you use the right macros and typedefs

No: It's not just a matter of macros and typedefs;  it relies upon a specific, proprietary language extension - not available on all compilers.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
Write it down - in binary.

This is important:

 

As the name suggests, the bit-wise operators work on bits - so it's important that you view the values as patterns of bits; ie, in binary.

 

With practice, you will learn to recognise bit patterns whether they're written in decimal or hex - but, to start, write them out in binary.

 

It is sad that the standard 'C' programming language does not have a notation for binary literals

(though some compilers offer this as an extension)

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Two things.

 

1) If you read the entire "Bit Manipulation 101" thread I linked to you will see some posts by a very creative poster called "danni" (Peter Danneger). He has a header file there (posted twice - take the later copy) called "sbit.h". With that you can do things like:

#include "sbit.h"

#define RED_LED PORT_B7

int main(void) {
    RED_LED = 1;
}

This is not quite the same as PORTB.7 (you only get to use that if you compiler is Codevision) but it comes pretty close.

 

2) Alternatively I've been working on a way to generate header files for AVRs that are a bit different to the ones in <avr/io.h> and those provided in other AVR C compilers. (long) details here:

 

https://www.avrfreaks.net/forum/b...

 

That allows you to do things like:

#include "ATmega16.h"

USE_SFRS();

#define RED_LED portd_b3

int main(void) {
    RED_LED = 1;
}

The way this one works is:

	union {
		uint8_t reg; // (@ 0x38) Port B Data Register
		struct {
			unsigned int b0:1;
			unsigned int b1:1;
			unsigned int b2:1;
			unsigned int b3:1;
			unsigned int b4:1;
			unsigned int b5:1;
			unsigned int b6:1;
			unsigned int b7:1;
		} bit;
	} _PORTB;
/* ================= (PORTB) Port B Data Register ================ */
#define portb pSFR->_PORTB.reg
#define portb_b0 pSFR->_PORTB.bit.b0
#define portb_b1 pSFR->_PORTB.bit.b1
#define portb_b2 pSFR->_PORTB.bit.b2
#define portb_b3 pSFR->_PORTB.bit.b3
#define portb_b4 pSFR->_PORTB.bit.b4
#define portb_b5 pSFR->_PORTB.bit.b5
#define portb_b6 pSFR->_PORTB.bit.b6
#define portb_b7 pSFR->_PORTB.bit.b7
#define USE_SFRS() volatile SFRS_t * const pSFR = (SFRS_t *)0x0020

While that may look a bit more complex at first I also define headers for ALL the bits in all the special function registers. So you can write things like:

#include "ATmega16.h"

USE_SFRS();

int main(void) {
    adcsra = aden | adsc;
    admux_adlar = 1;
}

which may be a little clearer than the <avr/io.h> version which would be:

ADCSRA = (1 << ADEN) | (1 << ADSC);
ADMUX |= (1 << ADLAR);

At the moment you need Python installed on your machine to use that though (just a one time thing - to actually generate the .h file(s))