best way to set pin high/low without using digitalWrite?

If I want to set pin 16 high on a Nano I’ve tried these three methods and they all work.

digitalWrite (16, HIGH);

PORTC = 1 << 2;

PORTC = 0B00000100;

In setup I have three of the pins in PORTC set as outputs. I see no use in using DDRC… because setting the pinMode only happens once during setup so it doesn’t make the code any faster.

pinMode(14, OUTPUT); //14 is pin A0 on UNO and Nano
pinMode(15, OUTPUT); //15 is pin A1
pinMode(16, OUTPUT); //16 is pin A2

But I’m not using any of the other pins in PORTC YET.

Question…

If I later want to use the other three available pins in this port (17,18,19) for other things, will doing something like PORTC = 0B00000100; mess with those other three pins, because obviously I’m setting them to 0?

Does using PORTC = 1 << 2; instead fix this problem and leave the other pins alone?

How about something like PORTC = PORTC | 0B00000100; ?
Is this preferable to using PORTC = 1 << 2; ?

If you do:

PORTC = 1 << 2;

you’ll affect all bits. Use AND, OR and XOR operations to manipulate bits:

PORTC |= 1 << 2; //set bit 2
PORTC &= ~(1 << 2);  //clear bit 2
PORTC ^= 1 << 2;  //toggle bit 2

OK. I didn’t think of it that way.

So is doing this…

PORTC = PORTC | 0B00000100;
just as good as doing
PORTC |= 1 << 2;

I prefer doing it the longer way because I can easily visualise the entire byte and which ones are 1 or 0.

ALSO
Wouldn’t using | and then << mean that it’s using more clock cycles than the other method that only uses a single | ?

dentaku:
OK. I didn’t think of it that way.

So is doing this…

PORTC = PORTC | 0B00000100;
just as good as doing
PORTC |= 1 << 2;

I prefer doing it the longer way because I can easily visualise the entire byte and which ones are 1 or 0.

The two statements are equivalent logically. A good compiler should generate basically the same code.

ALSO
Wouldn’t using | and then << mean that it’s using more clock cycles than the other method that only uses a single | ?
[/quote]

The compiler should compute a constant shifted by ‘n’ bits prior to encoding (if you have a variable shifted by ‘n’ that’s different.) So “1<<2” should be the same at code generation as “0b00000100”.

It should just cost the cycles for a read/modify/write either way.

What is "best"? Fastest? Easiest to understand when you read the code? Most impressive to the opposite sex?

Blackfin:
ALSO
Wouldn’t using | and then << mean that it’s using more clock cycles than the other method that only uses a single | ?

The compiler should compute a constant shifted by ‘n’ bits prior to encoding (if you have a variable shifted by ‘n’ that’s different.) So “1<<2” should be the same at code generation as “0b00000100”.

It should just cost the cycles for a read/modify/write either way.

Aha. That makes sense that the compiler can do this because it’s not a variable.

Hmmm. It might be interesting to do an experiment using avr-objdump and see what the compiler does using different methods for setting a bit high.
Not that I really understand that kind of code though :slight_smile:

dentaku:
Hmmm. It might be interesting to do an experiment using avr-objdump and see what the compiler does using different methods for setting a bit high.

Dead horse beating. But, here you go…

PORTC |= 1 << 2; //set bit 2
 1aa:	42 9a       	sbi	0x08, 2	; 8

PORTC &= ~(1 << 2);  //clear bit 2
 1ac:	42 98       	cbi	0x08, 2	; 8

PORTC ^= 1 << 2;  //toggle bit 2
 1ae:	98 b1       	in	r25, 0x08	; 8
 1b0:	84 e0       	ldi	r24, 0x04	; 4
 1b2:	89 27       	eor	r24, r25
 1b4:	88 b9       	out	0x08, r24	; 8

Writing a bit to a PIN register toggles the output on some AVR processors…

 1b0:	94 e0       	ldi	r25, 0x04	; 4
...
PINC = 1 << 2;  //toggle bit 2
 1b6:	96 b9       	out	0x06, r25	; 6

The single instruction optimization relies on the port being in the lower 32. In other words some ports on some processors will require more code.