using certain pins of a PORT for other things during Direct Port Manipulation?

When using direct port manipulation can you use only 4 pins of a port, for example, and leave the others alone so they can be used for other things?

On an UNO you can use 0 through 7 on PORTD but what if I only needed pins 4,5,6,7, leaving 0,1 alone and 2 and 3 open for other things?
OR for PORTB, I could use pins 8,9,10,11 and leave pins 12 and 13 free.

Is this even possible?

Pinmapping: Arduino - PinMapping168

Since you write the sketch, you can solve this in software.

If the used output pins only needs to toggle, you can write for example 0x55 to PINB/C/D while that port is output. That will toggle only the pins that get a ‘1’ and those with a ‘0’ are not changed. This is a special feature of the ATmega328P.

It is allowed to write to the PORTB register when a crystal is used. The PB6 and PB7 are disconnected when using a crystal.

The Arduino macro bitSet() and bitClear() can be used to set a single output bit one by one. The compiler will compile that into a two-clock instruction.

A trick can be used when the other pins are set as input. When you write to the output register, that will enable or disable the internal pullup resistor. When that does not change the input signal, perhaps you can get away with it.

Conclusion: You may not write to a PORTB/C/D when some pins are used for other things. There are some tricks, but not a full solution. If you use a library, for example the Serial library, then it is not possible to solve it in software without changing that library.

Why do you want to write directly to registers with more than one bit at a time ? Perhaps that is not needed.

I was wanting to see if I could use direct port manipulation to write to a 74HC4515 4-to-16 decoder and it only needs 4 bits of data but I didn't want to waste Arduino pins unnecessarily.

At the moment I'm using a different method which uses bitread to read out each bit of a number, checking it it's a 1 or 0 and digital Writing them to 4 separate pins and was wondering if there was a better way.

I'm testing out the 4514 with 10 LEDs connected to the first 10 outputs on an UNO but in the end it will be used on a Leonardo which I know has a different port layout.

Here's how I'm doing it now.

int ledPin[] = { 5, 4, 3, 2 }; // four pins to output binary data to the 4514 A,B,C,D pins
const int strobePin = 6; // controls 4514 Strobe pin

void setup()
{
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(strobePin, OUTPUT);
}

void loop()
{
  int colPotValue = analogRead(A0); // read x axis value from joystick (column potentiometer)
  colPotValue = map(colPotValue, 0, 1023, 0, 9); // map 10 bit value to 0-9
  displayBinary(colPotValue); // send binary value to Arduino pins 5, 4, 3, 2
}

void displayBinary(byte numToShow)
{
  digitalWrite(strobePin, LOW);
  for (int i = 3; i >= 0; i--) // do this 4 times
  {
    //Use the bitRead function and cycle through each bit of the binary number
    //to see if it is a one or zero.
    if (bitRead(numToShow, i) == 1) { // it can only be 1 or 0 because it's a BIN value
      digitalWrite(ledPin[i], HIGH);
    }

    else {
      digitalWrite(ledPin[i], LOW);
    }
  }

  digitalWrite(strobePin, HIGH); //pulse strobe pin
}

Yes, just use |= and &= to only change bits corresponding to the pins you want to use, and avoid changing the ones for pins you don’t want to use.

@DrAzzy, reading the port, changing the bits and writing the port. Could that be a problem when an interrupt uses some of those pins ?

@dentaku, using the registers directly is faster, but not better. If you really, really need the maximum speed, then you can use it.

The digitalWriteFast library performs nearly as well as port manipulation but is a lot easier to use.

...R

Interesting.
I doubt I'll need the speed but was just wondering if there was a better/simpler way of doing it and since writing to a port is the simplest way to send binary data across multiple pins with an Arduino I started looking into it but see how it just adds complication if you're not going to use every pin in that port AND still expect to be able to use those unused pins.
It also makes the code not as obvious to follow.

I'll look into digitalWriteFast if I end up needing it.

Robin2:
The digitalWriteFast library performs nearly as well as port manipulation but is a lot easier to use.

...R

@dentaku mentions a 4-16 decoder. Setting the pins one-by-one will give spurious outputs on the decoder until the correct 4-bit code is in place. It may be fast enough that you wouldn't see the LEDs flickering but it might be a source of trouble if the final device is a coil.

Setting all four bits at one go with a port write could make the decoder go instantly from out3 ON to out12 ON with no intermediate values.

What says the forum?

I thought of that and it turns out that the 74HC4514 has a STROBE pin which you pull down while sending in data so that the outputs only change once STROBE goes high again.
My code does...

digitalWrite(strobePin, LOW);

sets 4 bits

digitalWrite(strobePin, HIGH);

dougp:
@dentaku mentions a 4-16 decoder. Setting the pins one-by-one will give spurious outputs on the decoder until the correct 4-bit code is in place. It may be fast enough that you wouldn't see the LEDs flickering but it might be a source of trouble if the final device is a coil.

Setting all four bits at one go with a port write could make the decoder go instantly from out3 ON to out12 ON with no intermediate values.

What says the forum?

dentaku:
I thought of that and it turns out that the 74HC4514 has a STROBE pin which you pull down while sending in data so that the outputs only change once STROBE goes high again.
My code does...

digitalWrite(strobePin, LOW);

sets 4 bits

digitalWrite(strobePin, HIGH);

Did you test that? I looked at the datasheet and it looks like strobe is not the same as latch; I might be mistaken though.

You can easily test by adding delays between the digitalWrites and check if the outputs only follow when strobe goes high or that they always follow.

Further, as the pin mapping of the Leonardo is different from the Uno, you probably will have to use different pins (that all belong to the same port) if you want to use direct port manipulation.