I need help with port manipulation on Uno

I am trying to learn how to use port manipulation on my Uno so that I can then use it on a mega with a slightly different port setting.

In this code below, I would like to blink pins 8 - 13. I am using the on board LED and the serial monitor to debug the code. Currently, the LED will come on but it will not blink.

Could some on help please.

#include "pins_arduino.h"

// constants won't change. Used here to
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 800;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  DDRB = B00111111; // Set all the pins to output in port B
  Serial.begin(115200);
}

void loop()
{
  Serial.println("time");

  PORTB = B11111111;

  delay(800);

  PORTB = PORTB & B00000000;
}

You need a second delay. The port is only off for a few microseconds.

I'm confused. Direct port manipulation is typically used when speed is needed. Using it in code with massive delays seems to miss the point. And, of course, it's not portable.

There is a library for fast digital writes:

http://code.google.com/p/digitalwritefast/

I personally would stay away from port manipulation unless speed is absolutely required. Especially if I was writing code for multiple board types.

Thanks Nick and PaulS!

I used the delay method so that I could quickly write the sketch and see some results. Thanks for catching my silly mistake.

The reason that I want to learn port manipulation is that, I need to fire 24 pins quickly on a Mega. On the Mega, I will be using ports A, C, and L. It is for a GE Christmas light program. I know that the code will not be portable to other boards but, right now, I think it is the only answer that I think will work.

Thanks to all for the quick help!

cyclegadget: quickly

Christmas light

Define 'quickly'. Have you demonstrated that plain old digitalWrite() is not quick enough?

Premature optimisation should be avoided.

Here is part of the .cpp that is being used with GE G35 Christmas lights. They use a one wire style protocol. Instead of firing only one pin, I need to fire 24 on 3 different ports. The timing is critical according to the author. The code will be used on a Mega.

/*
  G35: An Arduino library for GE Color Effects G-35 holiday lights.

  Copyright © 2011 The G35 Authors. Use, modification, and distribution are
  subject to the BSD license as described in the accompanying LICENSE file.

  Original version by Paul Martis (http://www.digitalmisery.com). See
  README for complete attributions.

  Special thanks to Richard <rkfoote@gmail.com> and "slinky" for the unrolled-
  loop protocol code that seems to work very well!
*/

#if MHZ_16
#define DELAYLONG 17    // should be ~ 20uS long
#define DELAYSHORT 7   // should be ~ 10uS long
#else  // 20MHz
#define DELAYLONG 25    // should be ~ 20uS long
#define DELAYSHORT 11   // should be ~ 10uS long
#endif
#define DELAYEND 40     // should be ~ 30uS long

#define ZERO(x) digitalWrite(x, LOW);           \
  delayMicroseconds(DELAYSHORT);                \
  digitalWrite(x, HIGH);                        \
  delayMicroseconds(DELAYLONG);

#define ONE(x) digitalWrite(x, LOW);            \
  delayMicroseconds(DELAYLONG);                 \
  digitalWrite(x, HIGH);                        \
  delayMicroseconds(DELAYSHORT);

It looks as if the values being written are encoded as a timed sequence of pulses. In that case since each output channel will have different data values it will have different timing requirements so I don’t see how direct port access will be useful here.

Since it appears that the timing constraints are associated with the pulses that make up an individual bitstream, it may be that you don’t need to output each channel continuously and may be able to output them separately in sequence. It comes down to how frequently you need to send output on each channel, and how long it takes to do that for a given channel.

http://www.arduino.cc/en/Reference/PortManipulation

The caveat is that if you get it wrong, it's hard to figure out and can mess things up. However if you get it right, it's faster and uses less code.

If I had terrible fear of getting things wrong, I would never have gotten much code written as I would have quit in the first month! I don't worry about that since I know I can make it right and it will remain so until I screw with it again. In the meantime, I learn.

Using pin write for each pin in turn only takes a few microseconds per pin and is easier to be more sure of so you might go that way. Put it in a function (or put port manipulation in with protections once you have it worked out in a simple example) that takes a byte argument for data and there you are. Either way, make it work and you'll be fine.

If you do go with port manipulation, work it out in a small test sketch and triple check the gnarly parts. If you only ever write to those pins, set data direction in setup() using the normal pinMode() commands for just those pins. That takes care of the whole DDRx business. You also won't be using PINx since that's for read and you will be writing. On the UNO you have to turn off interrupts then read the port to get the bits you don't want changed (interrupts off so something else doesn't change them), then AND and OR the bits you do want changed and write that byte to PORTx, then turn interrupts back on. On the MEGA doing 8 bit writes to a dedicated port you just write to PORTx that you set up the pins as OUTPUT in setup. It's a lot cleaner and easier when you use a whole port. Note that the code will be hardware specific. If this scares you then don't mess with port manipulation.

I'd work out the other way in a test function too. Either way, it'd probably be good to wire in resistors and leds for the test.