Bit Manipulation?

Hello I'm trying to perform some bit manipulations using a 74HC595 IC to light up 8 leds.

I just did the basics, like the circular shift.

This is the code that I'm using for the circular shift:

int latchPin = 11;
int clockPin = 9;
int dataPin = 12;
int dt = 2000;
uint8_t n1 = 128, n2 = 1;

byte myByte = 0b10000001; //in BIN

void setup() {
Serial.begin(9600);
pinMode(latchPin,OUTPUT);
pinMode(dataPin,OUTPUT);
pinMode(clockPin,OUTPUT);
}



//circular shift to the left
void loop() {
digitalWrite(latchPin,LOW);
shiftOut(dataPin,clockPin,LSBFIRST,myByte);
digitalWrite(latchPin,HIGH);

Serial.print("BIN: ");
Serial.print(myByte,BIN);
Serial.print(" --> ");
Serial.print("HEX: ");
Serial.print(myByte,HEX);
Serial.print(" --> ");
Serial.print("DEC: ");
Serial.println(myByte,DEC);
myByte = myByte/128 + myByte*2;    //shift by left //using MSBFIRST
//myByte = myByte*2;    //shift by right //using MSBFIRTS
delay(dt);
}

But now I would like to obtain an output like this in myByte:

1 0 0 0 0 0 0 1
0 1 0 0 0 0 1 0
0 0 1 0 0 1 0 0
0 0 0 1 1 0 0 0
0 0 0 1 1 0 0 0
0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0
1 0 0 0 0 0 0 1.....

and so on it repeats

I've read some people use iostream in c++ to perform an output like this, but if i understood well arduino has not enough memory to run iostream or other heavy library.

How can I perform this task? Thank You

How can I perform this task?

One very simple way that involves no calculation, bit masking, bit shifting or brain power would be to put the required patterns in an array

Yes I was trying to avoid that way, just to practice bit manipulation.

For example i found searching in the web a person who wrote this code, that works in c++, but how can I adapt this code to my arduino? Because this code was written only for c++.

This is the code:

#include <iostream>
#include <iomanip>
#include <limits>

int main() 
{
    unsigned char b = 0b10000001;
    int width = std::numeric_limits<unsigned char>::digits / 2;

    for ( int i = 0; i < width; i++ )
    {
            std::cout << std::hex << static_cast<int>( b ) << " - "
                      << std::dec << static_cast<int>( b ) << '\n';
            b = ( b & ( 0b1111 << width ) ) >> 1 | ( b & 0b1111 ) << 1;
    }

    for ( int i = 0; i < width; i++ )
    {
            std::cout << std::hex << static_cast<int>( b ) << " - "
                      << std::dec << static_cast<int>( b ) << '\n';
            b = ( b & ( 0b1111 << width ) ) << 1 | ( b & 0b1111 ) >> 1;
    }

    return 0;
}

A little something to play with

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  byte output = 0b10000001;
  for (int bit = 0; bit < 8; bit++)
  {
    printFullBin(output);
    if (bit == 3)
    {
      continue;
    }
    bitWrite(output, bit + 1, 1);
    bitWrite(output, 7 - bit - 1, 1);
    bitWrite(output, bit , 0);
    bitWrite(output, 7 - bit , 0);
  }
}

void loop()
{
}

void printFullBin(int input)
{
  for (int bit = 7; bit >= 0; bit--)
  {
    Serial.print(bitRead(input, bit));
  }
  Serial.println();
}

It should not be difficult to change it to use bit manipulation instead of the bitRead() and bitwrite() functions

The skipping of bit == 3 is a kludge

The particular pattern you've given is just one bit right shifted every iteration and one bit left shifted every iteration. So you could have two variables, left shift one, right shift the other, and bitwise "or" the two to get your output.

uint8_t up, down, output, k ;
up = 0b00000001 ;
down = 0b10000000 ;
for (k=0; k<8 ; k++)
  {
    output = up | down ;
    printf("%x, %x, %x\n", up, down, output) ;
    up = up << 1 ;
    down = down >> 1 ;
  }

