Handle up to 10-15 buttons inputs simultaneously

Can 8 sn74hc165 chips have a latency the lowest as possible to make the inputs apper simultaneous to the user?
I have about 45 buttons connected to these registers, but I need the simultaneous interaction of at most 10 buttons. The sketch contains just the reading of the inputs and the send part to the midi perpherals (about 5 serial.write).
Would I be able to do that?

The registers are connected in series.

Short answer yes, maybe.

We need to see the code first. There is usually a lot of dead weight there.

Do you "Daisy chain" the chips or connect them individually to your board (Arduino Nano, Uno, Mega?).
Do you use SPI or shiftout.

There is too little information to help you.

Microcontrollers work on timescales that are extremely fast indeed compared to our human timescales. For 45 buttons, even if not using SPI, it would certainly appear to us humans to be simultaneous (unless you totally screw up your code in some way, so do post that as suggested by v3xX). Using SPI, you could read many hundreds of buttons and it would still appear simultaneous!

v3xX:
Do you “Daisy chain” the chips or connect them individually to your board (Arduino Nano, Uno, Mega?).

He said “The registers are connected in series.”

v3xX:
Do you use SPI or shiftout.

Not really relevant.


I hope Apocalypse480 has not already wired this up, as it is not the best way to do it by any means!

Far simpler to wire them up as a matrix though you will need to include a diode in series with each button, They can be “scanned” with a 74HC595 or 74HC4017 and read with a 74HC165.

This vastly simplifies the wiring and just two chips. If you used chained 74HC165 (six of them for 45 buttons) you need a pull-up for each; in a matrix you need a diode for each and eight pull-ups on the single 74HC165.

Apocalypse480:
Can 8 sn74hc165 chips have a latency the lowest as possible to make the inputs apper simultaneous to the user?

You're talking about a human input device. The SPI bus of an Arduino UNO can clock in data @ 8 MHz. Latency from reading the inputs is a non-issue.

Each MIDI message takes around a millisecond to transmit (30 symbols / 31250 baud). That's two orders of magnitude more than the time it takes to clock in 8 bytes over SPI.

Paul__B:
Far simpler to wire them up as a matrix though you will need to include a diode in series with each button, They can be "scanned" with a 74HC595 or 74HC4017 and read with a 74HC165.

This vastly simplifies the wiring and just two chips. If you used chained 74HC165 (six of them for 45 buttons) you need a pull-up for each; in a matrix you need a diode for each and eight pull-ups on the single 74HC165.

+1

Pieter

If you in fact use a 74HC4017 with a 74HC165, you can service up to 80 keys, but because the 74HC4017 gives active-high outputs, you need pull-downs on the 74HC165.

I am actually using 74hc165 chips daisy chained, here is the sketch (it is incomplete at the moment, the MIDI part is missing):

/*
 * SN74HC165N_shift_reg
 *
 * Program to shift in the bit values from a SN74HC165N 8-bit
 * parallel-in/serial-out shift register.
 *
 * This sketch demonstrates reading in 16 digital states from a
 * pair of daisy-chained SN74HC165N shift registers while using
 * only 4 digital pins on the Arduino.
 *
 * You can daisy-chain these chips by connecting the serial-out
 * (Q7 pin) on one shift register to the serial-in (Ds pin) of
 * the other.
 * 
 * Of course you can daisy chain as many as you like while still
 * using only 4 Arduino pins (though you would have to process
 * them 4 at a time into separate unsigned long variables).
 * 
*/

unsigned char commands[10][3]={
{0x90,0x55,0x7f},{0x90,0x55,0x00}, //JOGWHEEL SX TOUCH/RELEASE
{0xb0,0x41,0x01}, //JOGWHEEL SX CLOCKWISE SPIN + TOUCH
{0xb0,0x41,0x7f}, //JOGWHEEL SX COUNTERCLOCKWISE + TOUCH
{0xb0,0x40,0x01}, //JOGWHEEL LATERAL CLOCKWISE SPIN
{0xb0,0x40,0x7f}, //JOGWHEEL LATERAL COUNTERCLOCKWISE SPIN
{0x90,0x32,0x7f},{0x90,0x32,0x00}, //PLAY-PAUSE SX PRESS/RELEASE
{0x90,0x31,0x7f},{0x90,0x31,0x00}, //CUE PRESS/RELEASE
{0x90,0x30,0x,7f},{0x90,0x30,0x00}, //SYNC SX PRESS/RELEASE
{0x90,0x56,0x7f},{0x90,0x56,0x00}, //SHIFT SX PRESS/RELEASE
{0x90,0x01,0x7f},{0x90,0x01,0x00}, //LOOP ON SX PRESS/RELEASE
{0x90,0x00,0x7f},{0x90,0x00,0x00}, //LOOP X1/2 SX PRESS/RELEASE
{0x90,0x02,0x7f},{0x90,0x02,0x00}, //LOOP X2 SX PRESS/RELEASE
{0x90,0x03,0x7f},{0x90,0x03,0x00}, //AIR FX PRESS/RELEASE
};

/* How many shift register chips are daisy-chained.
*/
#define NUMBER_OF_SHIFT_CHIPS   1

/* Width of data (how many ext lines).
*/
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8

/* Width of pulse to trigger the shift register to read and latch.
*/
#define PULSE_WIDTH_USEC   5

/* Optional delay between shift register reads.
*/
#define POLL_DELAY_MSEC   1

