Single pin Port Manipulation

I'm wondering if it is possible to use port manipulation for only one pin and digitalRead/Write for the other pins. Everything I've read leads me to believe that you can only use port manipulation only on an entire port, not individual pins.

I want to use port manipulation on pin 0 where I have an IR led used as a remote (standalone 328, no Serial used). Can I do this?

Here's the applicable code.

//Sample program to trigger camera via IR
//Circuit: IR LED from pin 0, to 150 Ohm resistor, to ground

int IRpin = 0;

void setup(){
 
 
  pinMode(IRpin, OUTPUT);
  
  FireIR(7330);

}

void loop(){}

void FireIR(int IRdelay){
  //send first 16 bursts
  //for (int j=0; j<2; j++){
  for(int i=0; i<16; i++) { 
    digitalWrite(IRpin, HIGH);
    delayMicroseconds(10);
    digitalWrite(IRpin, LOW);
    delayMicroseconds(10);
  } 

  delayMicroseconds(IRdelay); 

  //send second 16 bursts
  for(int i=0; i<16; i++) { 
    digitalWrite(IRpin, HIGH);
    delayMicroseconds(10);
    digitalWrite(IRpin, LOW);
    delayMicroseconds(10);
  }  
}

You can do both. Just be careful not to disturb the other seven bits when you make changes to pin 0.

Thank you.
I found this Instructable: http://www.instructables.com/id/Arduino-is-Slow-and-how-to-fix-it/step2/A-and-B-watch-out-C-is-here/

I try and take instructables with a spoon of salt... Here's what they say:

PORTB |= _BV(PB5); //write port B5 HIGH
PORTB &= ~_BV(PB5); //write port B5 LOW

Can that just be simply substituted for a digitalWrite command?

Can I use a pinMode(IRpin, OUTPUT) in setup as normal? or do I need to set the pinMode with Port Manipulation for that one pin?

Use bit-wise operators.

Use Bitwise-AND to set the pins you want low. Use Bitwise-OR to set the pins you want HIGH. The mask determines which bit changes.

Use PORTD as an example (Uno Pins 0 to 7). You want to only change Arduino Pin 3, which is PORTD bit 3.

To set the pin high you would do this:
PORTD = PORTD | 0x08
(the mask is: 0000 1000)
Any pins already set to a 1 will stay a 1. Pin 3 / Bit 3 will be force High no matter what.

To set the pin low you would do this:
PORTD = PORTD & 0xF7
(the mask is: 1111 0111)

Don't worry about whether some of the pins on the port are set to Input. PORTD is used to determine if the internal pull-up resistor is turned on or not. So these operations will have no affect on them.

Yes, yes, and no.

The only thing I'd add is you're going to use PORTD and _BV(PD0) since you want to change D0, but you probably already knew that.

Good luck!

John_S:
PORTB |= _BV(PB5); //write port B5 HIGH
PORTB &= ~_BV(PB5); //write port B5 LOW

Can that just be simply substituted for a digitalWrite command?

Yes it can. Which would make me wonder why you want to do port maniuplation if you are okay with using digitalWrite().

John_S:
Can I use a pinMode(IRpin, OUTPUT) in setup as normal? or do I need to set the pinMode with Port Manipulation for that one pin?

Port Manipulation isn't a special mode. It is just a faster way to do what digitalWrite() and digitalRead() does. If you look at the code for those functions, you'll see they are using direct port manipulation themselves.

pinMode() sets the appropriate DDRx bits for which direction the bit / pin is going to be. Since this usually isn't a time critical function it is normal to see people set the direction with pinMode() while accessing the bits directly.

Thanks for the help all.

Which would make me wonder why you want to do port maniuplation if you are okay with using digitalWrite().

I'm having a hard time tweaking the IR code using digitalWrite. Sometimes it works, sometimes it doesn't. I think writing to the ports will allow more accurate timing.

John_S:
I think writing to the ports will allow more accurate timing.

It allows for faster writing. I'm not sure it is more accurate. Accuracy will probably depend more on what you are doing around the write operation.

So, I wrote a short blink sketch. I used #define to set the hex values, now using them in the program is easy.
This compiles to 846 bytes (IDE 0023) but using digitalWrite() to do the same thing compiles to 1034 bytes. After seeing this, it's hard to think of a good reason to use digitalWrite anymore XD

#define D13high  | 0x20;  //hex code to write Digital Pin 13 HIGH
#define D13low & 0xDF;  //hex code to write Digital Pin 13 LOW

void setup()
{
  pinMode(13, OUTPUT);
}
void loop()
{
  for(int i = 0; i < 10; i++)
  {
    PORTB = PORTB D13high;  //set Digital 13 HIGH
    delay(100);
    PORTB = PORTB D13low;   //set Digital 13 LOW
    delay(100);
  }
  while(1);
}

