Bool array to byte or int for shiftout?

Hello,

I'm trying to shiftout a buttonStates array to leds. Pretty simple, one can think...

I've got 16 buttons, the array is set to 16 and the two 8 channel shift register can handle 16 bits in chunks if I'm correct, since it just shift over the amount that doesn't fit in the first register to the next. Am I right so far?

My first thought is to take the 16 true/false bits in the array and put them in an int because it can handle 16 bits. It may also be possible to use bytes for this, I don't know what's best?

After searching the whole web I'm going crazy. How hard can this be? It must be so simple?? What am I missing?

After trying multiple examples I only get the invalid conversion from boolean to int or byte in the compiler..

Hint: we can't see your code

There are two easy ways to do this. You can use the shiftOut function in which case you'll need to convert your 16 bools into two bytes, or you can bit-bang the array.

AWOL:
Hint: we can't see your code

I was talking in general how to solve the problem, but sure you can have the code. Obviously the byte data line is wrong. Hopefully this will do:

boolean buttonState[16]; //array with stored state

void loop() {

 // //DIGITAL OUT SHIFT REGISTER FOR LEDS_______________________
  for (int i = 0; i < 16; i++) { //loop buttons
    byte data = toggleState; //load the button state from the array, make byte from boolean???
    if (digitalReadMux1(i) == tempDigitalRead1) { //check if pushbutton is still the same
      //ground latchPin and hold low for as long as you are transmitting
      digitalWrite(latchPin, 0);
      //send information
      shiftOut(dataPin, clockPin, LSBFIRST, data);

      byte j; // Loop shift register
      for (j = 0; j < 16; j++) {
        digitalWrite(clockPin, LOW);
        if (tempDigitalRead1 == LOW) { //if button pressed > change led on/off
          if (buttonState[i] == 1) {
            digitalWrite(dataPin, (data >> j & 1));
          }
          digitalWrite(clockPin, HIGH);
        }
        //return the latch pin to high to signal chip that it's no longer need to listen for information
        digitalWrite(latchPin, 1);
      }
    }
  }
}

DKWatson:
There are two easy ways to do this. You can use the shiftOut function in which case you'll need to convert your 16 bools into two bytes, or you can bit-bang the array.

I've tried the first one without any good result. I will check out bit-banging for sure!

I'm going to refer you to my Control Surface library again, as I understand that you're doing a very similar project :slight_smile:

The easiest way (and the one that scales best if you would want to add a third register), is to use a byte array/buffer. You then flip bits in this buffer (see links below for how to do that in practice), and you shift out all bytes in the buffer.

Here's the header file of my shift register class: Control-Surface/ShiftRegisterOut.h at 9839e310ede12f0f5f6178ba17927d9586383b08 · tttapa/Control-Surface · GitHub
And here's the implementation: Control-Surface/ShiftRegisterOut.cpp at 9839e310ede12f0f5f6178ba17927d9586383b08 · tttapa/Control-Surface · GitHub
Here's the BitArray class: Control-Surface/BitArray.hpp at 9839e310ede12f0f5f6178ba17927d9586383b08 · tttapa/Control-Surface · GitHub
As you can see BitArray is just some bit-math on a byte buffer. The index in the buffer is bitindex / 8, and the mask is just 1 << (bitindex % 8 ). As you can see, it currently uses an array on the heap, which is not a problem if you only create static instances. You could easily turn it into a template class with a fixed buffer.

Pieter

Bit-banging is quite straight forward. You have an array of bool so each entry is either 0 or 1.
Assume the array is a multiple of 8;

