Shift registers, multiplexing, and what it means for your weekend

Ideally, it would be nice to be able to know more about what’s going on in a solar panel than to use a multimeter or lick wires every time you want to verify that it’s working.
Also you don’t want a whole lot of your microcontroller’s pins surrendered to basic things like incoming voltage/amperage/cell temperature/etc.
Also if you’re like me you don’t mind overcomplicating things and buy more transistors than you know what to do with.
That’s where the TPIC6B595 high power shift register comes in.  If you’re a supernerd like me you can check out the datasheet here.
If you’re not a nerd but still sorta smart, basically a shift register lets 8 bits stream into it via serial input and outputs it in parallel.  It also has an output that allows daisy-chaining, which could allow you to add hundreds of outputs to a microcontroller without taking up any precious pins.
The TPIC6B595 family is a high-power shift register in that it is capable of consistently sinking 150mA per bit and can handle spikes of up to 500mA.  Because it handles high power, it is only able to sink power, not output it.  But again, it’s a good thing I have so many transistors kicking around.
For a nice 7 segment LED output I picked up a few cheap-o multiplexed 4 digit displays from adafruit.com.
I won’t spare the gruesome details but after cutting a lot of jumper wires and modeling it on a breadboard I was able to come up with this:
What’s particularly nice is that only 3 pins are used by the microcontroller.  What’s not particularly nice is that it looks like a 70’s porn vagina what with the tangles of wire.  You’ll also note that the value displayed is the current voltage being received from the solar panel.  To measure this, you’ll see that the upper right of the board contains a series of resistors that serve as voltage dividers, generating a maximum voltage reading of 25V but reducing it down to a max of 5V which can be read by the microcontroller and then multiplied back to the correct value.
The multiplexing is crazy in that only one digit is actually having power applied to it at any given moment.  But thanks to persistence of vision and the fact that LEDs take more time to sink all of their current than it takes the microcontroller to repower it, it’s absolutely impossible to notice.  
The arrangement I have can handle another 4 digit 7 segment strip without the need for another shift register.  Adding one more would give me two additional 4 digit sets.  
A quick closeup with a little more contrast and a little less focus:
Not to gloat but I also did all of this using nothing but product datasheets and cusses.  Time to PCB this.
Many more fails to come…
Here’s the code if you’re interested:

int clock = 12;
int latch = 8;
int data = 11;
float voltage = 0.0;
byte numbers[10] =
{
  B0111111, // 0
  B0000110, // 1
  B1011011, // 2
  B1001111, // 3
  B1100110, // 4
  B1101101, // 5
  B1111101, // 6
  B0000111, // 7
  B1111111, // 8
  B1101111  // 9
};
void setup()
{
pinMode(latch,OUTPUT);
}
int readTime = 1000;
unsigned long previousMillis = 0;
int value = 0;

void shiftmOut(int myDataPin, int myClockPin, int digitpos, byte myDataOut, bool dec ) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low
//internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);
 //clear everything out just in case to
 //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);
  for (int x=0;x<7;x++){
digitalWrite(myClockPin,0);
if (x==digitpos){
digitalWrite(myDataPin, 1);
} else {
digitalWrite(myDataPin, 0);
}
digitalWrite(myClockPin,1);
digitalWrite(myDataPin,0);
  }
  //decimal point
  digitalWrite(myClockPin,0);
  digitalWrite(myDataPin,dec);
  digitalWrite(myClockPin,1);
  digitalWrite(myDataPin,0);
  for (i=6; i>=0; i–)  {
    digitalWrite(myClockPin, 0);
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {
      pinState= 0;
    }
    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }
  //stop shifting
  digitalWrite(myClockPin, 0);
}

void RefreshDisplay()
{
digitalWrite(latch, 0);
shiftmOut(data,clock,6,numbers[(int)(voltage/10)%10],false);
digitalWrite(latch,1);
digitalWrite(latch,0);
shiftmOut(data,clock,5,numbers[(int)(voltage)%10],true);
digitalWrite(latch,1);
digitalWrite(latch,0);
shiftmOut(data,clock,4,numbers[(int)(voltage/.1)%10],false);
digitalWrite(latch,1);
digitalWrite(latch,0);
shiftmOut(data,clock,3,numbers[(int)(voltage/.01)%10],false);
digitalWrite(latch,1);
}
void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis – previousMillis > readTime)
  {
    previousMillis = currentMillis;
    //for (int x=0;x<100;x++){
    voltage += analogRead(A0);
    //}
    voltage = voltage*25/1024;

  }
  RefreshDisplay();
}


Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s