Go Down

### Topic: multiplexing voltage display (Read 1 time)previous topic - next topic

#### jessjess

##### Nov 20, 2012, 11:48 am
Hi all, simple design that i have planned: to display onto three (3) 7-segment LED displays. the voltage of a variable power supply from 1.5-22VDC.

first problem i am having is that the numbers displayed are inverted, that is from the display:
_        A
|_|   F, G, B
|_|.  E, D, C, DP

for the digit '1' B and C should be lit, however, A, D, E, F, G, DP are lit instead.

trying to test this, i have been using a code that i found:

Code: [Select]
`/*Using 2 7-segment displays with the 74HC595 shift registersCC by-sa-nc 3.0http://tronixstuff.wordpress.com */ int latchpin = 8; // connect to pin 12 on the '595int clockpin = 12; // connect to pin 11 on the '595int datapin = 11; // connect to pin 14 on the '595float b = 0;int c = 0;float d = 0;int e = 0;int speed = 300; // used to control speed of countingint segdisp[10] = { 3,159,37,13,153,73,65,27,1,9};void setup(){ pinMode(latchpin, OUTPUT); pinMode(clockpin, OUTPUT); pinMode(datapin, OUTPUT);}void loop(){ //  Count up for (int z=0; z<100; z++) {   digitalWrite(latchpin, LOW);   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the right display   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the left display   digitalWrite(latchpin, LOW);   if (z<10)   {     digitalWrite(latchpin, LOW);     shiftOut(datapin, clockpin, LSBFIRST, segdisp[z]); // sends the digit down the serial path     shiftOut(datapin, clockpin, LSBFIRST, 255); // sends a blank down the serial path to push the digit to the right     digitalWrite(latchpin, HIGH);   }   else if (z>=10)   {     d=z%10; // find the remainder of dividing z by 10, this will be the right-hand digit     c=int(d); // make it an integer, c is the right hand digit     b=z/10; // divide z by 10 - the whole number value will be the left-hand digit     e = int(b); // e is the left hand digit     digitalWrite(latchpin, LOW); // send the digits down to the shift registers!     shiftOut(datapin, clockpin, LSBFIRST, segdisp[c]);      shiftOut(datapin, clockpin, LSBFIRST, segdisp[e]);      digitalWrite(latchpin, HIGH);   }   delay(speed); } delay(2000); //  Count down for (int z=99; z>=0; z--) {   digitalWrite(latchpin, LOW);   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the right display   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the left display   digitalWrite(latchpin, HIGH);   if (z<10)   {     digitalWrite(latchpin, LOW);     shiftOut(datapin, clockpin, LSBFIRST, segdisp[z]); // sends the digit down the serial path     shiftOut(datapin, clockpin, LSBFIRST, 255); // sends a blank down the serial path to push the digit to the right     digitalWrite(latchpin, HIGH);   }   else if (z>=10)   {     d=z%10; // find the remainder of dividing z by 10, this will be the right-hand digit     c=int(d); // make it an integer, c is the right hand digit     b=z/10; // divide z by 10 - the whole number value will be the left-hand digit     e = int(b); // e is the left hand digit     digitalWrite(latchpin, LOW); // send the digits down to the shift registers!     shiftOut(datapin, clockpin, LSBFIRST, segdisp[c]);      shiftOut(datapin, clockpin, LSBFIRST, segdisp[e]);      digitalWrite(latchpin, HIGH);   }   delay(speed); }    delay(2000);}`

probably well known, counts from 0 through to 99 then backwards.

so, my first problem is i have the hardware set up correctly, so why are the numbers invertly lit?

#### Riva

#1
##### Nov 20, 2012, 12:15 pm
Maybe the display is common anode/cathode instead of common cathode/anode (delete as applicable), really need a schematic and part numbers to be sure. As it lights the segments correctly (though inverted) I would think it's wired okay. Simple fix would be to invert the segment definitions from 3,159,37,13,153,73,65,27,1,9 to 252,96,218,242,102,182,190,228,254,246
Don't PM me for help as I will ignore it.

