Jeopardy Controllers are Easy

Hardware is easy…

according to the people that use many of the things I make, that is. They don’t actually say this, but I can tell. They see that you connected a box via usb to a computer and, Buzzerspresumably, think, ‘oh that looks simple, you just hook up this cable and it works.‘ It isn’t until they ask how it was made and I crack open the enclosure do they get an idea of how much work it really is to put something like this together. The project I am referring to here, as you might have guessed, is a of game buzzer button type controls.

While sitting and eating some lunch at The Wurst Place with my Amazon team we discussed what fun activity we could do at our next “Beer Friday” (which don’t happen every Friday, so we are clear). We had a bunch of harebrained ideas that would ultimately have little to know participation or bring down human resources on us within an hour. I then brought up that I had watched Defcon Jeopardy a while back and it looked like a lot of fun. This conversation went quickly to how we could make this happen in 7 days. We decided that is would be possible to build both the hardware buzzers and the software game-board and scoring system in those 7 days. This proved to be a time challenge for me.

I had to order the parts that I needed from Amazon with 2 day shipping to get them in time to complete the build. I should have used 1 day shipping.

Items from Amazon:

  1. Learning Resources Answer Buzzers – Set of 4
  2. Arduino Uno R3
  3. Protoshield KIT for Arduino R3
  4. Box for Arduino

Arduino UNO r3Proto boardI didn’t get my parts until Tuesday and the game was on that Friday. I drew up a simple schematic and mapped out pins to functional components.

[PLACE HOLDER FOR SCHEMATIC] I may actually post this. I have to look around for it. I wrote it on paper. I’ve moved on to other things and am not sure where it might be.

I spent a majority of my time stripping and soldering CAT-5 from a db25 connector to each answer buzzer. The rest of the time was spend performing point-to-point wiring on the protoshield. There wasn’t a large amount of this, but it gets a bit cramped.

Having made the mistake of not drawing a layout ahead of time in previous projects. I decided to draw out the protoshield on some graph paper and draw my intended layout over the protoshield sketch. This saved me significant time and headaches. It also allowed me to check my layout against the schematic before I began to solder. De-soldering mistakes takes a long time, is a pain and it is easy to damage things. I’ve ripped out plenty of pads to know it is better to measure twice and solder once.

I found the layout:

jep-r-dee-layout

The firmware was pretty simple. It uses a single byte protocol.

The input is as follows:

  • The low order bits represent lighting the LEDs on the buzzers.
  • The high order bits represent playing the sound on the buzzers.

The output is as follows:

  • A single byte is sent for each buzzer that is pressed. The number, not the bits, represent the buzzer that was pressed.

Output was handled this way mostly due to the fact that I was writing this code at 1:00AM, was a bit sick and wanted, very badly, to go to bed. I should have used some bit shifting and used a single byte to represent all of the currently pressed buzzers. I should have also randomized my scanning pattern so that buzzer 0 wasn’t always the first buzzer looked at and buzzer 3 always queried last. In the end it worked out. 🙂

#define CONTROLLER_COUNT 4
#define BUFF_LENGTH 100
#define CTL_0_LED 0x01
#define CTL_1_LED 0x02
#define CTL_2_LED 0x04
#define CTL_3_LED 0x08

#define CTL_0_SND 0x10
#define CTL_1_SND 0x20
#define CTL_2_SND 0x40
#define CTL_3_SND 0x80

int btns[] =  {  2,  7,  4, 13 };
int leds[] =  {  3,  6,  5,  9 };
int snds[] =  { 12,  8, 11, 10 };
int deck[] =  {  0,  1,  2,  3 };

volatile char buff[100];
volatile int buffWriteIndex = 0;
int buffReadIndex = 0;

void playSnd(int controller);
void controlLED(int controller);
boolean isBtnPressed(int controller);

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);

  for(int i = 0; i < CONTROLLER_COUNT; ++i) {
    pinMode(btns[i], INPUT);
    pinMode(leds[i], OUTPUT);
    pinMode(snds[i], OUTPUT);
  }

  for(int i = 0; i < CONTROLLER_COUNT; ++i) {
    controlLED(i, HIGH);
  }
}

void loop()
{
  if(buffReadIndex != buffWriteIndex) {
      char cmd = buff[buffReadIndex];
      if(buffReadIndex >= BUFF_LENGTH -1) {
      buffReadIndex = 0;
    } else {
      buffReadIndex++;
    }
    controlLED(0, (cmd & CTL_0_LED) == 0 ? HIGH : LOW);
    controlLED(1, (cmd & CTL_1_LED) == 0 ? HIGH : LOW);
    controlLED(2, (cmd & CTL_2_LED) == 0 ? HIGH : LOW);
    controlLED(3, (cmd & CTL_3_LED) == 0 ? HIGH : LOW);

    if((cmd & CTL_0_SND) != 0) {
      playSnd(0);
    }

    if((cmd & CTL_1_SND) != 0) {
      playSnd(1);
    }

    if((cmd & CTL_2_SND) != 0) {
      playSnd(2);
    }

    if((cmd & CTL_3_SND) != 0) {
      playSnd(3);
    }

  }

  for(int i = 0; i < CONTROLLER_COUNT; ++i) {
    if(isBtnPressed(i)) {
      Serial.write(i);
    } 
  }

}

void playSnd(int controller) {
  digitalWrite(snds[controller], LOW);
  delay(10);
  digitalWrite(snds[controller], HIGH);
  delay(20);
  digitalWrite(snds[controller], LOW);
}

void controlLED(int controller, int value) {
  digitalWrite(leds[controller], value);
}

boolean isBtnPressed(int controller) {
  return digitalRead(btns[controller]) == HIGH;
}

void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    buff[buffWriteIndex] = inChar;
    if(buffWriteIndex >= BUFF_LENGTH -1) {
      buffWriteIndex = 0;
    } else {
      buffWriteIndex++;
    }
  }
}
Electronics, Technology , , ,

1 response to Jeopardy Controllers are Easy


  1. Pingback: Sheep It! | JeremyVeleber.com