bool array[n*8];
for (byte i = 0; i < n; i++)
{
  for (byte j = 0; j < 8; j++
  {
    digitalWrite(output_pin, array[(i * 8) + j];
    digitalWrite(clk_pin, 1);  // clock the output into the 595
    digitalWrite(clk_pin, 0);
  }
}
digitalWrite(latch_pin, 1);  // latch the 595s to output
digitalWrite(latch_pin, 0);

That will send LSB (array[0]) first.

DKWatson:
Bit-banging is quite straight forward. You have an array of bool so each entry is either 0 or 1.
Assume the array is a multiple of 8;

Looks nice, but I get "n" was not declared in this scope, and the same with toggleState, when trying your code. Besides that it must be missing a few signs right? Parenthesis on second "for" line and on first digitalWrite line?

Do I need to declare the "n" in some way to make it work, or am I thinking wrong once again?

Thanks for your input on the bit-banging!

The Arduino shiftOut function does the bitbaning for you. If you don't want to use it, you can still use it for some inspiration:
source

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
	uint8_t i;

	for (i = 0; i < 8; i++)  {
		if (bitOrder == LSBFIRST)
			digitalWrite(dataPin, !!(val & (1 << i)));
		else	
			digitalWrite(dataPin, !!(val & (1 << (7 - i))));
			
		digitalWrite(clockPin, HIGH);
		digitalWrite(clockPin, LOW);		
	}
}

PieterP:
I'm going to refer you to my Control Surface library again, as I understand that you're doing a very similar project :slight_smile:

You are right, we are probably doing the same stuff kind of. I like your library but I feel kind of stuck when I don't understand my whole code and have the flexibility of editing it exactly how I want it.

For example I want the buttons to act like togglebuttons, but send midi on release. Does your library handle this?

I may be able to use some parts from your library, I will check out the things you linked, thanks! :slight_smile:

The Arduino shiftOut function does the bitbaning for you. If you don't want to use it, you can still use it for some inspiration:

Aaah! Good to know, I didn't understand that! So how do I just get the array in the shiftOut? Have read the manual a dussin of times but I didn't catch it anyway, I'm really stupid hence my name. ;D

Can I simply declare the uint8_t val = toggleState[16], or something?

Btw, shall the shiftOut be in 8 bits, or can I change to 16 instead? Maybe it doesn't matter, the shiftOut perhaps do the work for me anyway even if set to 8?

shiftOut is the way to go if you have bytes to move. You can also use SPI and turn it over to the hardware, but then to are limited to the pins you can use.
The 'n' is a placeholder for the multiple of 8 bools that you have in your array! Glasses maybe?? If you look at the line above I declared the array as n8. in your case with a 16 byte array, ( n8 ) will equal 16 so n = 2.

You can also do this:
You want transform your 16 bools into a int number. Bools can be 0 or 1. So you can have the array and the number. (or you can also don't use the array). You can make the number=0 and after, in a 16 times for (0/15) moltiply number and 2 and after add the for° element of array

Silente:
You can make the number=0 and after, in a 16 times for (0/15) moltiply number and 2 and after add the for° element of array

And who can argue with that?

@Silente: please at least do a cursory proofreading before hitting the "post" control.

shiftOut only works with bytes,

DKWatson:
shiftOut is the way to go if you have bytes to move. You can also use SPI and turn it over to the hardware, but then to are limited to the pins you can use.
The 'n' is a placeholder for the multiple of 8 bools that you have in your array! Glasses maybe?? If you look at the line above I declared the array as n8. in your case with a 16 byte array, ( n8 ) will equal 16 so n = 2.

Great information! Actually I already got my glasses on and letters seem to be a common thing to use in C++, therefore my question. I see that you declared the array, my wondering was if you need to declare the simple "n" as well, but after your answer I understood the meaning of the placeholder!

AAAND IT WORKS!! Big thank you!

....and now I should be able to make a variable of the "n" to set the amount of shift registers I'm using right? ( To just change the "n" to a number in the top of the sketch, instead of in the for loop as well?)

AWOL:
And who can argue with that?

@Silente: please at least do a cursory proofreading before hitting the "post" control.

Is it not a solution? Why? Have I misunderstand the question? If so @OP what is the question? And more, I told that my idea is a possible soluyion for the question that I understood, if it is incorrect also the op understand that all of my answere is useless.
If the question is correct why my answere is not correct? Does I misunderstand maths?

Imbecillen:
I feel kind of stuck when I don't understand my whole code and have the flexibility of editing it exactly how I want it.

I totally understand, I'm just like that myself :slight_smile:

The goal of the library is to make abstraction of the low-level stuff that you don't have to worry about, but still allow for many customizations in places where it matters.

For example, MIDI I/O is all handled for you, but you can select many different MIDI Interfaces, and you can easily add ones yourself, while still being able to reuse the parts you want to keep.

Same for IO: shift registers and multiplexers are abstracted, and you can just use digitalRead, analogRead, digitalWrite, etc. as if the multiplexed pins are just normal IO pins.

For example, this sketch will blink an LED connected to a shift register. As you can see, the code in the setup and loop is identical to the normal Arduino blink example.

Code:

---



```
#include <Control_Surface.h> // Include the Control Surface library.

using namespace ExtIO;

const pin_t latchPin = 10;  // Pin connected to ST_CP of 74HC595
const pin_t dataPin  = 12;  // Pin connected to DS of 74HC595
const pin_t clockPin = 13;  // Pin connected to SH_CP of 74HC595

/** Instantiate a shift registers on the correct pins, most significant bit
* first, and a total of 8 outputs. */
ShiftRegisterOut sreg = { dataPin, clockPin, latchPin, MSBFIRST, 8 };

const pin_t ledPin = sreg.pincolor=#000000[/color]; // first pin of the shift register

void setupcolor=#000000[/color] { /* Initialize everything. */
  sreg.begincolor=#000000[/color];
  pinMode(ledPin, OUTPUT); // You don't even need this line, since
                          // shift registers are always outputs
}

void loopcolor=#000000[/color] { /* Toggle the LED every ½ second. */
  digitalWrite(ledPin, HIGH);
  delaycolor=#000000[/color];
  digitalWrite(ledPin, LOW);
  delaycolor=#000000[/color];
}
```

|

If you want to add your own MIDI buttons that only send on release, you can just add your own MIDI Output Element. The code you have to write yourself is minimal.
The library automatically discovers your objects, you can use the debounced button classes provided by the library, you can use the MIDI output provided by the library, etc.

For example, this is the class that sends MIDI events based on input from a button:

You can see how easy it is. You just have to implement two methods: a begin function that is called once (automatically, when calling Control_Surface.begin()) that initializes your object, and a update function, that is called continuously (automatically, when calling Control_Surface.loop()).

 template <DigitalSendFunction sendOn, DigitalSendFunction sendOff>
 class MIDIButton : public MIDIOutputElement {
   protected:
     MIDIButton(pin_t pin, uint8_t baseAddress, uint8_t baseChannel)
         : button{pin}, baseAddress(baseAddress), baseChannel(baseChannel) {}
 
   public:
     void begin() final override { button.begin(); }
     void update() final override {
         Button::State state = button.getState();
         if (state == Button::Falling) {
             sendOn(baseChannel, baseAddress);
         } else if (state == Button::Rising) {
             sendOff(baseChannel, baseAddress);
         }
     }
 
   private:
     Button button;
     const uint8_t baseAddress;
     const uint8_t baseChannel;
 };

Source and documentation: https://tttapa.github.io/Control-Surface/Doc/Doxygen/dd/d47/Abstract_2MIDIButton_8hpp_source.html

Imbecillen:
I may be able to use some parts from your library, I will check out the things you linked, thanks! :slight_smile:

If you have any questions, just ask!

Imbecillen:
....and now I should be able to make a variable of the "n" to set the amount of shift registers I'm using right? ( To just change the "n" to a number in the top of the sketch, instead of in the for loop as well?)

Yes. Use something other than 'n' though. Single letter global variables are never a good idea.

DKWatson:
Yes. Use something other than 'n' though. Single letter global variables are never a good idea.

Applause! Is it possible in any way to set MSBFIRST or LSBFIRST with the bit-banging or do I need to use shiftOut for this? My LEDs are corresponding to my button presses, but in the wrong order. Probably due to the hardware, but it should anyway be possible to change order in the code right?

Imbecillen:
Applause! Is it possible in any way to set MSBFIRST or LSBFIRST with the bit-banging or do I need to use shiftOut for this? My LEDs are corresponding to my button presses, but in the wrong order. Probably due to the hardware, but it should anyway be possible to change order in the code right?

Just reverse the loop, go from n-1 down to zero instead of from zero to n.

You'll need to reverse both loops.