Canada
Offline
Sr. Member
Karma: 0
Posts: 319
Sometimes teaching, always learning,
|
 |
« on: February 25, 2012, 10:05:21 am » |
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); } }
|
|
|
|
|
Logged
|
|
|
|
|
West Des Moines, Iowa USA
Offline
Sr. Member
Karma: 2
Posts: 429
|
 |
« Reply #1 on: February 25, 2012, 10:23:11 am » |
You can do both. Just be careful not to disturb the other seven bits when you make changes to pin 0.
|
|
|
|
|
Logged
|
There's always a better way!
|
|
|
|
Canada
Offline
Sr. Member
Karma: 0
Posts: 319
Sometimes teaching, always learning,
|
 |
« Reply #2 on: February 25, 2012, 10:38:45 am » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
Austin, TX
Offline
Faraday Member
Karma: 42
Posts: 5244
CMiYC
|
 |
« Reply #3 on: February 25, 2012, 10:45:29 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Southern California
Offline
Sr. Member
Karma: 5
Posts: 476
I like blinky lights
|
 |
« Reply #4 on: February 25, 2012, 10:47:03 am » |
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!
|
|
|
|
|
Logged
|
|
|
|
|
Austin, TX
Offline
Faraday Member
Karma: 42
Posts: 5244
CMiYC
|
 |
« Reply #5 on: February 25, 2012, 10:49:16 am » |
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(). 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.
|
|
|
|
|
Logged
|
|
|
|
|
Canada
Offline
Sr. Member
Karma: 0
Posts: 319
Sometimes teaching, always learning,
|
 |
« Reply #6 on: February 25, 2012, 11:14:51 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Austin, TX
Offline
Faraday Member
Karma: 42
Posts: 5244
CMiYC
|
 |
« Reply #7 on: February 25, 2012, 11:19:34 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Canada
Offline
Sr. Member
Karma: 0
Posts: 319
Sometimes teaching, always learning,
|
 |
« Reply #8 on: February 25, 2012, 12:34:59 pm » |
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  #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); }
|
|
|
|
|
Logged
|
|
|
|
|
ottawa, canada
Offline
God Member
Karma: 4
Posts: 973
Arduino rocks
|
 |
« Reply #9 on: February 25, 2012, 12:45:21 pm » |
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  #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!
|
|
|
|
|
Logged
|
|
|
|
|
Austin, TX
Offline
Faraday Member
Karma: 42
Posts: 5244
CMiYC
|
 |
« Reply #10 on: February 25, 2012, 12:51:10 pm » |
code using digitalWrites() will work on any Arduino board. Direct port manipulation won't.
|
|
|
|
|
Logged
|
|
|
|
|
Canada
Offline
Sr. Member
Karma: 0
Posts: 319
Sometimes teaching, always learning,
|
 |
« Reply #11 on: February 25, 2012, 01:59:09 pm » |
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.
|
|
|
|
« Last Edit: February 25, 2012, 02:10:05 pm by John_S »
|
Logged
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 129
Posts: 10377
|
 |
« Reply #12 on: February 25, 2012, 02:15:56 pm » |
I just ran a speed test Using code similar to what you posted?
|
|
|
|
|
Logged
|
|
|
|
|
Canada
Offline
Sr. Member
Karma: 0
Posts: 319
Sometimes teaching, always learning,
|
 |
« Reply #13 on: February 25, 2012, 02:35:22 pm » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 129
Posts: 10377
|
 |
« Reply #14 on: February 25, 2012, 02:47:03 pm » |
static const int LEDpin = 13;
...and then rerun the test.
|
|
|
|
|
Logged
|
|
|
|
|
|