3

I'm attempting to read the values of 8 pins at a time into a byte.

The obvious answer to this seems to be the Port registers, however with the way the Arduino is wired, I'd have to split my read across two registers.

In this case, I need a way to combine the lower 5 bits of PORTB with the upper 3 bits of PORTD into a single byte.

For example, this is the physical layout with the data lines I'm attempt to read/write to and their corresponding port assignments.

             SCSI
DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
|   |   |   |   |   |   |   |
PB4 PB3 PB2 PB1 PB0 PD7 PD6 PD5
            AVR

From what I can gather I need to use some shift operators to achieve this, perhaps something like:

hi = PORTB & 3;
lo = PORTD >> 3; 

But I'm unsure if that's correct and then how I would combine them.

Is it possible to write a macro to make getting and setting this byte easier?

Is there a good learning resource on bit manipulation like this?

  • OK thanks to Excel (had no idea I could do bit operations in it) I've worked out this would probably give the correct value for reading. (PORTB & (32-1) << 3) | (PORTD >> 5) but I'm still uncertain how to go about it for writing. – Peter Godwin Dec 23 '15 at 12:10
  • We overlapped. Is my answer clear enough, or do you need some more? – gbulmer Dec 23 '15 at 12:22
  • Hi gbulmer. Thanks for the answer. Indeed it's clear enough. I like method you've got for showing which bytes are being manipulated. Very clever. The only thing I need to think about is writing back to the ports without overriding, say, the serial ports. – Peter Godwin Dec 23 '15 at 12:42
2

Assuming PORTB and PORTD are correctly giving unsigned char values:

result = (PORTB << 3) | (PORTD>>5)

would do it.

As a macro:

#define SCSIBITS ((PORTB << 3) | (PORTD>>5))

Then use like this:

result = SCSIBITS

To make it clearer which specific bits are being used, write:

#define SCSIBITS (((PORTB & B00011111) << 3) | ((PORTD & B11100000) >> 5)))

It should be easier to see that the lower 5 bits of PORTB, and the upper 3 bits of PORTD are being used.

In the general case, where the values being manipulated are not unsigned char (should not be a problem in this specific case, but may be helpful to know), you might write:

#define SCSIBITS ((unsigned char)((PORTB & B00011111) << 3) | ((PORTD & B11100000) >> 5)))

or:

#define SCSIBITS ((((unsigned char)PORTB & B00011111) << 3) | (((unsigned char)PORTD & B11100000) >> 5)))

Here are a few links to bit-manipulation tutorials:
https://www.hackerearth.com/notes/bit-manipulation/
http://www.cprogramming.com/tutorial/bitwise_operators.html
http://www.tutorialspoint.com/ansi_c/c_bits_manipulation.htm

  • Thanks for that. I really like the little trick there to show which bits are being manipulated. Those resources look good too, though I must admit that playing with the Excel bitwise functions and getting a real-time result really made what was happening much more obvious than reading various pieces on the matter. – Peter Godwin Dec 23 '15 at 12:44

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.