Help with PID Control Project

Hi there!

I’ve been attempting to replicate the PID control tutorial found here:

I’ve made a few small changes - no LCD, no encoder, and I’ve replaced the 12V heater with a piece of nichrome wire. The rest of the connections are the same.

I think I may be making some sort of rudimentary error when it comes to connecting my power supply. When I connect the positive terminal of my power supply to the wire and the negative terminal to my resistor, the thermocouple reading jumps to >400ºC but the wire does not heat up. When I swap the terminals so that negative is connected to the wire and positive to the resistor the thermocouple reading goes to 0ºC but still the wire does not heat.

As for connecting the thermocouple to the wire, I had the wire tip of the thermocouple just wrapped around my nichrome wire. Even if I do remove the thermocouple from the wire and adjusts the PWM value output to pin D3 manually (tried 0, 255, 127) the wire does not heat regardless of where I connect the positive/negative power terminals.

If anyone has any insight into what I may be doing wrong, I would greatly appreciate the help!

I’m happy to provide pictures of my breadboard set up if that would be helpful.

UPDATE: picture of schematic


#include <SPI.h>
//We define the SPI pìns
#define MAX6675_CS   10
#define MAX6675_SO   12
#define MAX6675_SCK  13
int PWM_pin = 3;
float temperature_read = 0.0;
float set_temperature = 100;
float PID_error = 0;
float previous_error = 0;
float elapsedTime, Time, timePrev;
int PID_value = 0;
//PID constants
int kp = 0;   int ki = 0;   int kd = 0;
int PID_p = 0;    int PID_i = 0;    int PID_d = 0;
void setup() {
  TCCR2B = TCCR2B & B11111000 | 0x03;    // pin 3 and 11 PWM frequency of 980.39 Hz
  Time = millis(); 
void loop() {
 // First we read the real value of temperature
  temperature_read = readThermocouple();
  //Next we calculate the error between the setpoint and the real value
  PID_error = set_temperature - temperature_read;
  //Calculate the P value
  PID_p = kp * PID_error;
  //Calculate the I value in a range on +-3
  if(-3 < PID_error <3)
    PID_i = PID_i + (ki * PID_error);
  //For derivative we need real time to calculate speed change rate
  timePrev = Time;                            // the previous time is stored before the actual time read
  Time = millis();                            // actual time read
  elapsedTime = (Time - timePrev) / 1000; 
  //Now we can calculate the D calue
  PID_d = kd*((PID_error - previous_error)/elapsedTime);
  //Final total PID value is the sum of P + I + D
  PID_value = PID_p + PID_i + PID_d;
  //We define PWM range between 0 and 255
  if(PID_value < 0)
  {    PID_value = 0;    }
  if(PID_value > 255)  
  {    PID_value = 255;  }
  //Now we can write the PWM signal to the mosfet on digital pin D3
  analogWrite(PWM_pin,255-PID_value); // have tried manually sending values 0, 127, 255 to see if wire will heat, no luck
  previous_error = PID_error;     //Remember to store the previous error for next loop.
double readThermocouple() {
  uint16_t v;
  pinMode(MAX6675_CS, OUTPUT);
  pinMode(MAX6675_SO, INPUT);
  pinMode(MAX6675_SCK, OUTPUT);
  digitalWrite(MAX6675_CS, LOW);
  // Read in 16 bits,
  //  15    = 0 always
  //  14..2 = 0.25 degree counts MSB First
  //  2     = 1 if thermocouple is open circuit  
  //  1..0  = uninteresting status
  v = shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
  v <<= 8;
  v |= shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
  digitalWrite(MAX6675_CS, HIGH);
  if (v & 0x4) 
    // Bit 2 indicates if the thermocouple is disconnected
    return NAN;     
  // The lower three bits (0,1,2) are discarded status bits
  v >>= 3;
  // The remaining bits are the number of 0.25 degree (C) counts
  return v*0.25;

A schematic is much better at describing an electronic circuit than words. Please post a schematic showing all components, their values and all power supplies.

Also post your code in code tags. Read the forum guidelines.

Thanks so much, will do!

You cannot connect an external voltage to a thermocouple as you are doing by way of the nichrome wire. A thermocouple generates millivolts and you’re overloading the input of the MAX6675 with 12 volts that is present on the nichrome wire.

You need a heater that electrically isolates the heater element from the thermocouple.

In a pinch, you could substitute a 12 volt tungsten automotive tail lamp. Fasten the thermocouple to the top of the glass bulb with a thermally conductive epoxy like JB-Weld or PC-7. You will not have has as wide a temperature range but the lamp provides visual feedback of the PID output.

Edit: note that the epoxies mentioned are electrically conductive which can cause some measurement error if you are using a bare wire thermocouple junction. If the wire junction is inside a metal can/tip, no error will occur.

Thermocouples provide extremely low voltage. 100°C = 4.1 mv, 0 ° = 0 mv

The MAX6675 requires the thermocouple is below 5+, best at or near zero. These breakout boards have minimal filtering so any PWM nearby will go right into the thermocouple giving you erratic readings.

Curious, what resistance is you piece of nichrome?

Ah got it, thank you!

I am curious if you have an idea as to why the wire never heats up when the power is connected? Even if I disconnect the thermocouple from the wire and manually adjust the value sent to the D3 pin (tried 0, 127, 255) no heat is generated. If I apply 12V to the wire directly it heats up very quickly so I’m thinking that I may be missing something/doing something incorrectly with regard to supplying the power to the wire.

The wire has a resistance of 1.016 Ohms/ft and the piece I’m using is about 8in long.

It seems like I’ll need to find another way of getting a temperature reading from the wire, but I’m more concerned with why even when the thermocouple is disconnected and I’m manually changing the value sent to the PWM pin (tried 0, 127, 255) the wire never heats up.

I’ve tried applying various voltages to the wire directly and when I do that it does heat up relatively quickly, so I think I must be making some error in how I’m supplying the power or setting up the circuit in general. Do you have any ideas as to what I could be doing incorrectly there?

Looking closer at that section of the illustration, it is obvious no one checked the authors design. There is a significant mistake in that there is no current limitation of the base current in the S8050 driver transistor. It must have a resistor in series with the Arduino output and the base of the transistor. Without it, the ATmega328 processor will be destroyed if left energized for any length of time. A 1K resistor should be sufficient. The problem is that either the transistor or the output of the processor (perhaps both) are likely damaged and reason the heater is not turning on.

Overall, the choice of IRFZ44N was a poor one, probably due to what the author had on hand. The worst aspect of the design is that when the PWM output is low, as is the case when the processor powers up, the S8050 is off and the IRFZ44N is on. If the processor fails to write a logic HIGH to the PWM output, the heater is on continuously, not a good default condition. A much better choice is this minimal circuit:

D1 is not needed for a resistive load, a good mosfet choice is the FQP30N06L

Thank you so much! I’ll make those changes and see if that fixes the heating issue.

The circuit image that you attached is showing up as broken. Is there any chance you could try re-adding it?

Fixed by dragging and dropping the image into place. Looks like a forum software bug as the link works and the image appeared in the preview.

I see it now, thanks again!

Before you go too far, at a nichrome resistance of < 1 ohm, Is your supply ready to supply > 12 Amps?

I’m using this power supply:

I believe it tops out at 10 amps. Should I upgrade to one that can output 12 or more?

I don’t know what your heating nor the the design requirement that lead to a 0.8" piece of nichrome wire.

If your wire was from a spool of wire I would first run with a longer wire and wring out the operation. But that might not be practical in your case.

I was just using a small piece as a test. I do have a full spool and it’s definitely practical for me to try with a longer piece. Thank you!

I do have a lot of flexibility when it comes to the final length of the wire used in my project - I’ll be coiling it up and using it as a heating element of sorts. It needs to be able to heat to at least ~100ºC, but higher would be ideal.

I don’t know your application but nichrome is not the only option. You could use a Power Resistor.

Probably a little slower but may be easier to mount.

Unless I’m missing something, when the mosfet turns on, a 1 ohm load is connected across the 12V supply, which obviously means it will draw 12A.
Is the supply rated for that ?