Reading several bits at once

Being very new to Arduino, and reading what introductionary texts I can, I have not seen anything yet about reading in several digital input bits at one time. Although not excactly what I want to do, a similarity would reading in, say, four bits from a BCD encoded rotaty switch. All the introductionary texts and examples I have read deal with reading in single bits. What am I not seeing? Thoughts or suggestions would be welcome. Thank you.

You should search for port manipulation and will find pages such as http://arduino.cc/en/Reference/PortManipulation#.Uy_ybqh_s1I

PINx will read all the available bits from port x, that is usually 8 bits but some ports have less.

As to what port to read and what bits are connected to external hardware you'll have to look at the board schematics to see that.


Rob

I came up with one method a while ago. In this sketch, see the global variables dipPins[] and dipWidth, the for() loop in setup(), and the function scanWidth() at the end of the sketch. See the Fritzing project for the schematic and breadboard layout that I used with this sketch.

While this method doesn’t really read “several bits at once” as in all in a single clock cycle, it should be a fast enough loop that I would imagine that it takes less than one millisecond. Should be fast enough for most applications.

/*     ---------------------------------------------------------
 *     |  Arduino Experimentation Kit Example Code             |
 *     |  CIRC-05 .: 8 More LEDs :. (74HC595 Shift Register)   |
 *     ---------------------------------------------------------
 *
 * We have already controlled 8 LEDs however this does it in a slightly
 * different manner. Rather than using 8 pins we will use just three
 * and an additional chip.
 *
 *
 */


// Pin Definitions
// The 74HC595 uses a serial communication
// link which has three pins
const byte data = 2;
const byte clock = 3;
const byte latch = 4;
// An array to recieve a binary 4-bit number for the scanWidth input (4DIP or 4bit rotary encoder)
// The Fritzing layout uses a 4-position DIP switch because there isn't a 4bit rotary encoder
// in the core parts bin.
const byte dipPins[] = 
{
  10,11,12,13
};
// Use sizeof() to dynamically get the size of the array. sizeof returns the number of bytes, so need
// divide by size of the datatype (in this case byte).
const byte dipWidth = sizeof(dipPins)/sizeof(byte);
// Which analog pin to use for the timing input (wiper of a pot)
byte analogPin = 0;

// Used for single LED manipulation
byte ledState = 1;
const byte ON = HIGH;
const byte OFF = LOW;

/*
 * setup() - this function runs once when you turn your Arduino on
 * We set the three control pins to outputs
 */
