4 Digit 7 Segment and DS18B20: Multiplexing and Timing Issues

Hi all, I'm new to the Arduino as well as C. I'm trying to display a four digit temperature using the Arduino Uno, a 4 digit 7 segment display, and a DS18B20 temperature sensor. I mean to display temperatures as 123.4, as an example. I'm trying to multiplex without using any additional components, like shift registers. My biggest issue so far is a delay in the middle of displaying the four digits. I read that this was because of the DS18B20 delaying the code whenever it takes a temperature reading.

So far I've tried lowering the resolution of temperature data and making the sensor take readings less often, but neither of these seem to have had an effect.

I added a delay(200); to give each digit a delay, rather than have a hard stop in the middle of a value. This made it easier to see the temperature being displayed, which I've found to be accurate.

I'm looking for help writing cleaner multiplexing / digit writing code, as well as some help with the DS18B20 stopping my code so much.

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 7 //DS18B20 sends data on pin 7
OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

int common[] = {12,11,10,9}; //digit pins
boolean count = false;
boolean shift = false;//count and shift control which digit is displayed
double doub=0.1; //multiplier of temp to read each digit
int c=-1; //power of 0.1 used to read each digit
double temp; //temperature
int digVal; //value of given digit
int digPin; //output pin that controls given digit
int counter=0; //delays temperature reading

void setup()
{
  pinMode(0,OUTPUT); //segment A
  pinMode(1,OUTPUT); //segment B
  pinMode(2,OUTPUT); //segment C
  pinMode(3,OUTPUT); //segment D
  pinMode(4,OUTPUT); //segment E
  pinMode(5,OUTPUT); //segment F
  pinMode(6,OUTPUT); //segment G
  pinMode(7,OUTPUT); 
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(8, OUTPUT); //decimal point
    sensors.begin();
    sensors.setResolution(0x1F); //sets resolution to 9-bit
}

void loop()
{
  doub = pow(0.1, c); 
  digVal = int(temp*doub)%10;//finds value of given digit
  digPin = 12;
 if(count) //count flips every loop, shift flips every other loop
   shift=shift^true; 
   //each of these if statements decides which digit to read
   //based on booleans shift and count
 if(shift && count) 
 {
   digPin=12;
   c=2;
   digitalWrite(8, LOW);
 }
  
 if(shift && !count)
 {
   digPin=9;
   c=1;
   digitalWrite(8, LOW);
 }
  
 if(!shift && count)
 {
   digPin = 10;
   c=0;
   digitalWrite(8, LOW);
 }
 
 if(!shift && !count)
 {
   digPin = 11;
   c=-1;
   digitalWrite(8, HIGH);
 }
  changePlace(digPin); //see below
  writeDigit(digVal); //see below
  delay(200);         //unnecessary
  count= count^true;
    
  counter++;
  if(counter%20==0) //meant to take temp readings every 20 digits
  {
   sensors.requestTemperatures();
  temp = sensors.getTempFByIndex(0);
  }
}

void writeDigit(int r) //sets proper pin states to display value r
{                      //assumed: 0<=r<=9
   int i=0;
  boolean leds[7];
  leds[0] = !(r==1 || r==4);
  leds[1] = !(r==5 || r==6);
  leds[2] = !(r==2);
  leds[3] = !(r==1 || r==4 || r==7);
  leds[4] =  (r==2 || r==6 || r==8 || r==0);
  leds[5] = !(r==1 || r==2 || r==3 || r==7);
  leds[6] = !(r==1 || r==7 || r==0);
  clearAll(); //sets all pins to 'off' state
  for(i=0; i<7; i++) //sets proper segment pins to 'on' state
  {
   
    if(leds[i])
      digitalWrite((i), HIGH);
    
  }
}
  void clearAll() //sets segment pins to 'off' state
  {
  int j=0;  
  for(j=0; j<7; j++)
      digitalWrite(j, LOW);
  }

void changePlace(int x) //sets pin x as the 'on' digit, turns 'off' all others
{
  clearAll();
  int h=0;
  for(h=0; h<4; h++)
    digitalWrite(common[h], HIGH);
  digitalWrite(x, LOW);
  
}

I don't think the issue is with the wiring, because actual correct numbers are being displayed.

Thank you all.

Have you looked at the Seven Segment library for cleaner code? But all such software depends on having no long delays. A big improvement is to use a timer interrupt to drive the display.

I have tried using the Seven Segment library. This is the one you mean, right? Arduino Playground - SevenSeg

//#include <OneWire.h>
//#include <DallasTemperature.h>
#include <SevenSeg.h>

#define ONE_WIRE_BUS 7

//OneWire oneWire(ONE_WIRE_BUS);

//DallasTemperature sensors(&oneWire);

SevenSeg disp(0, 1, 2, 3, 4, 5, 6);

int common[] = {12, 11, 10, 9};
long int start = 0;
long int fin = 0;
float temp = 124.5;
int freq = 100;
int dutyCycle = 100;
void setup() {
  disp.setDigitPins(4, common);
  disp.setDPPin(8);
  //sensors.begin();
  //start = micros();
  //sensors.requestTemperatures();
  //fin = micros();
  //sensors.setWaitForConversion(false);
  //disp.setDigitDelay((fin - start) / 4.0);
 // disp.setDutyCycle(100);
}

void loop() {

  //sensors.requestTemperatures();
  disp.write(temp);
  //temp = sensors.getTempF(0);
}

I tried once with all the commented-out stuff included. That didn't work, so I only included what would be needed for the display of a single number.

Hi,
Both your sketches use pins 0 & 1 for I/O, these are the Tx/Rx used for programming and may cause you some problems in programming and running you sketch.

Tom.... :slight_smile:

Alright, well that would leave me with 12 I/O pins to use, right? I need 7 for the segments, 1 for the decimal point, 4 for the digit pins, and 1 for the DS18B20. What do you suggest I do about this lack of I/O pins?

You have 20 total. 2 for serial, 12 for the display, 1 for DS18B20. That's 15. 5 still left.
A0 to A5 can also be used as D14 to D19. Is that enough?

Hi,
Have you thought of using this type of LED display?


It is 4digit 7segment Display that uses SPI, so you have no mutliplexing maintenance to do.

Tom... :slight_smile:

TomGeorge:
It is 4digit 7segment Display that uses SPI

... or I2C or serial.