/* You will need to change the "int" to "long" If the
 * NUMBER_OF_SHIFT_CHIPS is higher than 2.
*/
#define BYTES_VAL_T unsigned int

int ploadPin        = 8;  // Connects to Parallel load pin the 165
int clockEnablePin  = 9;  // Connects to Clock Enable pin the 165
int dataPin         = 11; // Connects to the Q7 pin the 165
int clockPin        = 12; // Connects to the Clock pin the 165

BYTES_VAL_T pinValues;
BYTES_VAL_T oldPinValues;

/* This function is essentially a "shift-in" routine reading the
 * serial Data from the shift register chips and representing
 * the state of those pins in an unsigned integer (or long).
*/
BYTES_VAL_T read_shift_regs()
{
    long bitVal;
    BYTES_VAL_T bytesVal = 0;

    /* Trigger a parallel Load to latch the state of the data lines,
    */
    digitalWrite(clockEnablePin, HIGH);
    digitalWrite(ploadPin, LOW);
    delayMicroseconds(PULSE_WIDTH_USEC);
    digitalWrite(ploadPin, HIGH);
    digitalWrite(clockEnablePin, LOW);

    /* Loop to read each bit value from the serial out line
     * of the SN74HC165N.
    */
    for(int i = 0; i < DATA_WIDTH; i++)
    {
        bitVal = digitalRead(dataPin);

        /* Set the corresponding bit in bytesVal.
        */
        bytesVal |= (bitVal << ((DATA_WIDTH-1) - i));

        /* Pulse the Clock (rising edge shifts the next bit).
        */
        digitalWrite(clockPin, HIGH);
        delayMicroseconds(PULSE_WIDTH_USEC);
        digitalWrite(clockPin, LOW);
    }

    return(bytesVal);
}

/* Dump the list of zones along with their current status.
*/
void display_pin_values()
{
    Serial.print("Pin States:\r\n");

    for(int i = 0; i < DATA_WIDTH; i++)
    {
        Serial.print("  Pin-");
        Serial.print(i);
        Serial.print(": ");

        if((pinValues >> i) & 1)
            Serial.print("HIGH"); //place here the link to the MIDI MATRIX
        else
            Serial.print("LOW");

        Serial.print("\r\n");
    }

    Serial.print("\r\n");
}

void setup()
{
    Serial.begin(9600);

    /* Initialize our digital pins...
    */
    pinMode(ploadPin, OUTPUT);
    pinMode(clockEnablePin, OUTPUT);
    pinMode(clockPin, OUTPUT);
    pinMode(dataPin, INPUT);

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

    /* Read in and display the pin states at startup.
    */
    pinValues = read_shift_regs();
    display_pin_values();
    oldPinValues = pinValues;
}

void loop()
{
    /* Read the state of all zones.
    */
    pinValues = read_shift_regs();

    /* If there was a chage in state, display which ones changed.
    */
    if(pinValues != oldPinValues)
    {
        Serial.print("*Pin value change detected*\r\n");
        display_pin_values();
        oldPinValues = pinValues;
    }

    delay(POLL_DELAY_MSEC);
}

I am actually using Arduino UNO board.

You have a lot of code there that could be made a lot faster using SPI.transfer and pins 10 (ssPin), 12 (MISO), and 13 (SCK)

digitalWrite (ssPin, LOW);
digitalWrite (ssPin, HIGH); // pulse to capture at HC165 inputs (or maybe High, then Low, I didn't read the datasheet)
for (x=0; x<4; x=x+1){
HC165inputs[x] = SPI.transfer(0);
}
// all 5 registers shifted in, do something with the data

Or just 0, 1 if you only have 2 shift registers.

CrossRoads:
You have a lot of code there that could be made a lot faster using SPI.transfer and pins 10 (ssPin), 12 (MISO), and 13 (SCK)

digitalWrite (ssPin, LOW);

digitalWrite (ssPin, HIGH); // pulse to capture at HC165 inputs (or maybe High, then Low, I didn’t read the datasheet)
for (x=0; x<4; x=x+1){
HC165inputs = SPI.transfer(0);
}
// all 5 registers shifted in, do something with the data



Or just 0, 1 if you only have 2 shift registers.

Sorry for all these days past, but i was a little busy:)
I am not very experienced at the moment, can you explain me why SPI is faster? I’ve just saw how it works, but I can’t figure out in what way it can be faster.
Thanks!

SPI and shiftOut() basically do the same thing. The shiftOut() function can use any pins you like, whereas with SPI you have to use certain pins. That's the downside. The upside is that shiftOut() is a short piece of code, but SPI is a piece of hardware built into the Arduino chip. Being hardware, it's probably hundreds of times faster, and can be left to get in with the job while the CPU does something else, like getting the next piece of data ready to send.

PaulRB:
SPI and shiftOut() basically do the same thing. The shiftOut() function can use any pins you like, whereas with SPI you have to use certain pins. That's the downside. The upside is that shiftOut() is a short piece of code, but SPI is a piece of hardware built into the Arduino chip. Being hardware, it's probably hundreds of times faster, and can be left to get in with the job while the CPU does something else, like getting the next piece of data ready to send.

Thank tou very much, now it is all clear,
I'll try to use SPI instead of shiftOut().
Anyway, will I be able to read that number of buttons "simultaneously" if the code is about the one I posted (consider the changes to use SPI)?
Thanks