void setup()
{
  pinMode(data, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(latch, OUTPUT);
  updateLEDs(1);  // Start everything how the pattern will end at then end of void loop()

  // Set each pin connected to the rotary DIP switch as an input
  for(byte i = 0; i < dipWidth; i++)
  {
    // Initialized as INPUT_PULLUP to reduce the part count of the board by 4 resistors.
    pinMode(dipPins[i], INPUT_PULLUP);
  }
}

/*
 * loop() - this function will start after setup finishes and then repeat
 * we set which LEDs we want on then call a routine which sends the states to the 74HC595
 */
void loop()  // run over and over again
{
  scanUp();
  scanDown();
}

/*
 * scanUp() - starting with the first LED on, scan up to the last LED, leaving
 * scanWidth number of LEDs on. End with only the last LED on.
 */
void scanUp()
{
  for(byte i = 1; i <= 7 + scanWidth(); i++)
  {
    delay(delayTime());
    // Turn on the next LED as long as it's a valid LED number
    if(i <= 7)
    {
      changeLED(i, HIGH);
    }
    // Turn off the previous LED on the other side of scanWidth as long as it's a valid LED number
    byte offLED = i - scanWidth();
    if(offLED >= 0 && offLED < 7)  //leave the last LED on.
    {
      changeLED(offLED, LOW);
    }
  }
}

/*
 * scanDown() - starting with the last LED on, scan down to the first LED, leaving
 * scanWidth number of LEDs on. End with only the first LED on.
 */
void scanDown()
{
  for(byte i = 6; i >= 0 - scanWidth(); i--)
  {
    delay(delayTime());
    // Turn on the next LED as long as it's a valid LED number
    if(i >= 0)
    {
      changeLED(i, HIGH);
    }
    // Turn off the previous LED on the other side of scanWidth as long as it's a valid LED number
    byte offLED = i + scanWidth();
    if(offLED <= 7 && offLED > 0)  //leave the first LED on.
    {
      changeLED(offLED, LOW);
    }
  }
}

//These are used in the bitwise math that we use to change individual LEDs
//For more details http://en.wikipedia.org/wiki/Bitwise_operation
const byte bits[] = 
{
  0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000
};
const byte masks[] = 
{
  0b11111110, 0b11111101, 0b11111011, 0b11110111, 0b11101111, 0b11011111, 0b10111111, 0b01111111
};

/*
 * changeLED(byte led, byte state) - changes an individual LED
 * LEDs are 0 to 7 and state is either 0 - OFF or 1 - ON
 */
void changeLED(byte led, byte state)
{
  ledState = ledState & masks[led];  // clears ledState of the bit we are addressing
  if(state == ON)
  {
    ledState = ledState | bits[led];
  }  // if the bit is on we will add it to ledState
  updateLEDs(ledState);  // send the new LED state to the shift register
}

/*
 * updateLEDs() - sends the LED states set in ledStates to the 74HC595
 * sequence
 */
void updateLEDs(byte value)
{
  digitalWrite(latch, LOW);  // Pulls the chips latch low
  shiftOut(data, clock, LSBFIRST, value);  // Shifts out the 8 bits to the shift register
  digitalWrite(latch, HIGH);  // Pulls the latch high displaying the data
}

/*
 * delayTime() - Calculate the delay time in milliseconds based on the value of an analog input.
 * For example, a potentiometer. Scaled to a range of 5 to 150.
 */
byte delayTime()
{
  byte ret = map(analogRead(analogPin), 0, 1023, 5, 150);
  return ret;
}

/*
 * scanWidth() - converts a binary value on multiple digital inputs to a byte. Use this
 * byte for the number of LEDs wide we want the scan pattern.
 */
byte scanWidth()
{
  byte ret = 0;
  byte bitValue[] =  // Only have the decimal equivalents for 8 bits because this function's datatype is byte.
  {
    1,2,4,8,16,32,64,128
  };
  for(byte i = 0; i < dipWidth; i++)
  {
    // Because the pins are using the internal pull-ups, we want to treat them as low-active.
    if(!digitalRead(dipPins[i]))
    {
      ret = ret + bitValue[i];
    }
  }
  return ret;
}

Hope this helps. Just one way of many to skin this particular cat. Techniques like this allow you to select arbitrary pins (and order of pins) for your dip switches. I’m not advocating choosing random pins all over the place, but this method does release one from having to make sure that all the dip switch (or BCD/HEX encoder) pins are on the correct hardware port.

P.S. Hey, I just noticed an error on the schematic… I have the lines from the dip switch labeled wrong. dipPins[0] should be on dip switch pin 4 (Arduino D10) through dipPins[3] on dip switch pin 1 (Arduino D13). I may or may not eventually get around to fixing that on the fritzing project page…

Thank you all very much for your inputs. (No pun intended.) Coming from doing Picaxe programs, I am finding information about bit manipulation with Arduino a bit thin on the ground. I am sure it is there, but I am yet to find a ready reference with all this information in one place. As I said, I am still learning. Thanks again.

gerrymcc: Thank you all very much for your inputs. (No pun intended.) Coming from doing Picaxe programs, I am finding information about bit manipulation with Arduino a bit thin on the ground. I am sure it is there, but I am yet to find a ready reference with all this information in one place. As I said, I am still learning. Thanks again.

See the Arduino reference page section on Bits and Bytes for direct bit manipulation if that is what you want to do it. Just watch endianness... Also in my example the section:

  byte bitValue[] =  // Only have the decimal equivalents for 8 bits because this function's datatype is byte.
  {
    1,2,4,8,16,32,64,128
  };

could also be rewritten as:

  byte bitValue[] =  // Only have the decimal equivalents for 8 bits because this function's datatype is byte.
  {
    0b00000001,
    0b00000010,
    0b00000100,
    0b00001000,
    0b00010000,
    0b00100000,
    0b01000000,
    0b10000000
  };

To be a bit more obvious to someone who thinks in bits instead of decimal values... Takes more space, but should compile to the same binary...

gerrymcc: Thank you all very much for your inputs. (No pun intended.) Coming from doing Picaxe programs, I am finding information about bit manipulation with Arduino a bit thin on the ground. I am sure it is there, but I am yet to find a ready reference with all this information in one place. As I said, I am still learning. Thanks again.

Perhaps you could give an example of what you want to do so that you could be advised how best to do it.