Posts tagged ·

buttons

·...

Interacting with the Button Pad Controller SPI

4 comments

By popular request, here’s an update to the first code for the Button Pad Controller SPI. This sketch now includes interactive feedback, in the form of changing colours based on key-presses.

Click view full size image.

Click to view full size image.

Click to play video.

Click to play video.

Download the sketch here.

// The wires
#define CS 10
#define MISO 11
#define MOSI 12
#define SCK  13

// Frame buffer for lights
int lights = 16;
int depth = 3;
byte buf[16][3];

boolean wait = false;
boolean ready = true;

void setup() {
  pinMode(CS, OUTPUT);
  pinMode(MISO, OUTPUT);
  pinMode(MOSI, INPUT);
  pinMode(SCK, OUTPUT);

  digitalWrite(CS, LOW);
  delay(100);

  blank();

  Serial.begin(9600);
  Serial.println("Starting");
}

void blank() {
  // init frame buffer
  for(int l = 0; l < lights; l++) {
    for(int d = 0; d < depth; d++) {
      buf[l][d] = 0;
    }
  }
}

void loop() {
  digitalWrite(SCK, HIGH);
  digitalWrite(CS, HIGH);
  delayMicroseconds(15);

  // Set lights: 3 x 16 bytes
  for(int d = 0; d < depth; d++) {
      for(int l = 0; l < lights; l++) {
        writeByte(buf[l][d]);
      }
  }

  if(!ready) {
    wait = true;
    ready = true;
  }

  // Read the buttons: 16 bytes.
  for(int l = 0; l < lights; l++) {
    // readByte returns a non-zero value when a button is pressed.
    byte b = readByte();

    // If a button is pressed, change the colour.
    if (b > 0 && ready && !wait) {
      if      (buf[l][2] > 0) { buf[l][2] = 0; }
      else if (buf[l][1] > 0) { buf[l][1] = 0; buf[l][2] = 255; }
      else if (buf[l][0] > 0) { buf[l][0] = 0; buf[l][1] = 255; }
      else {                                   buf[l][0] = 255; }

      Serial.print("Button ");
      Serial.print(l);
      Serial.print(": ");
      Serial.print((int)b);
      Serial.println();

      // Change colours slowly.
      ready = false;
    }
  }

  digitalWrite(CS, LOW);

  // After the second cycle, get ready to read new button clicks.
  if(wait) {
    delay(500);
    wait = false;
    ready = true;
  }

  delayMicroseconds(400);
}

// Write out a byte.
// This is for a single colour channel, for a single button.
void writeByte(byte data) {
  for(int i = 0; i < 8; i++) {
    digitalWrite(SCK, LOW);
    delayMicroseconds(5);

    digitalWrite(MISO, (data & (1 << i)) >> i);
    delayMicroseconds(5);

    digitalWrite(SCK, HIGH);
    delayMicroseconds(10);
  }
}

// Read a byte.
// Returns the value for a single button.
// Non-zero if it is pressed, or 0 otherwise.
byte readByte() {
  byte result = 0;
  for(int i = 0; i < 8; i++) {
    digitalWrite(SCK, LOW);
    delayMicroseconds(5);

    result += (!digitalRead(MOSI)) * i;
    delayMicroseconds(5);

    digitalWrite(SCK, HIGH);
    delayMicroseconds(10);
  }

  return result;
}

Physical tone matrix

Comments Off

As an update to yesterday’s post on the Tone Matrix, here’s a very stylish realization from the Reenigne blog. Featuring 16×16 LED lights (just like the Flash app),  the same number of switches (using simple wire and conducting through the finger), and an Arduino / ATmega328 controller.

Comments Off

First code for the Button Pad Controller SPI

4 comments

I recently got the Button Pad Controller SPI from SparkFun. Today I had some time to play around with the code, and got it working. Currently, it is only blinking all the lights, however the code should demonstrate the basics. The user guide from SparkFun documented the details of the interface. Add a few delayMicroseconds() calls, and it’s up and running.

Download the sketch here.

// The wires
#define CS 10
#define MISO 11
#define SCK  13

void setup() {
  Serial.begin(9600);
  Serial.println("setup");
  
  pinMode(CS, OUTPUT);
  pinMode(MISO, OUTPUT);
  pinMode(SCK, OUTPUT);
  
  digitalWrite(CS, LOW);
  delay(1);
}

int lights = 0;

void loop() {
  Serial.println("loop");
  
  // "The Button Pad Controller SPI will begin listening
  //  for a data set once the CS input has been brought high."
  
  // "(HINT: It's best if the SCK signal is set high before
  //  setting the CS pin high)."
  digitalWrite(SCK, HIGH);
  digitalWrite(CS, HIGH);
  delayMicroseconds(15);

  // Blink the lights.  
  lights = !lights;
  
  // Four frames (3 for lights input, 1 for button output)
  // (Here, it is writing to output on the 4th as well, which
  // is wrong, but seems not to cause any issues).
  for(int f = 0; f < 4; f++) {
    
      // Each frame has 16 * 8 = 128 bits of data.
      for(int i = 0; i < 128; i++) {
        
          // "The data on the MISO line should be set while the
          //  clock is low. When the SCK signal goes high the
          //  Button Pad Controller locks in the data currently
          //  on the MISO line."
          digitalWrite(SCK, LOW);
          delayMicroseconds(5);
          
          digitalWrite(MISO, lights);
          delayMicroseconds(5);
          
          digitalWrite(SCK, HIGH);
          delayMicroseconds(10);
      }
  }
  
  digitalWrite(CS, LOW);
 
  Serial.println("end");
  
  // "The CS signal should remain high for the duration of the
  //  data set, at which point it should be brought low for a
  //  minimum of 400 μs before sending the next set of data."
  
  //delayMicroseconds(400);
  delay(500);
}