newbie: using PORT registers in conditionals

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

quick background: new to AVR but have programming background. Using ATmega (started arduino uno) programmed via eclipse and dapa bit banging (got to love old hardware) to play with various home project ideas.

Having little previous embedded experience I have little concern with littering my code with if/else and case statements. In an effort to be more conscious of memory use and to better understand the basics of uC I've been using more direct register access. My question concerns reading PORT into conditionals.

My concern is that a multi-level conditional that reads PORT at each comparison would have invalid values as PORT may change at any time. Ex:

if (PORTB ^ 2) {
  // do something
} elsif (PORTB ^ 4) {
  // PORTB might have changed so we are
  // really only "if" not "else" at this point
} else {
  // whatever
}

The obvious fix is

byte portB = PORTB; // store the value

if (portB ^ 2) {
  // do something
} elsif (portB ^ 4) {
  // PORTB might have changed but we are using a
  // stored value so the current register value is
  // irrelevant to us
} else {
  // whatever
}

Am I understanding the nature of reading the PORT register correctly?

Sorry if this seems obvious. I did do a few searches but my search-foo is greatly hampered by a coffee deficiency. That't my excuse and i'm sticking with it.

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

Quote:

The obvious fix is

Indeed it is :-)

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

Cool. At least I've wrapped my head around the difference between uC registers and the buffered inputs I'm used to seeing.

Now I just need to unwrap my head from the desk I've been pounding aforementioned head upon.

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

Although now that I'm looking at my first post, it's PIN not PORT. I'm looking at input not output.

What a moron.

Although I guess the same would apply as I could be executing first condition, get an interrupt, have PORT altered, then resume at else, and be in the same boat.

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

All the AVR special function registers are defined as 'volatile'.

So every statement or expression that includes PINB will involve a physical read of PINB.

Yes, a simple optimisation is to read PINB into a non-volatile variable pinB. Then all the expressions will use the value held in pinB.

Quite honestly, it makes little difference to code size or execution speed.

Incidentally, do you really want to do XOR with PORTB ?
It is more common to use AND with PINB.

IMHO, just make your source code simple and readable. It is far more important to have code that works than to worry about saving two cycles!

David.

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

Quote:

Quote:

The obvious fix is

Indeed it is


I beg to differ. At least about the "obvious" part.

1) It is not obvious that it would make sense (except in very rare cases) to do a conditional on PORTx contents on an AVR8. PINx, yes.

2) I might be missing some cleverness. Let's assume

Quote:

if (portB ^ 2)

is meant to mean "do something when PB1 is low".

So, what is the result of this when PB1 is indeed low, and PB3 and PB4 are high? Won't it be a different result than if all PBn are low?

Short answer: Take a trip to the tutorials forum and look for "bit manipulation" in the title.
https://www.avrfreaks.net/index.p...

You end up with

unsigned char pinB = PINB; // store the value

if (pinB & (1<<PB1)) {
  // do something
} else if (pinB & (1<<PB2)) {
} else {
  // whatever
} 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Good points David.

Right now this is mostly academic for me (learn, then build). I've been playing with interrupt timer and buttons (debounce anyone :) ) and ran into the theoretical problem this afternoon at work while thinking about my self imposed exercise for this evening; use a left, right, on and off momentary switches to select an LED from a PORTB and set it to blink or off. I fully expect all my code to break at this point but when confronted with a "hey, this seems wrong" brain interrupt I opted to be smart.

As to my use of XOR vs. AND, Please refer to the head to desk application I alluded to earlier. The XOR was from my scribbled "set the LED" napkin scrawl while my question was about reading the buttons.

And I did admit to being a moron. Freely.

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

theusch wrote:
2) I might be missing some cleverness.

Nope. Just stupid mistake from typing code to illustrate an as yet non-existent problem. As you pointed out the code should have used PINB and & (David pointed that out too).

I do like the use of the PBx macros. I need to get into that habit.

Thank you!