Riemanndiy:
But now I would like to obtain an output like this in myByte:
1 0 0 0 0 0 0 1
0 1 0 0 0 0 1 0
0 0 1 0 0 1 0 0
0 0 0 1 1 0 0 0
0 0 0 1 1 0 0 0
0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0
1 0 0 0 0 0 0 1.....

and so on it repeats
How can I perform this task? Thank You

In that particular example you could shifting bits left and right from myByte and just increment a Variable example T18) for each sequence, resetting that variable back to 0 when it reaches 8
Byte B1 = myByte << T18; // binary: 00000010 when T18 = 1
Byte B2 = myByte >> T18; // binary: 01000000 when T18 = 1
Byte B3 = B1 | B2; // bitwise OR 01000010

Here's another option. It's agnostic as to the bit size of the input (subject to changing the data type, of course). You could implement various controls to avoid the infinite loop, but this at least shows you the general algorithm.

    uint8_t startByte, newByte;
    startByte = 0b10000001;
    for (int i = 1; true; i++) {
      newByte = startByte >> i;
      newByte |= startByte << i;
      // do something with newByte 
      if (newByte == startByte) {
          i = 0;
      }
    }

Can anyone provide the complete code so I can successfully upload the code? because I integrated your part of the code, in my original one and compiles, but doesn't work, nor i can't see anything in the serial monitor.

Thank you @UkHelibob, i will study better your code but it works.

Anyway I ended up with another solution that works using a for cicle, noticing that the output I wanted was:

129,66,36,24,24,36,66,129 = 128+1; 64+2 ; 32+4; 16+8; 16+8; 32+4; 64+2; 128+1;

So that:

int latchPin = 11;
int clockPin = 9;
int dataPin = 12;
int dt = 2000;
uint8_t n1 = 128, n2 = 1;
byte myByte = 0b10000001; //in BIN

void setup() {
Serial.begin(9600);
pinMode(latchPin,OUTPUT);
pinMode(dataPin,OUTPUT);
pinMode(clockPin,OUTPUT);
}

//circular shift to the left
void loop() {
digitalWrite(latchPin,LOW);
shiftOut(dataPin,clockPin,LSBFIRST,myByte);
digitalWrite(latchPin,HIGH);
int i;


myByte = 0b10000001; //restarting the value of 129
        Serial.print("BIN: ");
        Serial.print(myByte,BIN);
        Serial.print(" --> ");
        Serial.print("HEX: ");
        Serial.print(myByte,HEX);
        Serial.print(" --> ");
        Serial.print("DEC: ");
        Serial.println(myByte,DEC);
        delay(200);


    for (int i = 0; i < 7; i++) {
        Serial.print("i:  ");
        Serial.println(i);
        //int i1 = i+1;
        //int myGap = myByte - (pow(2,i));      //no need to round when it's raised to 0;
        //int firstpart = (myGap/2);
        //int secondpart = 0.5 + pow(2,i1);     //because it rounds the number. (i.e --> 1.9999 = 1)
        //myByte = firstpart+ secondpart;

          myByte = (myByte - (pow(2,i)))/2 + (0.5 + pow(2,i+1));
        
        //Serial.print("firstpart: ");
        //Serial.println(firstpart);
        //Serial.print("secondpart: ");
        //Serial.println(secondpart);
        //delay(3000);
        Serial.print("BIN: ");
        Serial.print(myByte,BIN);
        Serial.print(" --> ");
        Serial.print("HEX: ");
        Serial.print(myByte,HEX);
        Serial.print(" --> ");
        Serial.print("DEC: ");
        Serial.println(myByte,DEC);
        digitalWrite(latchPin,LOW);
        shiftOut(dataPin,clockPin,LSBFIRST,myByte);
        digitalWrite(latchPin,HIGH);
        delay(100);
    }
//myByte = myByte*2;    //shift by right //using MSBFIRTS
//delay(dt);
}

Anyway i will look for your suggestion and point of views if you can upload a complete code. Thanks

