Friday, May 6, 2016

So last week, I got the easy part out of the way: the serial-to-parallel shift out to an array of LEDs. This week, I'm going to be going through how I set-up a 16 bit parallel-to-serial shift in from an array of "buttons" to the Arduino in order to turn those LEDs on at will.

That Shift Register is Talking Some Mad Binary

This is a little less straight-forward than last week's endeavor. I had to take everything into account that was done then and add some practical way to control it.

What helped this time around was looking at the old code I wrote to do this back in 2011. The original code didn't work thanks to Arduino changing things in the compiler and the IDE, but a few hours of beating on it (and my desk) got it to work.

Materials Used:
  • Everything from last week's post
  • More hook-up wire
  • 2 - HCF4021B Shift Registers (Have a datasheet!)
  • 16 - 10kΩ resistors
Why 16 resistors when there will only be 10 buttons in the final product? The 4021 chip I chose freaks out whenever one of the data in pins doesn't have a path to ground. I played around with this in it's 8 bit form and without a single path to ground, it was sending me 11111111 or 255 and nothing else. 

If you're doing this and are getting weird results like the circuit is sending 127 or 255 constantly or whenever a button is pressed, check to see if your resistors are seated securely in the breadboard. The 4021 is a tricky, fickle demon.

Step 1: Put Some Wire on Board

This will at least power the chips

Step 2: The Control Wires


The Clock (yellow) is shared with the 595 circuit. Tie the Clock pins together.  There is no point in having a second clock.
Data (blue) goes to D5. Additionally, a wire needs to go from DS on the top IC to Q7 on the bottom.
The Latch (orange) goes to D4. Tie the Latch pins together. Why the separate Latch? I don't know.

Step 3: The "Button" Debounce Circus

If you have access to 10kΩ DIP resistors, not only will you be better off, but I hate you out of jealousy.

My end-result ended-up being 16 10kΩ resistors straight from the pin line on the breadboard from the chip directly to ground. Since I don't have this many buttons to play with, I just probed the board at certain points with a wire hooked directly to the 5v rail. It does the same thing as a button and is as expensive as a foot of hookup wire.
I used purple in the sketch for lines from pins. RIP Prince

Step 4: The Code

Here's what works:


int latchPin = 4;
int dataPin = 5;
int clockPin = 7;
int led_latchPin = 11;
int led_dataPin = 10;
byte switchVar1 = 72;
byte switchVar2 = 159;

void setup() {
  //start serial
  Serial.begin(9600);

  //define pin modes
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, INPUT);
  pinMode(led_latchPin, OUTPUT);
  pinMode(led_dataPin, OUTPUT);
  unsigned int bitsToSend = 0;
  digitalWrite(led_latchPin, 0);
  bitWrite(bitsToSend, 8, HIGH);
  byte registerOne = highByte(bitsToSend);
  byte registerTwo = lowByte(bitsToSend);
  shiftOut(led_dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(led_dataPin, clockPin, MSBFIRST, registerOne);
  digitalWrite(led_latchPin, 1);
}
void loop() {
  int LED;
  digitalWrite(latchPin, 1);
  delayMicroseconds(40);
  digitalWrite(latchPin, 0);
  switchVar1 = shiftIn(dataPin, clockPin);
  switchVar2 = shiftIn(dataPin, clockPin);
  unsigned int allIn = switchVar1 * 256 + switchVar2; //The total value of what is being sent to the Arduino
  if (allIn != 0) {
    switch (allIn) {
      case 1:
        LED = 1;
        break;
      case 2:
        LED = 0;
        break;
      case 4:
        LED = 15;
        break;
      case 8:
        LED = 14;
        break;
      case 16:
        LED = 13;
        break;
      case 32:
        LED = 12;
        break;
      case 64:
        LED = 11;
        break;
      case 128:
        LED = 10;
        break;
      case 256:
        LED = 9;
        break;
      case 512:
        LED = 8;
        break;
      default:
        LED = 8; //Don't know what to do? Go home.
        break;
    }
    Serial.println(switchVar1);
    Serial.println(switchVar2);
    Serial.println(allIn);
    Serial.println("--------------");
    unsigned int bitsToSend = 0;
    digitalWrite(led_latchPin, 0);
    bitWrite(bitsToSend, LED, HIGH);
    byte registerOne = highByte(bitsToSend);
    byte registerTwo = lowByte(bitsToSend);
    shiftOut(led_dataPin, clockPin, MSBFIRST, registerTwo);
    shiftOut(led_dataPin, clockPin, MSBFIRST, registerOne);
    digitalWrite(led_latchPin, 1);
    //changeProgram(LED);
    delay(200);
  }

}


byte shiftIn(int myDataPin, int myClockPin) {
  int i;
  unsigned temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);
  for (i = 7; i >= 0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      myDataIn = myDataIn | (1 << i);
    }
    else {
      pinState = 0;
    }
    digitalWrite(myClockPin, 1);
  }
  return myDataIn;
}

 There are very few things in common with last week's code. For those following along at home: my apologies.

Step 5: The Madness Sets In

From there, I probed around - putting the hot wire between the resistors and the 4021 chips. The lights turned on and off. It was a success.

For further troubleshooting, the Arduino will print out the high bit, the low bit and the combined 16 bit value of what is sent back to the console. Additionally, here's the Fritzing sketch I put together for this post.

If you're seeing a behavior like the following, you too have success. If not, troubleshooting will lead to eventual insanity.



Reactions:

0 comments:

Post a Comment

Subscribe to RSS Feed Follow me on Twitter!