2

I have come accross a lot of examples using ways similar to the ones shown below to assign values to the pins.

PORTB |= (1<<PORTB2); //set bit 2

PORTB &= ~(1<<PORTB1); //clear bit 1

DDRD = DDRD | B11111100; //Sets up the pins for output

My question is why do we need to use bitwise operations to make assignements?

4
  • 1
    You have "set bit 2" in comment, not "set bit 2 and clear all others"
    – KIIV
    Oct 11, 2020 at 16:44
  • @KIIV that is a bitwise OR operator ... it cannot clear bits
    – jsotola
    Oct 11, 2020 at 22:44
  • 1
    @jsotola exactly my point. PORTB |= (1<<PORTB2); //set bit 2 and keep the rest unchanged and PORTB = (1<<PORTB2); //set bit 2 and clear everything else.
    – KIIV
    Oct 12, 2020 at 4:35
  • Take a look at the LPC3250 User Manual on page 64 (Table 20. HCLK PLL Control register (HCLKPLL_CTRL - 0x4000 4058)). Now tell me, how would you put the PLL in power down mode, and later power it up again, without changing anything else? :) You need to only change bit 16, in a 32-bit register. The C language doesn't have an explicit "Set/change/read only this specific bit" (although, you can do some cool struct/bit member mask stuff with "bitfields"), so you have to be creative and use available operations to modify a subset of bits.
    – Gizmo
    Oct 12, 2020 at 6:57

4 Answers 4

7

My question is why do we need to use bitwise operations to make assignements?

Because you're not assigning, you're modifying.

If you want to turn on just pin 3 (for example) you need to only control bit 3 of PORTB and leave the others alone.

That means you need to "or" the value of just bit 3 being on with the existing PORTB to turn the bit on, or AND it with the inverse (all pins on except bit 3) to turn it off.

To get the value of bit 3 you can remember that it's 4, or you can just use 1<<3 to say "Bit 3" - or use the macro PORTB3 to make it more readable instead of just the number 3.

The operation is commonly known as "Read Modify Write" and in some low-end microcontrollers you have to take special care when doing it.

For example, if you want to control the output pin 3 and currently you have pins 2, 5 and 6 on and the rest of pins 0-7 off (those are the ones on port B on the Uno) the sequence may be like:

Turn on:

Calculate bit value 1<<3    => 0b00001000
Read PORTB                  => 0b01100100
OR the two values together  => 0b01101100
Write to PORTB              <= 0b01101100

Turn off:

Calculate bit value 1<<3    => 0b00001000
Invert it                   => 0b11110111
Read PORTB                  => 0b01101100
AND the two values together => 0b01100100
Write to PORTB              <= 0b01100100
4
  • Could you put examples into your answer as you write (refer) to them? I have learned from your and &Gerbens answer, but it would make things easier to understand if reference and example are seen simultaneously. Thanks
    – Tomas
    Oct 11, 2020 at 19:11
  • @Tomas Does that help you?
    – Majenko
    Oct 11, 2020 at 19:21
  • Thanks. That just become one of the posts to read when learning Arduino
    – Tomas
    Oct 11, 2020 at 20:10
  • 1
    Possibly worth noting that some chips (including the AVR) have specific "set bit" instructions, and at least gcc-avr will recognize this idiom and use the single instruction. Oct 12, 2020 at 1:52
1

If you want to change all pins on a port at once, you don't have to.

The point isn't just that you want to set/clear the pins you want, it's that you want to not change the state of the other pins. To do that, you need to modify only the bits for the pins to be changed, and leave all the other bits as they are. The only way to do this is with bitwise operators.

But if you do want to change all the pins at once, then you can perfectly well just set the port register to a value. Outputting a value on an 8-bit bus would be a classic case where you'd do this.

I do need to pick you up on one thing in your question though. In many cases, it is a bad idea to read the state of the port, modify the bits, and write the value back. The reason is that almost all microcontrollers use the same port address for setting the output state and reading the input state. So by reading back the port state, you aren't necessarily reading the actual outputs you set. Logic-high outputs are generally weaker than logic-low, so it's entirely possible for your connected electronics to pull down a logic-high. The sequence of faults for the bug goes:-

  • Your program sets a bit (pin) to 1.
  • Another component pulls that pin down to logic-low.
  • The next time you read that port back to change another pin, the input for the pin reads 0.
  • You modify the value for the pin you intended to change.
  • You write the value back. Now not only has the intended pin changed state, but so has the pulled-down output.
  • The other component stops pulling the pin down. But your micro keeps outputting 0 (logic-low) for that pin.

The solution is that you don't do bitwise operations directly on the register. Instead, you keep a "shadow" variable containing the state you want the outputs to be. You do all your bitwise operations on that shadow variable, and then you write the shadow variable directly to the register. And the bug goes away.

0

The registers are 8 bits in size. And in the above two cases you want to set/clear 1 bit, while leaving the others the same.

In the last example you want to set pins D2-D7 to output, while leaving pins D0 and D1 unchanged.

0

It makes code easier to write and re-use.

Let's say your program needs to do 3 unrelated things on different pins. Control a motor, flash a light, count some input pulses.

Since this bitwise technique allows you to read/change only the bits you need to, and leave the others alone, you can totally separate the code for the 3 tasks. It can even be written in separate files by separate people, and without knowing what other pins in the project are being used for. The code for one of the 3 tasks could be copy-pasted into a separate project, without needing to untangle it from project 1 nor make major changes to project 2. In software engineering lingo this is called making code "more maintainable" and also "modular."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.