#### dhenry

#2
##### Nov 20, 2012, 01:35 pm
Quote
A, D, E, F, G, DP are lit instead.

Rather than sending a number, send the opposite of that number.

Code: [Select]
`     shiftOut(datapin, clockpin, LSBFIRST, segdisp[z]); // sends the digit down the serial path`

Use

Code: [Select]
`     shiftOut(datapin, clockpin, LSBFIRST, ~segdisp[z]); // sends the digit down the serial path`

#### jessjess

#3
##### Nov 21, 2012, 04:50 am
Beautiful. i didnt try the print the not number, because the first worked fine.

now that i have the physical printing semi-sorted, i moved onto the voltage calculation itself. it works perfectly fine, however, because i want to display to 0.1V, is there any method of 'rounding' that i could use to print a result (as seen by serial) of 2.55 to 2.6, and 2.54 to 2.5 for later integration onto the 7 segment displays?

here is the voltage snippit of coding

Code: [Select]
`/*result smoothing: http://www.arduino.cc/en/Tutorial/SmoothingVoltage calculation: http://arduinotronics.blogspot.com.au/2011/03/monitoring-voltage-of-dc-battery-supply.html*/int VoltageIn = A5;const int numReadings = 40;int readings[numReadings];      // the readings from the analog inputint index = 0;                  // the index of the current readingint total = 0;                  // the running totalint average = 0;                // the averagevoid setup(){Serial.begin(9600); // initialize serial communication with computer:                   // initialize all the readings to 0:   for (int thisReading = 0; thisReading < numReadings; thisReading++)    readings[thisReading] = 0;  }void loop(){  total= total - readings[index];         // subtract the last reading:  readings[index] = analogRead(VoltageIn);// read from the sensor:    total= total + readings[index];         // add the reading to the total:       index = index + 1;                      // advance to the next position in the array:    if (index >= numReadings)               // if we're at the end of the array...          index = 0;                            // ...wrap around to the beginning:                    average = total / numReadings;          // calculate the average:  Serial.println(average);                // send it to the computer as ASCII digits  delay(1);                               // delay in between reads for stability            int val = analogRead(average); // read the value from the sensorfloat volts = (average * 0.021965811965812); // calculate the ratioSerial.println("Volts:");Serial.println(volts); // print the value in voltsSerial.println("average value");delay(400);}`
# note: the value or 0.0219... was calculated manually as a constant to alter the calculated value to the true voltage

#### jessjess

#4
##### Nov 21, 2012, 10:58 am
Hi all,
i managed to (re) find the wording for code i was after.
here is my code thus far.

