Driving a 4 digitl 7 segment LCD display with shift register

Hey guys! So im having some trouble with this LCD display that Im trying to use. It is one of the 4x7segment parts on sparkfun. datasheet here: http://www.sparkfun.com/datasheets/Comp … B4B-35.pdf

Anywho. I am trying to find out the best way to output to my display. I will be taking in data wirelessly from an accelerometer and outputting the integral of the data to the display.

Anyways, I will be using a multiplexer and a shift register to get the data to the display. The multiplexer is going to select the digit (out of 4) and always be at Vcc (3.3V) whereas the shift register will be low to turn on the segment and high to reverse bias the diode (turn it off). So I was thinking of putting all the values stored in a binary array (is that possible?) or stored as a hex value. For example, a “0” is 0x03, “1” is 0x9F. The shift register I am using is SN74HC595 from Sparkfun. My question is, how do I go about outputting this data to the shift register. I have reserved a few pins for it. One digital out pin will be the serial line, the other will be the “clock” and one more will be the enable pin. How do I either traverse through a binary array or through the bits of a hex value? Can this be done? Thanks!

You’re looking for the bitshift operators (<< and >>) or shiftOut/shiftIn. See: http://arduino.cc/en/Reference/

There’s also a tutorial for this with your specific chip: http://www.arduino.cc/en/Tutorial/ShiftOut

Hey thanks for bringing that to my attention Changrin.

Does anyone know how to convert the data from an accelerometer (so an ADC-ed value, is that an int datatype?) for writing to the display? Do I have to convert it to a string? Im gonna skip using decimals, but I basically need to traverse through a string and write each digit to the display.

I was thinking of either using hex or booleans for each digit (0,1, 2 ,3 etc…) and then could I have an array of pointers to those numbers?

for exampe:

int zero=0x03;

int one = 0x9F;

int* numbers {zero,one, two, three, four…};

then somehow I need to take in a y-axis value from my accelerometer (over Xbee transmission) that will be on the RC car (this display is on the remote control) and display it. Is there a toString() function? I dont see it in the reference. How do I convert the data from whatever it is (what would the datatype be for an analog input signal?) to an array of either ints or chars?

So I got the LCD to blink a little bit but all the segments are incorrect. AKA the data that I shift into the register doesnt really get asserted correctly. The LCD screen I have has 8 pins for the 7 segments and a decimal point, which are all asserted LOW. Then there are selector pins for the digits, which are raised high if I want that digit to be lit. Here’s my code:

/*
Make the following connections:

    * GND (pin 8) to ground,
    * Vcc (pin 16) to 5V
    * OE (pin 13) to ground
    * MR (pin 10) to 5V 
    * DS (pin 14) to dataPin (3)
    * SH_CP (pin 11) to clockPin (4)
    * ST_CP (pin 12) to latchPin(5) 
*/

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin= 5;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin= 4;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 3;
const int digit1 =  6;
const int digit2=   7;
const int digit3=   8;
const int digit4=   9;
const byte zero = B00000011;
const byte one =  B10011111;
const byte two =  B00110101;
const byte three= B00001101;
const byte four=  B10011001;
const byte five = B01001001;
const byte six =  B01000001;
const byte seven= B00011111;
const byte eight= B00000001;
const byte nine = B00011001;

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("reset");
}

void loop() {
  // iterate over the 16 outputs of the two shift registers
  for (int thisDig = 0; thisDig < 4; thisDig++) {
    if(thisDig==0){
        digitWrite(digit1,zero);
    }
    else if(thisDig==1){
         digitWrite(digit2,one); 
    }
    else if(thisDig==2){
        digitWrite(digit3,two);
    }
    else{
       digitWrite(digit4,three);   
    }
    // pause between LEDs:
   // delay(250);
  }
}

void digitWrite(int whichDigit, byte value){
    // turn off the output so the pins don't light up
   digitalWrite(latchPin, LOW);
   digitalWrite(whichDigit,HIGH);
   shiftOut(dataPin,clockPin, MSBFIRST,value);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);
  delay(50);
}

Does anyone know how I could use the shiftOut command to do the appropriate shifting? Or should I just manually do it by using digitalWrite?

I also tried doing it manually, like this:

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin= 5;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin= 4;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 3;
const int digit1 =  6;
const int digit2=   7;
const int digit3=   8;
const int digit4=   9;
int zero[]={0,0,0,0,0,0,1,1};
const byte eight= B00000001;
int length=8;
int startController=75;
int endController=57;
int startCar=42;
int endCar=24;

void setup() {

  // put your setup code here, to run once:
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(digit1,OUTPUT);
  pinMode(digit2,OUTPUT);
  pinMode(digit3,OUTPUT);
  pinMode(digit4,OUTPUT);
  digitalWrite(digit1, HIGH);
}
void loop() {

 // digitalWrite(digit2, HIGH) ;
  //digitalWrite(digit3, HIGH);
  //digitalWrite(digit4, HIGH);
  digitalWrite(latchPin, HIGH);
  
  for(int thisBit=0; thisBit < 8; thisBit++){
     if(zero[thisBit]=1){
      digitalWrite(dataPin,HIGH);
      delay(1);
      digitalWrite(clockPin,HIGH);
      delay(1);
      digitalWrite(clockPin, LOW);
     } 
     if(zero[thisBit]=0){
        digitalWrite(dataPin,LOW);
        delay(1);
        digitalWrite(clockPin,HIGH);
        delay(1);
        digitalWrite(clockPin, LOW);      
     }
     
   
  }

  digitalWrite(latchPin, LOW);
  delay(250);
  
  // put your main code here, to run repeatedly: 
  
}

But that doesnt work either.

Is there a problem with using a Low asserted value to turn on the LCD screen?

It’s basically a bunch of diodes, with the positive side selecting the digits and the negative side selecting the segments. So it needs to pull current when it is in a low state. Is that a problem?

Here’s the data sheet so u can see what I mean:

http://www.protogear.com.au/docs/YSD-439AB4B-35.pdf

OK so I figured out how to get the display working. Now the problem is I dont know how to convert a floating point number to a float with only 4 digits (or 5 if you include decimals) and then to an int or byte array of 0 through 9. How would I break up the number into digits?

Multiply by some power of 10 to get your significant digits to the left of the decimal. You don’t care where the decimal is actually located since you’re driving the LCD by individual segments.

If you really need each digit as a separate variable, treat it like you would a number base conversion. Let’s take 1.234 as an example.

1.234 x 1000 = 1234

1234/1000 = 1.xxx (store results as integers)

(1234 - 1x1000) to get 234, 234/100 = 2.xx

(1234 - 1x1000 - 2x100) = 34, 34/10 =3.x

(1234 - 1x1000 - 2x100 - 3x10) = 4

That’s the simple math version. You could also convert to/from strings and concatenate the string or pick a single character from the string depending on the language.

To convert a single digit integer to its ASCII equivalent, add 48: 0 + 48 = “0”, 1 + 48 = “1” etc.

You need to be able to handle 14 bit math for the maximum 9999 for the display. If you can’t, then go through the routine twice, the first time for the 2 most significant digits, then again for the 2 least significant digits.