John_S:
So, I wrote a short blink sketch. I used #define to set the hex values, now using them in the program is easy.
This compiles to 846 bytes (IDE 0023) but using digitalWrite() to do the same thing compiles to 1034 bytes. After seeing this, it's hard to think of a good reason to use digitalWrite anymore XD

#define D13high  | 0x20;  //hex code to write Digital Pin 13 HIGH

#define D13low & 0xDF;  //hex code to write Digital Pin 13 LOW

void setup()
{
  pinMode(13, OUTPUT);
}
void loop()
{
  for(int i = 0; i < 10; i++)
  {
    PORTB = PORTB D13high;  //set Digital 13 HIGH
    delay(100);
    PORTB = PORTB D13low;  //set Digital 13 LOW
    delay(100);
  }
  while(1);
}

Until you want to change the pin you're using!

code using digitalWrites() will work on any Arduino board. Direct port manipulation won't.

Until you want to change the pin you're using!

Maybe you would like this a little better then?

int LEDpin = 13;  //set LED pin

void setup()
{
  pinMode(LEDpin, OUTPUT);  //set LEDpin as output
}
void loop()
{
  for(int i = 0; i < 10; i++)
  {
    portWrite(LEDpin, HIGH); //Write LEDpin HIGH
    delay(100);
    portWrite(LEDpin, LOW);  //Write LEDpin LOW
    delay(100);
  }
  while(1);
}


void portWrite(int pin, int state){
  if (state == 1){ //write HIGH
  switch (pin){
    case 0: PORTD = PORTD | 0x01; break;
    case 1: PORTD = PORTD | 0x02; break;
    case 2: PORTD = PORTD | 0x04; break;
    case 3: PORTD = PORTD | 0x08; break;
    case 4: PORTD = PORTD | 0x10; break;
    case 5: PORTD = PORTD | 0x20; break;
    case 6: PORTD = PORTD | 0x40; break;
    case 7: PORTD = PORTD | 0x80; break;
    case 8: PORTB = PORTB | 0x01; break; 
    case 9: PORTB = PORTB | 0x02; break;
    case 10: PORTB = PORTB | 0x04; break;
    case 11: PORTB = PORTB | 0x08; break;
    case 12: PORTB = PORTB | 0x10; break;
    case 13: PORTB = PORTB | 0x20; break;
    case 14: PORTC = PORTC | 0x01; break;
    case 15: PORTC = PORTC | 0x02; break;
    case 16: PORTC = PORTC | 0x04; break;
    case 17: PORTC = PORTC | 0x08; break;
    case 18: PORTC = PORTC | 0x10; break;
    case 19: PORTC = PORTC | 0x20; break;
  }
  } else {// write low
  switch (pin){
    case 0: PORTD = PORTD & 0xFE; break;
    case 1: PORTD = PORTD & 0xFD; break;
    case 2: PORTD = PORTD & 0xFB; break;
    case 3: PORTD = PORTD & 0xF7; break;
    case 4: PORTD = PORTD & 0xEF; break;
    case 5: PORTD = PORTD & 0xDF; break;
    case 6: PORTD = PORTD & 0xBF; break;
    case 7: PORTD = PORTD & 0x7F; break;
    case 8: PORTB = PORTB & 0xFE; break; 
    case 9: PORTB = PORTB & 0xFD; break;
    case 10: PORTB = PORTB & 0xFB; break;
    case 11: PORTB = PORTB & 0xF7; break;
    case 12: PORTB = PORTB & 0xEF; break;
    case 13: PORTB = PORTB & 0xDF; break;
    case 14: PORTC = PORTC & 0xFE; break;
    case 15: PORTC = PORTC & 0xFD; break;
    case 16: PORTC = PORTC & 0xFB; break;
    case 17: PORTC = PORTC & 0xF7; break;
    case 18: PORTC = PORTC & 0xEF; break;
    case 19: PORTC = PORTC & 0xDF; break;  
    }
  }
}

edit: I just ran a speed test, and the portWrite command is 30% faster than the digitalWrite command, but almost 8 times slower than the straight port manipulation.

I just ran a speed test

Using code similar to what you posted?

Speed test code:

#define D13high | 0x20; 
#define D13low  & 0xDF; 

int LEDpin = 13;

