What type are port registers?

What type does the compiler think e.g. PORTD, PIND, DDRD, are?

Hi EmilyJane;

I think they are bytes. Check the datasheet from the Arduino site http://arduino.cc/en/Main/ArduinoBoardUno and click datasheet. The registers numbers are located page 426. And also check the Atmel site http://www.atmel.com/dyn/products/product_docs.asp?category_id=163&family_id=607&subfamily_id=760&part_id=4720
for the datasheet ( at the begining ) and instructions set ( located at the bottom of the site ).

Thanks Techone. On the chip itself they are 8 bit registers. I think this is what you mean by "they are bytes". Yes?

The reason I am asking what the compiler treats them as is because I was playing around with different ways to use port values and noticed that

uint8_t b;
b = PINB; // set b equal to the bit pattern of PortB
b = b | PINB; // set b equal to b | PortB

works, but

uint8_t pinc |= PINC; // set pinc equal to b | PortB

New_RS485_WS.cpp: In function 'void loop()':
New_RS485_WS:57: error: expected initializer before '|=' token
New_RS485_WS:58: error: 'pinc' was not declared in this scope

does not, but

uint8_t pinc = pinc | PINC;
pinc |= PINC;

compiles with no errors

I just added these lines to the blink example:

int b=10;
int a|=b;

Error:
Blink:7: error: expected initializer before '|=' token

I think it is just that you can use operator= such as |=, += in initializer, you should use simpler initializer such as a constant 10 or else that doesn't involve the variable being initialized in the initializer.

EmilyJane:

uint8_t pinc |= PINC; // set pinc equal to b | PortB

This isn't valid syntax, regardless of type.

uint8_t pinc;

... creates the variable pinc, it isn't valid to create it and OR it with PINC at the same time.

Put another way:

uint8_t pinc;

At this point the value of pinc is undefined. Now trying to OR it with something is also undefined.

You are asking the compiler to create a variable, and then take its previous value (which doesn't exist) and OR it with something.

Yes, but shouldn't the last example give the same error?

uint8_t pinc = pinc | PINC;
pinc |= PINC;

It's probably compiler dependent whether an error is thrown. If the compiler sees (type) (assignment, eg. some=else), it will be ok. But if it sees (type) (assignment that requires the left variable in the right expression, eg. some|=else), it throws an error. Either way is poor programming, as neither way will have a properly initialized value for pinc at the time of the OR operation.

liudr:
It's probably compiler dependent whether an error is thrown. If the compiler sees (type) (assignment, eg. some=else), it will be ok. But if it sees (type) (assignment that requires the left variable in the right expression, eg. some|=else), it throws an error. Either way is poor programming, as neither way will have a properly initialized value for pinc at the time of the OR operation.

I figured it was something like that. I created the error while copy/pasting from a function where the variable in question was a parameter into another window where I was playing with port register manipulation. The compiler error message was clear enough, for a change, for me to see what I had done but the fact that it didn't flag the error in an equally incorrect situation made me wonder why.

The compiler error message was clear enough, for a change, for me to see what I had done but the fact that it didn't flag the error in an equally incorrect situation

Actually, the "equally incorrect situation" is not equally incorrect. In a declaration/initialization situation, the compiler KNOWS that nothing will happen (no interrupts, etc.) that can change the fact that the left operand is uninitialized, so this is an error.

The "equally incorrect situation" could have an interrupt fire, and that interrupt could (not likely, but remotely possible) initialize the left operand. Then, the operator would have valid data. Because the situation is remotely possible, the second scenario generates a warning, not an error.

The Arduino team suppresses all warnings, so you don't get to see the warning that you should fix your code. The warning, if you could see it, is equally clear.

Ah, thank you! That makes more sense.

EmilyJane:
Yes, but shouldn't the last example give the same error?

uint8_t pinc = pinc | PINC;

Interesting question.

Putting interrupts aside for the moment, we really need to consider the syntax of C++. Please refer to this for an example:

http://www.cplusplus.com/doc/tutorial/variables/

Basically you can declare a variable without initializing it, eg.

byte pinc;

Or initialize it by assigment:

byte pinc = 42;

Or initialize it by constructor:

byte pinc (42);

But that is where the syntax runs out. In any case it wouldn't make sense to initialize it with reference to itself.


Your example:

uint8_t pinc = pinc | PINC;

Actually follows the above syntax. The variable pinc is constructed, and then assigned a value based on oring in PINC with the newly constructed value. It may not make any more sense (pinc would be undefined if an auto variable), but we have to work within the syntax of the language.

That's interesting. I didn't know what initialization by constructor was. I can see where what I did could cause problems that would be hard to troubleshoot. The variable wouldn't get initialized to any default at run time and when it was created during execution it would just be whatever was in that stack/heap location at the time.