Riemanndiy:
Yes I was trying to avoid that way, just to practice bit manipulation.

Why?

The example you give is obviously trivial, and far more efficiently coded as an array.

Perhaps you should explain what you really propose to do?

What's wrong with the code in reply #2?

I never used an array in arduino, so I wouldn't know how to set it up. Totally nothing wrong

Where does the array come into it?

...a 74HC595 IC to light up 8 leds.

I just did the basics, like the circular shift.

:wink: This wouldn't work for your pattern that goes two directions at once, but, a million years ago I made a chase light effect with a shift register and no microcontroller! I used a bi-directional shift register so it could go both directions, and so inverters that I could switch-in to get an optional Johnson Counter effect. (There was some kind of sound activated "clock".)

(You could probably get your pattern with two shift registers going opposite directions.)


FYI - If you're going to do a lot of "bit programming" it's common to work in hexadecimal. Everything in the computer is binary, and of course we usually write the program using decimal but we can also can use hex. You can fairly-easily learn to convert numbers of any length between binary and hex in your head It's a lot easier (for humans) to read/write hex than binary, especially when you have more than 8 bits.

And, it's a LOT easier than converting between binary and decimal! You just have to learn 16 conversions (zero through F) and (unlike decimal) the "patterns" repeat with bigger numbers.

For example, 3 hex is 0011, and 33 hex is 00110011, and 333 hex is 001100110011. Each hex digit gets converted to exactly 4 binary bits. (With decimal you'd need a calculator.)

The Windows calculator in "programmer mode" will do these conversions.

I'll be honest - I haven't been using hex lately and I've forgotten a few numbers, but at one time I made some flash cards to memorize the conversions (and the decimal conversions for A through F).

You already know 0 and 1. Most of the other "patterns" are pretty easy to remember. Then, maybe 5 numbers are a little hard to remember (I usually forget B & D).

0 hex = 0000 (same in binary & decimal)
1 hex = 0001 (same in binary & decimal)
2 hex = 0010 (easy if you know the bit positions/weights)
3 hex = 0011 (easy pattern to remember)
4 hex = 0100 (easy if you know the bit positions/weights)
5 hex = 0101 (easy pattern to remember)
6 hex = 0110 (not too hard, one less than 7)
7 hex = 0111 (easy pattern to remember)
8 hex = 1000 (easy if you know the bit positions/weights)
9 hex = 1001 (not too hard, one more than 8)
A hex = 1010 (easy pattern, A hex =10 decimal = one more than 9, and it "looks like" ten-ten)
B hex = 1011 (this one is sometimes hard for me to remember)
C hex = 1100 (maybe an easy pattern, maybe hard to remember)
D hex = 1101 (maybe hard to remember)
E hex = 1110 (not too hard, one less than F)
F hex = 1111 (easy pattern to remember)

TheMemberFormerlyKnownAsAWOL:
Where does the array come into it?

An array of 8 bytes, each of the required bit pattern

Here's one implementation of the byte array. You should definitely check out arrays... they will come in handy at some point in your Arduino adventure.

byte byteArray[8] = {129,66,36,24,24,36,66,129};
for (int i = 0; i < 8; i++)  {
 // ...stuff before  
 shiftOut(dataPin,clockPin,LSBFIRST,byteArray[i]);
 // ...stuff after
}

But the code in reply #2 doesn't use arrays.

I'm confused.

Yes, you won't get much practice with bit manipulation using a look up table.

TheMemberFormerlyKnownAsAWOL:
What's wrong with the code in reply #2?

It is absurdly obscure and poorly explained. :astonished:

Which means we have no idea to what it compiles. :roll_eyes:

So you could have two variables, left shift one, right shift the other, and bitwise "or" the two to get your output.

This sounds like the best idea for the particular pattern requested.
The array is the best "general purpose" idea.
The example code in #2 is awful, using obscure C++ constructs where they aren't necessary ("std::numeric_limits::digits", Hmmph), and probably pretty inefficient.. (also obscured by the casts in the output code.)

@OP,
Is this different than the answers you are seeing in stackexchange?