PID Soldering Station - display related problem

Hello, I built the project from this link: https://www.allaboutcircuits.com/projects/do-it-yourself-soldering-station-with-an-atmega8/?utm_source=eetech&utm_medium=eetech-social&utm_campaign=reposts-projects/

Using an Arduino Uno, and I am unable to display correctly on the 7 segment led display the temperature, because the display is flickering and it does not show the correct numbers (it shows random numbers).
I used 3 digit x 7 segment common anode display. I left the resistors at 150R.

Please let me know the solution for this problem.

Soldering_Station.ino (3.53 KB)

//Soldering station Software using PID 
//Thank you Alex from https://geektimes.ru/ for help with led array function 
//AllAboutCircuits.com 
//epilepsynerd.wordpress.com 
 
#include <PID_v1.h> 
 
//This array contains what segments need to be turned on to display numbers 0-9 
byte const digits[] = { 
  B00111111, B00000110, B01011011, B01001111, B01100110, B01101101, B01111101, B00000111, B01111111, B01101111 
}; 
 
int digit_common_pins[] = {10, 9, 8}; //Common pins for the triple 7-Segment LED display 
int max_digits = 3; 
int current_digit = max_digits - 1; 
 
unsigned long updaterate = 500; //Change how fast the display updates. No lower than 500 
unsigned long lastupdate; 
 
int temperature = 0; 
 
//Define Variables we'll be connecting to 
double Setpoint, Input, Output; 
 
//Define the aggressive and conservative Tuning Parameters 
double aggKp = 4, aggKi = 0.2, aggKd = 1; 
double consKp = 1, consKi = 0.05, consKd = 0.25; 
 
//Specify the links and initial tuning parameters 
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT); 
 
void setup() 
{ 
  DDRD = B11111111;  // sets Arduino pins 0 to 7 as outputs 
  for (int y = 0; y < max_digits; y++) 
  { 
    pinMode(digit_common_pins[y], OUTPUT); 
  } 
  //We do not want to drive the soldering iron at 100% because it may burn, so we set it to about 85% (220/255) 
  myPID.SetOutputLimits(0, 220); 
  myPID.SetMode(AUTOMATIC); 
  lastupdate = millis(); 
  Setpoint = 0; 
} 
 
 
void loop() { 
  //Read temperature 
  Input = 0; 
  for(int i=0;i<50;i++) 
    Input += analogRead(0); 
  Input /= 50; 
  //Transform the 10bit reading into degrees celsius 
  Input = map(Input, 0, 450, 25, 350); 
  //Display temperature 
  if (millis() - lastupdate > updaterate) { 
    lastupdate = millis(); 
    temperature = Input; 
  } 
  //Read setpoint and transform it into degrees celsius(minimum 150, maximum 350) 
  double newSetpoint = analogRead(1); 
  newSetpoint = map(newSetpoint, 0, 1023, 150, 350); 
  //Display setpoint 
  if (abs(newSetpoint - Setpoint) > 3) { 
    Setpoint = newSetpoint; 
    temperature = newSetpoint; 
    lastupdate = millis(); 
  } 
 
  double gap = abs(Setpoint - Input); //distance away from setpoint 
 
  if (gap < 10) 
  { //we're close to setpoint, use conservative tuning parameters 
    myPID.SetTunings(consKp, consKi, consKd); 
  } 
  else 
  { 
    //we're far from setpoint, use aggressive tuning parameters 
    myPID.SetTunings(aggKp, aggKi, aggKd); 
  } 
 
  myPID.Compute(); 
  //Drive the output 
  analogWrite(11, Output); 
  //Display the temperature 
  show(temperature); 
} 
 
