0

I have the following code with digitalWrite I aim to write with bitwise operation only. No portability concerns here whatsoever. (for atmega328p here)

#define DATAOUT 11//MOSI 
byte commandbits = B11000000;
for (int i = 7; i >= 3; i--) {
    digitalWrite(DATAOUT, commandbits & (1 << i));
}

I came up with something like this below which works.

#define DATAOUT 11//MOSI 
byte commandbits = B11000000;
for (int i = 7; i >= 3; i--) {
    PORTB = (PORTB &(~(1<<3))) | (((commandbits &(1 << i))>>i) << 3);
}

Is this the most concise way. Is there a way to simplify it?

  • You do know that your code makes no real sense, don't you? Outputting data from a single pin like that can never do anything useful. You need a clock signal (synchronous serial) or for both ends of the connection to agree fairly precise timing (asynchronous serial). Or have you just omitted that part of your code for brevity? – Majenko Feb 15 at 18:28
  • I have omitted lots of it for brevity. obviously... – Noel Feb 15 at 21:20
  • That's OK then. I'll let you off. – Majenko Feb 15 at 21:39
2

Personally I'd expand it out a little:

if (commandbits & (1 << i)) {
    PORTB |= (1<<3);
} else {
    PORTB &= ~(1<<3);
}

It's far more readable, and there are less shifts to mess around with. Plus the AVR has bit set and bit clear operations which that will make use of, especially since it's now using literal values. You could actually replace those values with literals:

if (commandbits & (1 << i)) {
    PORTB |= 0x08;
} else {
    PORTB &= 0xF7;
}
  • That was my first idea of it. I did not mention it but the faster the better in my case. I'll have to do a timing test of the one liner vs if else. – Noel Feb 15 at 17:49
  • 2
    if you want fastest you need to look at the assembly code the compiler produces. I think the if statement would actually be faster than your code. AVRs can only do single bitshifts, so <<3 would be three instructions. Note that compilers are pretty smart. So don't bother replacing (1<<3) with 0x08 thinking it will be faster. – Gerben Feb 15 at 20:17
  • I confirm the if else is much faster. Thanks for your input Majenko and Gerben. – Noel Feb 18 at 16:50
1

If you like both portability, readability and performance there are a few libraries (for instance Arduino-GPIO):

#include "GPIO.h"

GPIO<BOARD::D11> data;

// Setup
data.output();

// Manual loop unrolling for speed. Could ask the compiler to do this
// Member function write()
data.write(commandbits & 0x80);
data.write(commandbits & 0x40);
data.write(commandbits & 0x20);
data.write(commandbits & 0x10);
data.write(commandbits & 0x08);

// Or using the assignment operator
data = commandbits & 0x80;
data = commandbits & 0x40;
data = commandbits & 0x20; 
data = commandbits & 0x10;
data = commandbits & 0x08;

And it is as fast as manually written direct port access.

  • Interesting. Your example get me thinking I should better get rid of the for loop and replace the (1<<i) with their value. – Noel Feb 15 at 17:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.