void setup()
{
 Serial.begin(9600);
}
void loop()
{
 unsigned long initial = 0;
 unsigned long final = 0;
 initial = micros();
 for(int i = 0; i < 500; i++)
 {
    digitalWrite(LEDpin,HIGH);
    digitalWrite(LEDpin,LOW);
 }
 final = micros();
 Serial.print("Time for digitalWrite(): ");
 Serial.print(final-initial);
 Serial.println("");
 initial = micros();
 for(int i = 0; i < 500; i++)
 {
    PORTB = PORTB | 0x20;
    PORTB = PORTB & 0xDF;
 }
 final = micros();
 Serial.print("Time for true c command: ");
 Serial.println(final-initial);

 initial = micros();
 for(int i = 0; i < 500; i++)
 {
    PORTB = PORTB D13high;
    PORTB = PORTB D13low;
 }
 final = micros();
 Serial.print("Time for true c command using #define: ");
 Serial.println(final-initial);

 initial = micros();
 for(int i = 0; i < 500; i++)
 {
    portWrite(LEDpin, HIGH);
    portWrite(LEDpin, LOW);
 }
 final = micros();
 Serial.print("Time for portWrite(): ");
 Serial.println(final-initial);
 while(1);
}


void portWrite(int pin, int state){
  if (state == 1){ //write HIGH
  switch (pin){
    case 0: PORTD = PORTD | 0x01; break;
    case 1: PORTD = PORTD | 0x02; break;
    case 2: PORTD = PORTD | 0x04; break;
    case 3: PORTD = PORTD | 0x08; break;
    case 4: PORTD = PORTD | 0x10; break;
    case 5: PORTD = PORTD | 0x20; break;
    case 6: PORTD = PORTD | 0x40; break;
    case 7: PORTD = PORTD | 0x80; break;
    case 8: PORTB = PORTB | 0x01; break; 
    case 9: PORTB = PORTB | 0x02; break;
    case 10: PORTB = PORTB | 0x04; break;
    case 11: PORTB = PORTB | 0x08; break;
    case 12: PORTB = PORTB | 0x10; break;
    case 13: PORTB = PORTB | 0x20; break;
    case 14: PORTC = PORTC | 0x01; break;
    case 15: PORTC = PORTC | 0x02; break;
    case 16: PORTC = PORTC | 0x04; break;
    case 17: PORTC = PORTC | 0x08; break;
    case 18: PORTC = PORTC | 0x10; break;
    case 19: PORTC = PORTC | 0x20; break;
  }
  } else {// write low
  switch (pin){
    case 0: PORTD = PORTD & 0xFE; break;
    case 1: PORTD = PORTD & 0xFD; break;
    case 2: PORTD = PORTD & 0xFB; break;
    case 3: PORTD = PORTD & 0xF7; break;
    case 4: PORTD = PORTD & 0xEF; break;
    case 5: PORTD = PORTD & 0xDF; break;
    case 6: PORTD = PORTD & 0xBF; break;
    case 7: PORTD = PORTD & 0x7F; break;
    case 8: PORTB = PORTB & 0xFE; break; 
    case 9: PORTB = PORTB & 0xFD; break;
    case 10: PORTB = PORTB & 0xFB; break;
    case 11: PORTB = PORTB & 0xF7; break;
    case 12: PORTB = PORTB & 0xEF; break;
    case 13: PORTB = PORTB & 0xDF; break;
    case 14: PORTC = PORTC & 0xFE; break;
    case 15: PORTC = PORTC & 0xFD; break;
    case 16: PORTC = PORTC & 0xFB; break;
    case 17: PORTC = PORTC & 0xF7; break;
    case 18: PORTC = PORTC & 0xEF; break;
    case 19: PORTC = PORTC & 0xDF; break;  
    }
  }
}

Results:

Time for digitalWrite(): 4120
Time for true c command: 348
Time for true c command using #define: 344
Time for portWrite(): 2864

static const int LEDpin = 13;

...and then rerun the test.

Results:

Time for digitalWrite(): 4060
Time for true c command: 348
Time for true c command using #define: 348
Time for portWrite(): 2740

It seems most of the time is going through the switch();. If I take out the pins I'm not using...

void portWrite(int pin, int state){
  if (state == 1){ //write HIGH
  switch (pin){
    case 13: PORTB = PORTB | 0x20; break;
  }
  } else {// write low
  switch (pin){
    case 13: PORTB = PORTB & 0xDF; break;
    }
  }
}

...the speed results are impressive:

Time for digitalWrite(): 4060
Time for true c command: 348
Time for true c command using #define: 348
Time for portWrite(): 352

You might be interested in this work on making a "fastDigitalWrite()"...

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1267553811/all

Thanks again James. The digitalWriteFast beats all the other options!

Time for digitalWrite(): 4060
Time for true c command: 348
Time for true c command using #define: 348
Time for portWrite(): 2744
Time for digitalWriteFast(): 288

And, one more...
static void portWrite(int pin, int state){