Flickering 4 x 7 segment display

What i'm trying to do is take the temperature reading from a DS18B20 and then output it to a 4 x 7 segment display (common cathode). I have this working mostly. the problem i'm don't know how to fix is that its strobing and ghosting (not sure if that's what its called when the previous number is faintly showing underneath the new number). I'm very new at this and any help would be appreciated.

#include <OneWire.h> 

int DS18S20_Pin = 12; //DS18S20 Signal pin on digital 2

//Temperature chip i/o
OneWire ds(DS18S20_Pin);  // on digital pin 2
int ones;
int tens;
int hundreds;
boolean negative;
int d1=14, d2=15, d3=16, d4=17;
int a=18, b=13, c=11, d=6, e=1, f=19, g=5, prd=7, x=0, v;
void setup(){
  Serial.begin(9600);
  pinMode(d1, OUTPUT);
  pinMode(d2, OUTPUT);
  pinMode(d3, OUTPUT);
  pinMode(d4, OUTPUT);
  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(prd, OUTPUT);
}
void loop(){
  
     float temperature = getTemp();
     Serial.println(temperature);

     v = getTemp();
     
    if(v<0) {
        negative=true;
        v=v*-1;
    }
    ones=v%10;
    v=v/10;
    tens=v%10;
    v=v/10;
    hundreds=v;			
    
   digit(1);
   number(0);
   delay(2);
   digit(5);
   number(11);
   digit(2);
   number(hundreds);
   delay(2);
   digit(5);
   number(11);
   digit(3);
   number(tens);
   delay(2);
   digit(5);
   number(11);
   digit(4);
   number(ones);
   delay(2);
   digit(5);
   number(11);
}

void digit(int num){
 switch(num){
   case 1:
    digitalWrite(d1, LOW);
    digitalWrite(d2, HIGH);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, HIGH); 
    break;
   case 2:
    digitalWrite(d1, HIGH);
    digitalWrite(d2, LOW);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, HIGH);
    break;
   case 3:
    digitalWrite(d1, HIGH);
    digitalWrite(d2, HIGH);
    digitalWrite(d3, LOW);
    digitalWrite(d4, HIGH);
    break;
   case 4:
    digitalWrite(d1, HIGH);
    digitalWrite(d2, HIGH);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, LOW);
    break;
   case 5:
    digitalWrite(d1, HIGH);
    digitalWrite(d2, HIGH);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, HIGH);
    break; 
   default:
    digitalWrite(d1, HIGH);
    digitalWrite(d2, HIGH);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, HIGH);
    break;   
 } 
}

void number(int num){
  switch(num){
    case 0:
      digitalWrite(a, HIGH);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, HIGH);
      digitalWrite(e, HIGH);
      digitalWrite(f, HIGH);
      digitalWrite(g, LOW);
      digitalWrite(prd, LOW);
      break;
    case 1:
      digitalWrite(a, LOW);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, LOW);
      digitalWrite(g, LOW);
      digitalWrite(prd, LOW);
      break;
    case 2:
      digitalWrite(a, HIGH);  
      digitalWrite(b, HIGH);
      digitalWrite(c, LOW);
      digitalWrite(d, HIGH);
      digitalWrite(e, HIGH);
      digitalWrite(f, LOW);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 3:
      digitalWrite(a, HIGH);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, HIGH);
      digitalWrite(e, LOW);
      digitalWrite(f, LOW);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 4:
      digitalWrite(a, LOW);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, HIGH);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 5:
      digitalWrite(a, HIGH);  
      digitalWrite(b, LOW);
      digitalWrite(c, HIGH);
      digitalWrite(d, HIGH);
      digitalWrite(e, LOW);
      digitalWrite(f, HIGH);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 6:
      digitalWrite(a, HIGH);  
      digitalWrite(b, LOW);
      digitalWrite(c, HIGH);
      digitalWrite(d, HIGH);
      digitalWrite(e, HIGH);
      digitalWrite(f, HIGH);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 7:
      digitalWrite(a, HIGH);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, LOW);
      digitalWrite(g, LOW);
      digitalWrite(prd, LOW);
      break;
    case 8:
      digitalWrite(a, HIGH);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, HIGH);
      digitalWrite(e, HIGH);
      digitalWrite(f, HIGH);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 9:
      digitalWrite(a, HIGH);  
      digitalWrite(b, HIGH);
      digitalWrite(c, HIGH);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, HIGH);
      digitalWrite(g, HIGH);
      digitalWrite(prd, LOW);
      break;
    case 10:
      digitalWrite(a, LOW);  
      digitalWrite(b, LOW);
      digitalWrite(c, LOW);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, LOW);
      digitalWrite(g, LOW);
      digitalWrite(prd, HIGH);
      break;
    case 11:
      digitalWrite(a, LOW);  
      digitalWrite(b, LOW);
      digitalWrite(c, LOW);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, LOW);
      digitalWrite(g, LOW);
      digitalWrite(prd, LOW);
      break;
    default:
      digitalWrite(a, LOW);  
      digitalWrite(b, LOW);
      digitalWrite(c, LOW);
      digitalWrite(d, LOW);
      digitalWrite(e, LOW);
      digitalWrite(f, LOW);
      digitalWrite(g, LOW);
      digitalWrite(prd, LOW);
      break;
  }
}