void show(int value) { 
  int digits_array[] = {}; 
  boolean empty_most_significant = true; 
  for (int z = max_digits - 1; z >= 0; z--) //Cycle through each digit 
  { 
    digits_array[z] = value / pow(10, z); //We now take each digit from the number 
    if (digits_array[z] != 0 ) empty_most_significant = false; //Do not display leading zeros 
    value = value - digits_array[z] * pow(10, z); 
    if (z == current_digit) 
    { 
      if (!empty_most_significant || z == 0) { //Check to see that we do not have leading zeros and display the current digit 
        PORTD = ~digits[digits_array[z]]; //Remove ~ for common cathode 
      } 
      else 
      { 
        PORTD = B11111111; 
      } 
      digitalWrite(digit_common_pins[z], HIGH);//Change to LOW for common cathode 
    } else { 
      digitalWrite(digit_common_pins[z], LOW);//Change to HIGH for common cathode 
    } 
 
  } 
  current_digit--; 
  if (current_digit < 0) 
  { 
    current_digit = max_digits; //Start over 
  } 
}
 if (abs(newSetpoint - Setpoint) > 3) { 
    Setpoint = newSetpoint; 
    temperature = newSetpoint;

line 66 - op’s
[ see post #6, this is not wrong, but used for displaying the setpoint ]

I went to the page for the soldering station and there was a Sous Vide controller…
I have been thinking about buying one and trying it out, but what is the fun in that ?
Makes me wonder if my old coffee hotplate has enough power to supply the heat for a DIY version.

I modified the code and it is working now. Thank you.
The new problem is that if I rotate the potentiometer, to increase the temperature, after 2/3 of the course there is a "blank" zone until the pot reach the end of the course. The maximum temperature is set before this "blank" zone appears. I tried 2 potentiometers and the problem was the same.
Can this problem be solved ? If yes, how can I solve this problem ?

Can you explain exactly what is wrong with line #66

    temperature = newSetpoint;

The value in temperature is the reading from the sensor.

in re-reading the code, it looks like when you change the setpoint, the if() statement, for that loop, changes the value in 'temperature' to be the same as the setpoint.

so, it is not wrong, but problem may be with how the display is interfacing.
the display of temperature was 'solved' but that does not mean the change was correct or complete.
I would like to see an indication on the display when it is in display setpoint mode.

when the setpoint has changed, in show(temperature)
shows the new 'temperature'. but the new temperature is really the setpoint for that loop
updaterate = 500 so, for half a second, the display shows the setpoint value and not temperature.

I would extend that [ unsigned long updaterate = 500; ] to 2000 and test again. that way, it would not revert to reading temperature as quickly and it would give you more time to play with it.

wvmarle:
The value in temperature is the reading from the sensor.

Ah, I was looking for a reason that would make the display flicker or show random numbers. As it is, the display would be showing the input from the potentiometer, which should in theory be a fairly stable value, and from the looks of the rest of the code I was not discounting that the original author of the code intended it that way.

After reading you last post, it is showing the temperature sensor most of the time, then changing to the potentiometer reading for the 500mS interval.

david_2018:
Ah, I was looking for a reason that would make the display flicker or show random numbers. As it is, the display would be showing the input from the potentiometer, which should in theory be a fairly stable value, and from the looks of the rest of the code I was not discounting that the original author of the code intended it that way.

what might appear to be random might be because it is changing from setpoint to temperature
since there was an effect by making a change, that leads to a problem with how the display is working.
maybe open the gap [ if (abs(newSetpoint - Setpoint) > 3) { ]
to eliminate noise ?
could be set to 50 and then require a twist in the dial to put it into 'show setpoint' mode

I have got a new problem now: I made the pcb, I inserted the Arduino on the PCB, I connected the PCB with the display, and the display is always showing 888.
If I connect the circuit only to the computer, the the display shows 350 and after that it shows a number (about 500). If I connect it to 24V supply, then it shows 888.
Why is this happening ?
How can I solve this problem ?

Please find attached the schematic

A 24V supply will guaranteed overheat that 7805 regulator.

The two schematics don't add up: one has an 11-pin connector for the display, the other has an 8-pin and a 3-pin connector.

The actual number shown on the display must be software related, as it won't display anything until pins get set to output.

wvmarle:
The actual number shown on the display must be software related, as it won’t display anything until pins get set to output.

All the LED pins are set to output, just a bit of an odd mix of direct port instructions along with pinMode.

  DDRD = B11111111;  // sets Arduino pins 0 to 7 as outputs
  for (int y = 0; y < max_digits; y++)
  {
    pinMode(digit_common_pins[y], OUTPUT);
  }

When set to output, a pin is low by default. So that'll switch on all your segments, showing 888.

You forgot to specify the value of the current limiting resistor on the segments, let's guess 10 mA per segment, times 24 segments is 240 mA total.

Then that 7805 gets to dissipate (24-5)*0.24 = 4.56W, and it's likely to go in thermal shutdown very quickly, or its output voltage drops sufficiently crashing the Arduino leaving the pins in output, low state. On USB that'll be just fine, as the USB can happily supply that much current.

Now the big question remains: why are you even attempting to mux that display the hard way, instead of using a TM1637 or similar chip? Less wiring, less components, easier code, less work for the Arduino. Just to name four major advantages.

If I want to make the soldering iron temperature to go up to 400 degrees C, then it is correct to modify the code as shown below ? (I replaced 350 by 400 in the "map" functions).
... and of course to re calibrate the soldering station.

//Transform the 10bit reading into degrees celsius
  Input = map(Input, 0, 600, 25, 400);
  //Display temperature
  if (millis() - lastupdate > updaterate) {
    lastupdate = millis();
    temperature = Input;
  }
  //Read setpoint and transform it into degrees celsius(minimum 150, maximum 350)
  double newSetpoint = analogRead(A1);
  newSetpoint = map(newSetpoint, 0, 1023, 150, 400);
  //Display setpoint
  if (abs(newSetpoint - Setpoint) > 3) {
    Setpoint = newSetpoint;
    temperature = newSetpoint;
    lastupdate = millis();
  }

This "Input" is some kind of temperature reading? May or may not work like that... depending on the actual input you get there.

wvmarle:
This "Input" is some kind of temperature reading?

Yes, it is.

Hi,
Can you post a copy of your current code please?

Thanks.. Tom.. :slight_smile:

Hi Tom,
Please find the code attached.

//Soldering station Software using PID
//Thank you Alex from https://geektimes.ru/ for help with led array function
//AllAboutCircuits.com
//epilepsynerd.wordpress.com

#include <PID_v1.h>

//This array contains what segments need to be turned on to display numbers 0-9
byte const digits[] = {
  B00111111, B00000110, B01011011, B01001111, B01100110, B01101101, B01111101, B00000111, B01111111, B01101111
};

int digit_common_pins[] = {8, 9, 10}; //Common pins for the triple 7-Segment LED display
int max_digits = 3;
int current_digit = max_digits - 1;

unsigned long updaterate = 1200; //Change how fast the display updates. No lower than 500
unsigned long lastupdate;

int temperature = 0;

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Define the aggressive and conservative Tuning Parameters
double aggKp = 4, aggKi = 0.2, aggKd = 1;
double consKp = 1, consKi = 0.05, consKd = 0.25;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);

void setup()
{
  DDRD = B11111111;  // sets Arduino pins 0 to 7 as outputs
  for (int y = 0; y < max_digits; y++)
  {
    pinMode(digit_common_pins[y], OUTPUT);
  }
  //We do not want to drive the soldering iron at 100% because it may burn, so we set it to about 85% (220/255)
  myPID.SetOutputLimits(0, 220);
  myPID.SetMode(AUTOMATIC);
  lastupdate = millis();
  Setpoint = 0;
}


void loop() {
  //Read temperature
  Input = 0;
  for(int i=0;i<50;i++)
  Input += analogRead(0);
  Input /= 50;
  //Transform the 10bit reading into degrees celsius
  Input = map(Input, 0, 550, 25, 400);
  //Display temperature
  if (millis() - lastupdate > updaterate) {
    lastupdate = millis();
    temperature = Input;
  }
  //Read setpoint and transform it into degrees celsius(minimum 150, maximum 350)
  double newSetpoint = analogRead(A1);
  newSetpoint = map(newSetpoint, 0, 1023, 150, 400);
  //Display setpoint
  if (abs(newSetpoint - Setpoint) > 3) {
    Setpoint = newSetpoint;
    temperature = newSetpoint;
    lastupdate = millis();
  }

  double gap = abs(Setpoint - Input); //distance away from setpoint

  if (gap < 10)
  { //we're close to setpoint, use conservative tuning parameters
    myPID.SetTunings(consKp, consKi, consKd);
  }
  else
  {
    //we're far from setpoint, use aggressive tuning parameters
    myPID.SetTunings(aggKp, aggKi, aggKd);
  }

  myPID.Compute();
  //Drive the output
  analogWrite(11, Output);
  //Display the temperature
  show(temperature);
}

void show(int value) {
  int digits_array[] = {};
  boolean empty_most_significant = true;
  for (int z = max_digits - 1; z >= 0; z--) //Cycle through each digit
  {
    digits_array[z] = value / pow(10, z); //We now take each digit from the number
    if (digits_array[z] != 0 ) empty_most_significant = false; //Do not display leading zeros
    value = value - digits_array[z] * pow(10, z);
    if (z == current_digit)
    {
      if (!empty_most_significant || z == 0) { //Check to see that we do not have leading zeros and display the current digit
        PORTD = ~digits[digits_array[z]]; //Remove ~ for common cathode
      }
      else
      {
        PORTD = B11111111;
      }
      digitalWrite(digit_common_pins[z], LOW);//Change to LOW for common cathode
    } else {
      digitalWrite(digit_common_pins[z], HIGH);//Change to HIGH for common cathode
    }

  }
  current_digit--;
  if (current_digit < 0)
  {
    current_digit = max_digits; //Start over
  }
}

Hi,

Input += analogRead(0);

to

Input += analogRead(A0);

In fact assigning all your pins numbers to variables will help the readability.

Also Input variable could be PotInput to explain where the value is coming from.

Tom... :slight_smile:

This line:

Input = map(Input, 0, 500, 25, 350);

Changed to:

Input = map(Input, 0, 550, 25, 400);

And this line:

 newSetpoint = map(newSetpoint, 0, 1023, 150, 350);

Changed to:

 newSetpoint = map(newSetpoint, 0, 1023, 150, 400);

Will make the temperature variable on the display from 150 to 400 C ?
And the ADC will read the temperature from 25 to 400 C ?