Addressable chain of buttons

I would like to make very long chain of buttons, at least 32 buttons in row.
Requirements are:

  1. Buttons(single units) need to be daisy chain, first connected to second, second to third and so on.
  2. There should be fixed amount of wires, hopefully 3-4. Vcc, Ground and data.
  3. All buttons need to be addressable(being able to tell what specific button is pressed and released)
  4. Any number of buttons can be pressed at same time and you should still be able to tell what specific buttons are pressed.

It's basically reversed addressable LED strip.

How can I go about solving this problem ?
What hardware components can make this easy ?
And what would be cheapest solution?

Where would I find a "reverse WS2812" I.C.?

Sounds "basically" like a voltage divider... using buttons, 1% tolerance resistors... except for the "infinite buttons at one time." Maybe a series of 74HC165 shift registers?

Why?

The voltage divider suggested will work but is there a specific reason you need to daisy chain them?

Maybe this is what you need.
Leo..

1 Like

In a similar project I used DS2401 connected in parasite mode.
As each one has a unique serial number, it is easy to know which button was pressed.

1 Like

LOL!

You can daisy-chain input shift registers on SPI bus and connect hardware debounced switches to that.

ps - shift registers are cheap but the output regs are cheaper.

1 Like

An option is to use analog input pin, please refer to this library:

as long as you only hit 1 button at a time. 30 steps is cutting it fine btw.

Buttons with resistors are unreliable, and that gets worse over time when the contacts oxidise.
Shift registers with SPI only work over short distances. 32 buttons in a row...
Maybe OP should tell us more about the project.
Leo..

4 X 8 matrix, like a keyboard?

Cool -- so you'd use normally-open buttons on the grounds of each and then poll for serial numbers?

The OneWire DS2413 I linked to in post#4 has two I/O pins.
It seems that one can be used for a button, and the other one for a feedback LED.
Two (or three) wires, all the way to button 32.
OP could be the first one to try this.
Leo..

Yes.

1 Like

That distance depends on SPI clock speed that does have a default divider of 4 but can be higher. I can say the same about 3 wire serial.

The same chain can be run fast using bit shifting. And that all is just the distance to the chained registers, from those to the buttons is another matter which the button circuitry addresses.

Blanket "you can't" become beginner electronic factoids that surface in threads over design choice.

This code may be used to id button pressed.

You need press all button to read and put into array when press a especial button
or modify code and put the value of all 1 wire into array.
When use auto read, the order into array will be the first serial into first array position
and so on....

#include <OneWire.h>                  // One wire lib
//https://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
#define readOneWires 4                // Button for read all One Wires and save at array
OneWire  ds(3);                       // Connect your 1-wire device to pin 3
byte myCount = 0;                     // Onewire found
unsigned int OneWireAdd[32] = {0};    // Array for onewire add
bool flag = false;                    // Msg control
unsigned long reReadTime = 5000;      // Time between 2 reads
unsigned long lastRead = 0;           // Last read time
//----------------------------------------------------------
void setup(void) {
  Serial.begin(115200);
  pinMode(readOneWires, INPUT_PULLUP);    // Button for read bus
  lastRead = millis();                    // Start first read time
}
//----------------------------------------------------------
void discoverOneWireDevices(void) {       // Discover One Wire Devices on bus
  byte i;                                 // General control
  byte present = 0;                       // Present Bit of one wire
  byte addr[8];                           // EEPROM from one wire

  Serial.print("Looking for 1-Wire devices...\n\r");
  while (ds.search(addr)) {
    Serial.print(" 1-Wire address: ");
    for ( i = 0; i < 8; i++) {
      Serial.print("0x");
      if (addr[i] < 16) {
        Serial.print('0');
      }
      Serial.print(addr[i], HEX);
      if (i < 7) {
        Serial.print(", ");
      }
    }
    for (i = 1; i < 7; i++)
    {
      OneWireAdd[myCount] += addr[i];
    }
    Serial.print("  Add: "); Serial.println(OneWireAdd[myCount], HEX);
    myCount++;
    if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.print("CRC is not valid!\n");
      return;
    }
  }
  Serial.print("Table loaded.\r\n");
  ds.reset_search();
  return;
}
//----------------------------------------------------------
void readButtons(void) {                  // Read One Wire Devices on bus to id button pressed
  byte i;                                 // General control
  byte present = 0;                       // Present Bit of one wire
  byte addr[8];                           // EEPROM from one wire
  unsigned int compare = 0;               // Button pressed value read  to compare to array

  Serial.print("Looking buttons pressed...\n\r");
  while (ds.search(addr)) {
    for ( i = 0; i < 8; i++) {
      //Serial.print("0x");
      if (addr[i] < 16) {
        //Serial.print('0');
      }
      if (i < 7) {
      }
    }
    for (i = 1; i < 7; i++)
    {
      compare += addr[i];
    }
    if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.print("CRC is not valid!\n");
      return;
    }
    for (int i =  0; i < myCount; i++)
    {
      if (compare ==   OneWireAdd[i])
      {
        Serial.print("button pressed "); Serial.println(i);
      }
    }
    compare = 0;
  }
  Serial.print("Bus readed.\r\n");
  ds.reset_search();
  return;
}
//----------------------------------------------------------
void loop(void) {
  if (digitalRead(readOneWires) == LOW) {
    delay(30);                                    // Debounce
    if (digitalRead(readOneWires) == LOW) {
      discoverOneWireDevices();                   // Read One Wires serial and save at array
    }
  }
  while (digitalRead(readOneWires) == LOW) {
    delay(30);                                     // Debounce
  }
  if (OneWireAdd[0] == 0x00) { // if bus not read
    if (flag == false) {
      Serial.println("Array empty");
      Serial.println("Press readOneWires button to read series");
      flag = true;
    }
    return;
  }
  if ( millis() - lastRead >= reReadTime)
  {
    if (OneWireAdd[0] |= 0x00) { // Array full
      readButtons();
      lastRead = millis();
    }
  }
}
2 Likes

Yep. Many years ago we implemented an LED and push button "pick-to-light" system using CMOS shift registers (so we could run 12V signals for better noise immunity) that ran for hundreds, if not thousands of feet in a very large room.

2 Likes

Thanks everyone for your help.

For those who are more interested in project, I will give a quick description.

I am making interactive hallway. That is composed of pressure plates with LEDs. I want to be flexible with width and length. So one length would be one chain. I would like for each module to be separate and same as all the rest. So in case of faulty one I would just remove it and plug in new one. Each modul would probably be 30cmx30cm. So for just 10m I am already over 30 moduls. Whole thing will probably be around 500 moduls.

Find out about capacitive sensing. With a conductive paint base layer yould know someone is reaching and if they touch the area.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.