float getTemp(){
  //returns the temperature from one DS18S20 in degrees C or F

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;  //return this for degrees C
  
  float TempA = TemperatureSum * 1.8; //these two lines convert to degrees F
  float TempB = TempA + 32;
  
  return TempB;
 // return TemperatureSum;
  
}

I'm not surprised..

All those delays, the idea is that your routine is fast enough* to display all 3 digits (1 at a time) individually, our eyes perceive the number as a whole, freeze frame a TV image, if you reduce the speed or the frame rate, you'll get what you're describing...

Remove all the delays, your best bet is to switch to Milli and every few seconds get the new temperature (Say every 3 - 5 seconds) value and then display that value until you refresh, inside the loop you check to see if 5 seconds have passed, if so, get the new value and display that value.

Alternatively, you could use something like 74hc595 control all the segments using just 3 pins, or even a specialized IC which does all that for you, all you do is get the temperature and pass the values the IC and then it takes care of keeping the values on your display...

To start with, remove all your delays when using digitalWrite and you'll see a huge improvement just doing that.

Timing is critical - so is the sequence of what you do.

Whenever I do multiplexed displays I do the following sequence:

  1. Set all segments off
  2. Set current digit off
  3. Increment digit
  4. Wrap digit number to 0 if needed
  5. Set needed segments on
  6. Set current digit on
  7. Slight delay (not using delay()) and repeat.

Note especially the inclusion of step 1 as the first thing to do with each pass - turn off all the segments. This helps to reduce the ghosting you see.

I usually have 1-6 running from within a timer interrupt, so that you don't need to worry about your code interrupting the fluidity of the display overmuch. It's also useful to have an array containing a bitmask for each digit 0-9 which is then mapped to the output pins, then you don't have to have a massive case statement; a simple lookup in the array, then map that to your IO pins using bitshifting / masking.

For instance, here is the update code from a system of mine (not written for the Atmel though, so the library won't work for you, but you get the idea):

void LEDMux::update()
{
    unsigned char v;
    unsigned char i;
    unsigned char c;
    static unsigned char b = 0;

    for (i=0; i<this->nAnodes; i++) {
        digitalWrite(this->anodes[i], 0);
    }
    for (i=0; i<this->nCathodes; i++) {
        digitalWrite(this->cathodes[i], 0);
    }

    this->digit++;
    if (this->digit >= this->nCathodes) {
            this->digit = 0;
            b++;
            b = b & 0b11111;
    }

    if (this->brightness[this->digit] == 0) {
        return;
    }

    if (b < (1<<(this->brightness[this->digit]-1))) {
        c = buffer[this->digit];
        c = c - ' ';
        c = c % 96;

        v = digits[c];
        if ((this->dp >> this->digit) & 1) {
            v = v | 0b10000000;
        }

        for (i=0; i<this->nAnodes; i++) {
            digitalWrite(this->anodes[i], v & (1<<i) ? 1 : 0);
        }
        digitalWrite(this->cathodes[this->digit], HIGH);
    }
}

(This one has most of the ASCII set in it's character array, but you can use just the digits. It happily supports 8 digits, and uses a char array to store the data, and inherits the Print class and implements write so you can print to it like Serial, or an LCD :wink: )

I modified my loop to this

void loop(){
  Serial.println(y);
  if(y ==500){
     float temperature = getTemp();
     Serial.println(temperature);

     v = getTemp();
     y = 0;
  }
     
    if(v<0) {
        negative=true;
        v=v*-1;
    }
    ones=v%10;
    v=v/10;
    tens=v%10;
    v=v/10;
    hundreds=v;			
   
   number(11);
   digit(5);
   digit(1);
   number(0);
   delay(2);
   number(11);
   digit(5);   
   digit(2);
   number(hundreds);
   delay(2);
   number(11);
   digit(5);   
   digit(3);
   number(tens);
   delay(2);
   number(11);
   digit(5);   
   digit(4);
   number(ones);
   
   y++;
  
}

but what happens is i get 4 zeros then it will flash to the temp and then back to the zeros. But the good thing is that all the numbers are solid and not flickering. I'm not sure but is the problem that v is resetting to zero after every time through the loop and how could i fix this

You're modifying V every loop iteration, but you're only getting its starting value once every 500 ms.

You should have another variable that you store the temperature in. Get the temperature into that variable every 500ms, and then copy it into V every loop.

Thanks for all the help i got it working