Bit operations tutorials?

Guys, I'm trying to learn how to work with bits so I can make my libraries use less memory. (thanks to a tip from a power user) ;-)

So, for instance, I know that unsigned int is a 16 bit number.

What I want to know is how to, in an easy and fast way, check for a bit and change the bit status.

I have read the bitwise operations of the Arduino site but didn't understand exactly how I could change my libraries in a way that it doesn't slow too much the whole process and make it use less memory.

In any event, I'm using the Arduino Mega, which has 8K of RAM, and my current project is already using 6K. (MIDI Drum Patterns takes a lot of space, I'm trying to change that)

Any help or advice will be much appreciated.

Wk

Could you share the code of the library? Think it belongs in the section Software Development by the way...

check for a bit and change the bit status.

Did you also read these: - http://arduino.cc/en/Reference/BitRead

MIDI Drum Patterns takes a lot of space, I'm trying to change that

Share your current implementation, maybe we could devise some sort of simple compression scheme.

BIT manipulations are pretty simple.

Data is stored in Bytes, right? 8 bit uC?

So, declare a variable byte 8_bit_var = 0; // clear all bits to start

to set a bit: 8_bit_var = 8_bit_var | 0b01010101; // OR in 1 to set bits (left to right) 6, 4, 2, 0 (might need capital B instead, try it & see what compiles) 8_bit_var now equals 0b01010101 or 0x55

to clear a bit: 8_bit_var = 8_bit_var & 0b10111011; // AND in 0 to clear bits 6, 2;

8_bit_var now equals 0b00010001 or 0x11

Use whatever data type you like.

Well, this isn’t related to your direct question, but it may help your memory problem.

You may be able to store the patterns in progmem, the flash memory that your program is stored in. This gives you a bunch more space. (128kb on the atmega1280)
http://www.arduino.cc/en/Reference/PROGMEM

As for your original question, bitRead() and bitWrite() could be used.
http://www.arduino.cc/en/Reference/BitRead
You could also use direct bit math. To see how, here’s the source code for them:

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))

Edit: Whoops, two people beat me as I was typing.

Edit: Whoops, two people beat me as I was typing.

But at least the answers are consistent at large and complementary in the detail! ;)

I'm using the Arduino Mega, which has 8K of RAM, and my current project is already using 6K. (MIDI Drum Patterns takes a lot of space, I'm trying to change that)

Don't confuse the Program Memory's Flash Space with the Run-time RAM.

As sciguy mentions, you can modify your code so that things like patterns are stored (and used) directly in of the PROGMEN's Flash space.

Thanks guys, its all great, it really helped me out, specially bitRead and the Macros. Its all clear as crystal now. I just had to ask to check if maybe I was confusing things up. :-[

The Drum Patterns is user-changeable, so RAM must be used. BUT, I'm using a SD Card as extra memory. ;-)

Check this out: http://open.wusik.com

I will post the code as soon as I have something ready. But you can check the C165 code at http://arduino.wusik.com

Wk

Guys, its working, thanks again. But it still needs improving…

Here’s the code so far:

C165.h

/*
 
      Created by WilliamK @ Wusik Dot Com (c) 2010
      http://arduino.wusik.com

      8 to 16 Inputs with only 3 pins on the Arduino using the following chip: 74HC165N
      http://www.sparkfun.com/products/9519

      Typical Usage:

            Setup:

                  C165 Inputs = C165(25,27,26);

                  C165(      Connects to Parallel load pin the 165, 
                              Connects to the Q7 pin the 165,
                              Connects to the Clock pin the 165);      // Same values for Tick();

            Loop:

                  if (Inputs.Tick(25,27,26)) // Returns True if something changed //
                  {
                        for (int xc=0; xc<16; xc++)
                        {
                              if (Inputs.hasEvent(xc))
                              {
                                    // Happens once for every click //
                              }
                        }
                  }

*/

#ifndef C165_h
#define C165_h

// 1 or 2 C165 chips //
#define NUMBER_OF_CHIPS   2      

#if NUMBER_OF_CHIPS == 2
      #define BYTES_VALT unsigned int
#else
      #define BYTES_VALT byte
#endif
#define BUS_WIDTH      NUMBER_OF_CHIPS * 8

#include <inttypes.h>
#include "HardwareSerial.h"

class C165
{
public:
    C165(byte loadPin, byte dataPin, byte clockPin);
      boolean Tick(byte loadPin, byte dataPin, byte clockPin);
      void Reset(void);
      boolean hasEvent(byte Pos);

private:
      BYTES_VALT values;
      BYTES_VALT prevvalues;
      BYTES_VALT prevhigh;
};

#endif

C165.cpp

/*
 
      Created by WilliamK @ Wusik Dot Com (c) 2010
      http://arduino.wusik.com

      Check the C165.h file for instructions
 
*/

#include "WConstants.h"
#include "C165.h"

// ------------------------------------------------------------------------------------------- //
C165::C165(byte loadPin, byte dataPin, byte clockPin)
{
      pinMode(loadPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
      pinMode(dataPin, INPUT);
      digitalWrite(clockPin, LOW);
      digitalWrite(loadPin, HIGH);

      Reset();            
}

// ------------------------------------------------------------------------------------------- //
boolean C165::Tick(byte loadPin, byte dataPin, byte clockPin)
{
      byte tempInputs;

      digitalWrite(loadPin, LOW);
      digitalWrite(loadPin, HIGH);
      for(int i=(BUS_WIDTH-1); i >= 0; i--)
      {
            tempInputs = digitalRead(dataPin);
            if (tempInputs == LOW && bitRead(prevhigh,i) > 0) bitSet(values,i);
            bitWrite(prevhigh,i,tempInputs);

            digitalWrite(clockPin, HIGH);
            digitalWrite(clockPin, LOW);
      }

      if (values != prevvalues)
      {
            prevvalues = values;
            return true;
      }

      return false;
}

// ------------------------------------------------------------------------------------------- //
void C165::Reset() 
{ 
      values = prevvalues = prevhigh = 0;
}

// ------------------------------------------------------------------------------------------- //
boolean C165::hasEvent(byte Pos)
{
      if (bitRead(values,Pos) > 0)
      {
            bitClear(values,Pos);
            return true;
      }

      return false;
}

Now, a few more questions...

Is there a global temporary variable I could use instead of creating my own just for this? In this case I mean for this part:

boolean C165::Tick(byte loadPin, byte dataPin, byte clockPin)
{
      byte tempInputs;

...

tempInputs = digitalRead(dataPin);

Maybe there's already one I could use from the Arduino code itself? Just checking...

Also, is there a way to have 3 internal fixed constants that are set by the Constructor, therefore, avoiding using more RAM but not having to pass the Pins numbers to Tick()? Also checking, as I have never done that before. ;-)

Wk