Code: [Select]
`/*result smoothing: http://www.arduino.cc/en/Tutorial/SmoothingVoltage calculation: http://arduinotronics.blogspot.com.au/2011/03/monitoring-voltage-of-dc-battery-supply.html*/int VoltageIn = A5;const int numReadings = 40;int readings[numReadings];      // the readings from the analog inputint index = 0;                  // the index of the current readingint total = 0;                  // the running totalint average = 0;                // the averageint latchpin = 8; // connect to pin 12 on the '595    GREEMint clockpin = 12; // connect to pin 11 on the '595   BLUEint datapin = 11; // connect to pin 14 on the '595    YELLOWfloat b = 0;int c = 0;float d = 0;int e = 0;int speed = 500; // used to control speed of countingint segdisp[10] = { 252,96,218,242,102,182,190,228,254,246};void setup(){Serial.begin(9600); // initialize serial communication with computer:                   // initialize all the readings to 0:   for (int thisReading = 0; thisReading < numReadings; thisReading++)    readings[thisReading] = 0;  pinMode(latchpin, OUTPUT);pinMode(clockpin, OUTPUT);pinMode(datapin, OUTPUT);}void loop(){  total= total - readings[index];         // subtract the last reading:  readings[index] = analogRead(VoltageIn);// read from the sensor:    total= total + readings[index];         // add the reading to the total:       index = index + 1;                      // advance to the next position in the array:    if (index >= numReadings)               // if we're at the end of the array...          index = 0;                            // ...wrap around to the beginning:                    average = total / numReadings;          // calculate the average:  Serial.println(average);                // send it to the computer as ASCII digits  delay(1);                               // delay in between reads for stability            int val = analogRead(average); // read the value from the sensorfloat volts = (average * 0.021965811965812 * 0.94104308390023); // calculate the ratioSerial.println("Volts:");Serial.println(volts); // print the value in voltsSerial.println("");Serial.println("");int ones = int(volts);int tenths = int((volts - ones) * 10);Serial.println("voltage _test:");Serial.println(ones);Serial.println(tenths);Serial.println("average value");Serial.println("");   digitalWrite(latchpin, LOW);   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the right display   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the left display   shiftOut(datapin, clockpin, LSBFIRST, 0); // clears the left display   digitalWrite(latchpin, LOW);if (volts < 10){  int tens = 0;  int ones = int(volts);  int tenths = int((volts - ones) * 10);  digitalWrite(latchpin, LOW);  shiftOut(datapin, clockpin, LSBFIRST, segdisp[tenths]); // clears the right display  shiftOut(datapin, clockpin, LSBFIRST, segdisp[ones]); // clears the left display  shiftOut(datapin, clockpin, LSBFIRST, segdisp[tens]); // clears the left display  digitalWrite(latchpin, LOW);    }else if (volts >= 10){  int tens = int(volts / 10);  int ones = int((volts - tens * 10));  int tenths = int((volts - tens * 10 - ones) * 10);    digitalWrite(latchpin, LOW);  shiftOut(datapin, clockpin, LSBFIRST, segdisp[tenths]); // clears the right display  shiftOut(datapin, clockpin, LSBFIRST, segdisp[ones]); // clears the left display  shiftOut(datapin, clockpin, LSBFIRST, segdisp[tens]); // clears the left display  digitalWrite(latchpin, LOW);}delay(5);    // to allow for a reset time}`

and i two questions. when writing to the '595s, there is a very annoying flicker between each value and re-print onto the 7 segments.
is there any way that that could be reduced?
and second. the relationship between the calculated voltage and true voltage should be a linear relationship, yes? i only ask because mine is not, i can have 1.2V calc == 1.2V measured, however bumping it up to 7.2V true gives me a fluctuating 7.3 - 7.4V measured

#### dhenry

#5
##### Nov 21, 2012, 12:54 pm
Quote
there is a very annoying flicker b

What you should have done is to calculate the right segment information, send them to the hc595, and then  latch. This will cause the display to be updated instantaneously, no flickering at all. Like this:

Code: [Select]
`  //get the right number to volts  unsigned short voltsx10 = volts * 10; //convert volts to a fixed point integer  tenths = voltsx10 % 10; voltsx10 /= 10;  ones = voltsx10 %10; voltsx10 /=10;  tens = voltsx10 %10;  //check for blanks  if (tens==0) tens = BLANK;  if ((tens == BLANK) || (ones == 0) ones = BLANK;  digitalWrite(latchpin, LOW);  shiftOut(datapin, clockpin, LSBFIRST, segdisp[tenths]); // clears the right display  shiftOut(datapin, clockpin, LSBFIRST, segdisp[ones]); // clears the left display  shiftOut(datapin, clockpin, LSBFIRST, segdisp[tens]); // clears the left display  digitalWrite(latchpin, LOW);  `

This will blank out leading zeros and will not cause any flickering.

You really should avoid the use of floating point math also.

#### fungus

#6
##### Nov 21, 2012, 01:01 pm
Might be a good idea to put the latch pin high every once in a while, too...

Latch should be a short pulse after the data is in place.
No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Go Up

Please enter a valid email to subscribe