Multiplexing while holding a value

Hello,

I was making a program for surveillance of a power part in an application. It should display the voltage and run a temperature control fan. The voltage is displayed on a 7-segment display, 3 digits, so it obviously is multiplexed.

The code seems to work like a charm so far, only problem is that the voltage source is quite jittery as I lately found out. The voltmeter though updates with the multiplexing frequency, which annoys the hell out of me.

I have tried some approaches, like delays in the voltage()-function or for-loops with multiple iterations at different parts in the code. But all has so far either screwed up the voltage reading or the multiplexing.

Has anyone an idea on how I could get the update rate down? About 2-4 times per second or so?

Code is provided below, any help is appreciated.
Thanks in advance,

Cheers, Ivo

//beginning of code

int pinA0=A0;
int disp1=1;
int disp2=2;
int disp3=3;
int segA=5;
int segB=6;
int segC=7;
int segD=8;
int segE=9;
int segF=10;
int segG=11;
int segDP=12;
int temp=A1; // remap to A13 on atTiny167
int fan=4; // remap to 14 on atTiny167

void setup() {
  pinMode(disp1, OUTPUT);
  pinMode(disp2, OUTPUT);
  pinMode(disp3, OUTPUT);
  pinMode(segA, OUTPUT);
  pinMode(segB, OUTPUT);
  pinMode(segC, OUTPUT);
  pinMode(segD, OUTPUT);
  pinMode(segE, OUTPUT);
  pinMode(segF, OUTPUT);
  pinMode(segG, OUTPUT);
  pinMode(segDP, OUTPUT);
  pinMode(pinA0, INPUT);
  pinMode(temp, INPUT);
  pinMode(fan, OUTPUT);
}

int voltage() {
  /*measures the voltage on pin A0 and returns a float value from 0 to 30. Meant 
  for a voltage divider factor 6 on the input. */
  int input=analogRead(pinA0);
  float voltage=(input /20.48)*6;
  return voltage;
}

void display(int digit) {
  /*Takes a single digit int and sets the according segments of the display*/
  switch (digit) {
    case 0:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segG, HIGH);
    break;

    case 1:
    digitalWrite(segA, HIGH);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, HIGH);
    digitalWrite(segG, HIGH);
    break;

    case 2:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, HIGH);
    digitalWrite(segD, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segF, HIGH);
    digitalWrite(segG, LOW);
    break;

    case 3:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, HIGH);
    digitalWrite(segG, LOW);
    break;

    case 4:
    digitalWrite(segA, HIGH);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    break;

    case 5:
    digitalWrite(segA, LOW);
    digitalWrite(segB, HIGH);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    break;

    case 6:
    digitalWrite(segA, LOW);
    digitalWrite(segB, HIGH);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    break;

    case 7:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, HIGH);
    digitalWrite(segG, HIGH);
    break;

    case 8:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    break;

    case 9:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    break;
  }
}

void callupDigit1(int y) {
  //Digit 1
  digitalWrite(disp1,HIGH);
  digitalWrite(disp2,LOW);
  digitalWrite(disp3,LOW);
  digitalWrite(segDP,HIGH);
  display(y);
}

void callupDigit2(int y) {
  //Digit 2  
  digitalWrite(disp3,LOW);
  digitalWrite(disp2,HIGH);
  digitalWrite(disp3,LOW);
  digitalWrite(segDP,LOW);
  display(y);
}

void callupDigit3(int y) {
  //Digit 3
  digitalWrite(disp1,LOW);
  digitalWrite(disp2,LOW);
  digitalWrite(disp3,HIGH);
  digitalWrite(segDP,HIGH);
  display(y);
}

void checkTemp() {
  int read = analogRead(temp);
  if (read >= 711) {
    digitalWrite(fan, HIGH);
  }
  else if (read <= 518) {
    digitalWrite(fan, LOW);
  }
}

void loop() {
  checkTemp();
  int x = voltage();
  int y = x%10;
  callupDigit3(y);
  delay(5);
  x = x/10;
  y = x%10;
  callupDigit2(y);
  delay(5);
  x=x/10;
  y=x;
  callupDigit1(y);
  delay(5);
}

//end of code

Program.ino (4.04 KB)

Please edit your post to include code-tags, see How to use the forum.

And I think you can make it yourself a HECK lot easier by just using the sevenSeg library :wink:

I would use a timer interrupt to drive the LEDs. Then you can use the main loop to do whatever processing on voltages you need.

Or use a MAX7219 to control the display, let it mux the display at 800 Hz for you. Then every 250-500mS you just send it whatever you want displayed.

septillion:
Please edit your post to include code-tags, see How to use the forum.

Thanks for pointing that out, I will do so. Sorry I have missed that, I am new to the forum.

Also, just to inform whoever might read this, I could fix the problem in the mean time.
I have not used the sevenSeg library, as I was not too familiar with the Arduino libraries just yet. I also need the code to be as small as possible.
I also had to avoid external components for this project.

Just so others can benefit from my errors, I will briefly explain what I changed:
In the loop, the different digits are determined by modulo division. I tried a sample and hold by sort of repeating that process multiple times, but that would always repeat the division and screw up the output.
In the new version, I now determine the digits outside the for-loop and then displayed several times. The sampling time is then (times of repeat)(total of delay)=3515=525ms in this case.
See the loop function for reference.

But thanks to everybody who offered help
Greets, Ivo

void loop() {
  checkTemp();
  int x = voltage();
  int y3 = x%10;
  x = x/10;
  int y2 = x%10;
  x=x/10;
  int y1 = x;
  for (int i=0; i<35; i++) {
    callupDigit3(y3);
    delay(5);
    callupDigit2(y2);
    delay(5);
    callupDigit1(y1);
    delay(5);
  }
}

Perlmarmelade:
I also need the code to be as small as possible.

With your implementation, that's nowhere going to be the case...

Well, small enough for me, got me one less header.

Then your definition of small is pretty large :stuck_out_tongue:

What do you mean "one less header"?

Just mind your reads that update the write variable.
If you want to update a reading less frequently, then obviously do that. Although you could make use of those frequent readings to average them out and only periodically print to get a smoother reading.

not sure how Arduin does it, but if I don't use a library, it should not be included into my code?
The code fits my use anyways.

Perlmarmelade:
but if I don't use a library, it should not be included into my code?

So? Using your own code vs a library doesn't make it automatically small... In this case, on the contrary. The library is better written and you only have to include it and write a hand full of lines of code to do the same. Smaller code, smaller upload size.

Perlmarmelade:
The code fits my use anyways.

Of course, that's to no surprise. It's a very small task / sketch for the Arduino...