PID temperature controller and stepper motor

Hello everyone. I am having trouble writing code for a machine with PET filament. I am using a NEMA17HS4401S stepper motor and a TMC2208 driver. An Arduino Nano is used to create the machine. I have separate code for the stepper motor, encoder and LCD1602 (I2C) display, and it works fine. There is also separate code for the PID controller, which also works fine, but as soon as I combine them into one, the stepper motor starts to jerk, but still rotates. If I try to turn off the display update while the stepper motor is running, the jerks become smaller, but are still audible. If I try to increase the PID update delay, the jerks become smaller but do not disappear. I don't know what to do, but I understand that the display and PID controller affect the operation in this case. I would appreciate your help.

The full code is below:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <AccelStepper.h>
#include <PID_v1.h>
#include <thermistor.h>

// Pins for the stepper motor
#define dirPin 7
#define stepPin 8
#define enablePin 9
#define motorInterfaceType 1

// Pins for the encoder
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4

// Pin for the thermistor
#define temperaturePin A0

LiquidCrystal_I2C lcd(0x27, 16, 2);
thermistor therm1(temperaturePin, 0);

// Motor settings
const int MICROSTEPS = 2;
const int STEPS_PER_REVOLUTION = 200 * MICROSTEPS;
float maxRPS = 10.0, minRPS = 0.1, targetRPS = 1.0, currentRPS = 1.0;
float rpsStep = 0.1, acceleration = 1.0;
const float GEAR_RATIO = 36.0;
const float WHEEL_CIRCUMFERENCE = 282.74;

// Encoder variables
volatile int encoderPos = 0;
int lastEncoderPos = 0;
bool btnPressed = false;
const int impulsesPerClick = 2;

AccelStepper stepper(motorInterfaceType, stepPin, dirPin);

// PID settings
double setpoint = 220, input, output;
double Kp = 80.0, Ki = 35.0, Kd = 80.0;
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);

// System state
byte inputMode = 0; // 0 - temperature, 1 - speed, 2 - direction
int motDir = 1;     // 0 - Reverse, 1 - Off, 2 - Forward

void updateEncoder() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > 5) {
    if (digitalRead(ENCODER_DT) == digitalRead(ENCODER_CLK))
      encoderPos++;
    else
      encoderPos--;
    lastInterruptTime = interruptTime;
  }
}

void setup() {
  Serial.begin(9600);
  
  // Initialize LCD
  lcd.init();
  lcd.backlight();
  
  // PID setup
  pid.SetMode(AUTOMATIC);
  pid.SetOutputLimits(0, 255);
  input = therm1.analog2temp();
  
  // Pin setup
  pinMode(ENCODER_CLK, INPUT_PULLUP);
  pinMode(ENCODER_DT, INPUT_PULLUP);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, LOW); // Enable motor driver
  
  // Motor setup
  stepper.setMaxSpeed(maxRPS * STEPS_PER_REVOLUTION);
  stepper.setAcceleration(acceleration * STEPS_PER_REVOLUTION);
  stepper.setSpeed(currentRPS * STEPS_PER_REVOLUTION);
  
  // Encoder interrupt
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), updateEncoder, CHANGE);
}

void loop() {
  static unsigned long lastTempUpdate = 0;
  static unsigned long lastDisplayUpdate = 0;
  
  // Update temperature and PID (every 500 ms)
  if (millis() - lastTempUpdate > 500) {
    input = therm1.analog2temp();
    pid.Compute();
    analogWrite(5, output);
    lastTempUpdate = millis();
  }
  
  // Handle controls
  handleEncoder();
  handleButton();
  updateMotorSpeed();
  stepper.runSpeed();
  
  // Update display (every 300 ms) only if motor is not moving
  if (millis() - lastDisplayUpdate > 300 && !isMotorMoving()) {
    updateDisplay();
    lastDisplayUpdate = millis();
  }
}

// Check if motor is moving
bool isMotorMoving() {
  return (motDir != 1 && currentRPS > 0.1); // If not off and speed is above minimum
}

void handleEncoder() {
  int delta = encoderPos - lastEncoderPos;
  if (abs(delta) >= impulsesPerClick) {
    int steps = delta / impulsesPerClick;
    
    switch (inputMode) {
      case 0: // Temperature
        setpoint += steps;
        setpoint = constrain(setpoint, 190, 230);
        break;
      case 1: // Speed
        targetRPS += steps * rpsStep;
        targetRPS = constrain(targetRPS, minRPS, maxRPS);
        break;
      case 2: // Direction
        motDir += steps;
        motDir = constrain(motDir, 0, 2);
        break;
    }
    lastEncoderPos = encoderPos;
  }
}

void updateMotorSpeed() {
  // Set direction
  if (motDir == 0) digitalWrite(dirPin, LOW);
  else if (motDir == 2) digitalWrite(dirPin, HIGH);
  
  if (motDir != 1) {
    // Smooth speed change
    if (abs(currentRPS - targetRPS) > 0.01) {
      currentRPS += (currentRPS < targetRPS) ? acceleration * 0.05 : -acceleration * 0.05;
      currentRPS = constrain(currentRPS, minRPS, maxRPS);
    }
    stepper.setSpeed(currentRPS * STEPS_PER_REVOLUTION);
  } else {
    stepper.setSpeed(0);
  }
}

void handleButton() {
  static bool lastState = HIGH;
  bool state = digitalRead(ENCODER_SW);
  if (state != lastState && state == LOW) {
    inputMode = (inputMode + 1) % 3;
    delay(200); // Debounce
  }
  lastState = state;
}

void updateDisplay() {
  lcd.clear();
  
  // First line - temperature
  lcd.setCursor(0, 0);
  lcd.print("T:");
  lcd.print((int)input);
  lcd.print("C S:");
  lcd.print((int)setpoint);
  lcd.print("C");
  
  // Second line - current mode
  lcd.setCursor(0, 1);
  switch (inputMode) {
    case 0:
      lcd.print("Temp: ");
      lcd.print((int)setpoint);
      lcd.print("C >");
      break;
    case 1:
      lcd.print("Speed: ");
      lcd.print(targetRPS, 1);
      lcd.print("RPS >");
      break;
    case 2:
      lcd.print("Dir: ");
      if (motDir == 0) lcd.print("REV >");
      else if (motDir == 2) lcd.print("FWD >");
      else lcd.print("OFF >");
      break;
  }
}

A couple of suggestions:

Swap out the AccelStepper library for the MobaTools libary. MobaTools uses interrupts in the background for doing the stepping so it will run more smoothly while you are doing all the other things in your code.

Update your handleEncoder() function to properly deal with encoderPos. Since that variable is volatile, you need to make a local copy and use that or you risk having an interrupt happen mid-access and getting garbage.

Get rid of the delay(200) in your handleButton() function. That is not a great way to debounce your button. Use a button library that does it properly without blocking. (Bounce2 or EZButton are just a couple)

1 Like

Here's some things to do to speed up the interface with the lcd display.

//#include <LiquidCrystal_I2C.h>
#include hd44780.h

The hd44780.h library by Bill Perry is the best and fastest library to use for the display. It is available through the library manager.

void updateDisplay() {
  lcd.clear();

lcd.clear() is a very slow instruction.
It is faster clear characters by writing spaces, and written locations can be overwritten without the lcd.clear().

Additionally, any unchanging elements, like parts of the first line, should be written once in setup.

1 Like

Besides removing the delay, another suggestion is to remove the <thermistor.h> library.

Use analogRead().

It seemed "heavy" to me, but since I'm not a programming expert, I'm unsure how much processing power a library can have.

1 Like

Your solution helped, but there is one question. When using 2 microsteps, the MobaTools library makes 10 revolutions in my code; when using 4 microsteps, it makes 5 revolutions and does not respond to further increases; when using 8 microsteps, it makes 2.5 revolutions and does not respond to further increases. Perhaps there are some limitations in this library, because when we change the microsteps, we increase the number of steps per rotation: 2 microsteps - 400 steps, 4 microsteps - 800 steps, 8 microsteps - 1600 microsteps. In the AccelStepper library, it was possible to achieve almost maximum speed at different microsteps, but here it feels like something in the library is limiting it. But overall, the library is great, the motor runs smoothly, without jerks.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <MobaTools.h>
#include <PID_v1.h>
#include <thermistor.h>
#include <Bounce2.h>

// Pin definitions
#define dirPin 7
#define stepPin 8
#define enablePin 9
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
#define temperaturePin A0

LiquidCrystal_I2C lcd(0x27, 16, 2);
thermistor therm1(temperaturePin, 0);

// Motor settings
const int MICROSTEPS = 4;
const int STEPS_PER_REVOLUTION = 200 * MICROSTEPS;
float maxRPS = 10.0, minRPS = 0.1, targetRPS = 1.0, currentRPS = 1.0;
float rpsStep = 0.1, acceleration = 1.0;

const float CYLINDER_DIAMETER_MM = 90.0f;  // Cylinder diameter in mm
const float GEAR_RATIO = 36.0f;           // Gear ratio 36:1

// Encoder
volatile int encoderPos = 0;
int lastEncoderPos = 0;
const int impulsesPerClick = 2;

// Motor
MoToStepper stepper(STEPS_PER_REVOLUTION, STEPDIR);

// Button
Bounce encoderButton = Bounce();

// PID
double setpoint = 220, input, output;
double Kp = 80.0, Ki = 35.0, Kd = 80.0;
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);

// Modes
#define MODE_ONOFF 0
#define MODE_SPEED 1
#define MODE_TEMP 2
#define MODE_PWM 3  // New mode for PWM
byte currentMode = MODE_ONOFF;
bool isMotorOn = false;

float rpsToMmS(float rps) {
  float cylinderCircumference = PI * CYLINDER_DIAMETER_MM;  // Cylinder circumference in mm
  float cylinderRps = rps / GEAR_RATIO;                   // Cylinder rotations per second
  return cylinderRps * cylinderCircumference;             // Speed in mm/s
}

void updateEncoder() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > 5) {
    if (digitalRead(ENCODER_DT) == digitalRead(ENCODER_CLK))
      encoderPos--;
    else
      encoderPos++;
    lastInterruptTime = interruptTime;
  }
}

void setup() {
  Serial.begin(9600);
  
  lcd.init();
  lcd.backlight();
  
  pid.SetMode(AUTOMATIC);
  pid.SetOutputLimits(0, 255);
  input = therm1.analog2temp();
  
  pinMode(ENCODER_CLK, INPUT_PULLUP);
  pinMode(ENCODER_DT, INPUT_PULLUP);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, LOW);
  
  encoderButton.attach(ENCODER_SW, INPUT_PULLUP);
  encoderButton.interval(25);
  
  stepper.attach(stepPin, dirPin);
  stepper.setSpeed(0);
  stepper.setRampLen(2);
  
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), updateEncoder, CHANGE);
  
  updateDisplay();
}

void loop() {
  static unsigned long lastTempUpdate = 0;
  static unsigned long lastDisplayUpdate = 0;
  
  if (millis() - lastTempUpdate > 300) {
    input = therm1.analog2temp();
    pid.Compute();
    analogWrite(5, output);
    lastTempUpdate = millis();
  }
  
  handleButton();
  handleEncoder();
  updateMotor();
  
  if (millis() - lastDisplayUpdate > 300) { 
    updateDisplay();
    lastDisplayUpdate = millis();
  }
}

void handleEncoder() {
  int currentEncoderPos = encoderPos;
  int delta = currentEncoderPos - lastEncoderPos;
  
  if (abs(delta) >= impulsesPerClick) {
    switch (currentMode) {
      case MODE_ONOFF:
        isMotorOn = !isMotorOn;
        break;
        
      case MODE_SPEED:
        targetRPS += (delta > 0) ? rpsStep : -rpsStep;
        targetRPS = constrain(targetRPS, minRPS, maxRPS);
        break;
        
      case MODE_TEMP:
        setpoint += (delta > 0) ? 1 : -1;
        setpoint = constrain(setpoint, 190, 230);
        break;
        
      case MODE_PWM:
        // In this mode, encoder doesn't change PWM (it's controlled by PID)
        // But manual control can be added if needed:
        // output += (delta > 0) ? 5 : -5;
        // output = constrain(output, 0, 255);
        break;
    }
    lastEncoderPos = currentEncoderPos;
  }
}

void handleButton() {
  encoderButton.update();
  
  if (encoderButton.fell()) {
    currentMode = (currentMode + 1) % 4;
    updateDisplay();
  }
}

void updateMotor() {
  if (isMotorOn) {
    // Smooth speed change considering microsteps
    if (abs(currentRPS - targetRPS) > 0.01) {
      currentRPS += (currentRPS < targetRPS) ? acceleration * 0.05 : -acceleration * 0.05;
      currentRPS = constrain(currentRPS, minRPS, maxRPS);
    }
    
    // Actual speed considering microsteps
    float effectiveSpeed = currentRPS / MICROSTEPS * 2; // Correction factor
    stepper.setSpeed(effectiveSpeed * STEPS_PER_REVOLUTION);
    stepper.rotate(1);
  } else {
    stepper.setSpeed(0);
    stepper.stop();
  }
}

void updateDisplay() {
  lcd.clear();
  
  // First line: Temperature
  lcd.setCursor(0, 0);
  lcd.print("T:");
  lcd.print((int)input);
  lcd.print("C S:");
  lcd.print((int)setpoint);
  lcd.print("C");
  
  // Second line: Display based on current mode
  lcd.setCursor(0, 1);
  switch (currentMode) {
    case MODE_ONOFF:
      lcd.print("MODE: ");
      lcd.print(isMotorOn ? "ON" : "OFF");
      break;
      
    case MODE_SPEED:
      lcd.print(targetRPS, 1);
      lcd.print("RPS ");
      lcd.print(rpsToMmS(targetRPS), 1);  // Display speed in mm/s
      lcd.print("mm/s");
      break;
      
    case MODE_TEMP:
      lcd.print("SET TEMP > ");
      lcd.print((int)setpoint);
      break;
      
    case MODE_PWM:
      lcd.print("PWM:");
      lcd.print((int)output);
      lcd.print("/255 ");
      lcd.print((int)(output/255.0*100));
      lcd.print("%");
      break;
  }
}

MoToStepper works a little bit differently than Accelstepper. With MoToStepper you can define the speed in rpm - and that's what setSpeed() does. If you want to define the speed in steps/sec you must use setSpeedSteps(). (Keep in mind, that the parameter of setSpeedSteps needs the speed in steps/10sec - I don't use float, and so you get a better resolution when defining the speed )
And - unlike AcceStepper - MoToStepper does not only accelerate smoothly to a new higher speed, but also decelerates smoothly if you reduce the speed. So it may not be necessary to do that in updateMotor() by yourself.

2 Likes

You still are not properly dealing with your volatile encoderPos in handleEncoer()
You need to turn off interrupts while making the copy and then turn them back on.

void handleEncoder() {
  noInterrupts();
  int currentEncoderPos = encoderPos;
  interrupts();
  ...
}
1 Like

Some more hints about using MoToStepper:
I assume your targetRPS defines the speed in rotations/sec. If you define the speed in RPM, you don't need float. float is fairly slow on an UNO R3. And if you define the speed in RPM*10 you get a better resolution and can use this value directly in setSpeed(). If your STEPS_PER_REVOLUTION is set correctly according to microsteps, there is no need for any correction factor.
Which board are you using? The maximum steprate MoToStepper can achive with an UNO R3 are 2500 steps/sec. This will work for up to 6 steppers moving in parallel. If you have only 1 stepper, you can reach up to 5000 steps/sec by changing a #define in MobaTools.h
The direction of movement can only be changed by changing the target position. setSpeed() doesn't accept negative values.
Did you read the documentation?

1 Like

I still have a problem.
The stepper motor suits me for now, but I will replace it if necessary. The issue here is with the PID.
This is a PID controller, but for some reason, the temperature at low values from 0 to 130 on the thermistor matches what the multimeter shows with a thermocouple. But when I set it to 200 degrees, for example, the temperature there reaches 180, and the multimeter shows 270 degrees, and the screen suddenly turns off, like nothing is visible there.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <MobaTools.h>
#include <PID_v1.h>
#include <thermistor.h>
#include <Bounce2.h>

// Pins
#define dirPin 7
#define stepPin 8
#define enablePin 9
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
#define temperaturePin A0
#define ENDSTOP_PIN 6  // Endstop pin

LiquidCrystal_I2C lcd(0x27, 16, 2);
thermistor therm1(temperaturePin, 0);

// Motor settings
const int MICROSTEPS = 8;
const int STEPS_PER_REVOLUTION = 200 * MICROSTEPS;
float maxRPS = 10.0, minRPS = 0.1, targetRPS = 1.0, currentRPS = 1.0;
float rpsStep = 0.1, acceleration = 1.0;

const float CYLINDER_DIAMETER_MM = 90.0f;  // Cylinder diameter in mm
const float GEAR_RATIO = 36.0f;           // Gear ratio 36:1

// Encoder
volatile int encoderPos = 0;
int lastEncoderPos = 0;
const int impulsesPerClick = 2;

// Motor
MoToStepper stepper(STEPS_PER_REVOLUTION, STEPDIR);

// Button
Bounce encoderButton = Bounce();

// PID
double setpoint = 220, input, output;
double Kp = 80.0, Ki = 35.0, Kd = 80.0;
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);

// Modes
#define MODE_ONOFF 0
#define MODE_SPEED 1
#define MODE_TEMP 2
#define MODE_PWM 3
byte currentMode = MODE_ONOFF;
bool isMotorOn = false;
bool endstopTriggered = false;

// Convert rotations per second to mm/s
float rpsToMmS(float rps) {
  float cylinderCircumference = PI * CYLINDER_DIAMETER_MM;
  float cylinderRps = rps / GEAR_RATIO;
  return cylinderRps * cylinderCircumference;
}

// Encoder interrupt handler
void updateEncoder() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > 5) {
    if (digitalRead(ENCODER_DT) == digitalRead(ENCODER_CLK))
      encoderPos--;
    else
      encoderPos++;
    lastInterruptTime = interruptTime;
  }
}

void setup() {
  Serial.begin(9600);
  
  lcd.init();
  lcd.backlight();
  
  pid.SetMode(AUTOMATIC);
  pid.SetOutputLimits(0, 255);
  input = therm1.analog2temp();
  
  pinMode(ENCODER_CLK, INPUT_PULLUP);
  pinMode(ENCODER_DT, INPUT_PULLUP);
  pinMode(enablePin, OUTPUT);
  pinMode(ENDSTOP_PIN, INPUT_PULLUP);  // Endstop pin setup
  digitalWrite(enablePin, LOW);
  
  encoderButton.attach(ENCODER_SW, INPUT_PULLUP);
  encoderButton.interval(25);
  
  stepper.attach(stepPin, dirPin);
  stepper.setSpeed(0);
  stepper.setRampLen(2);
  
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), updateEncoder, CHANGE);
  
  updateDisplay();
}

void loop() {
  static unsigned long lastTempUpdate = 0;
  static unsigned long lastDisplayUpdate = 0;
  
  // Check endstop
  endstopTriggered = (digitalRead(ENDSTOP_PIN) == LOW);
  
  if (millis() - lastTempUpdate > 300) {
    input = therm1.analog2temp();
    pid.Compute();
    analogWrite(5, output);
    lastTempUpdate = millis();
  }
  
  handleButton();
  handleEncoder();
  updateMotor();
  
  if (millis() - lastDisplayUpdate > 300) { 
    updateDisplay();
    lastDisplayUpdate = millis();
  }
}

void handleEncoder() {
  noInterrupts();
  int currentEncoderPos = encoderPos;
  interrupts();
  int delta = currentEncoderPos - lastEncoderPos;
  
  if (abs(delta) >= impulsesPerClick) {
    switch (currentMode) {
      case MODE_ONOFF:
        if (!endstopTriggered) {  // Only allow turning on if endstop isn't pressed
          isMotorOn = !isMotorOn;
        }
        break;
        
      case MODE_SPEED:
        targetRPS += (delta > 0) ? rpsStep : -rpsStep;
        targetRPS = constrain(targetRPS, minRPS, maxRPS);
        break;
        
      case MODE_TEMP:
        setpoint += (delta > 0) ? 1 : -1;
        setpoint = constrain(setpoint, 190, 230);
        break;
        
      case MODE_PWM:
        break;
    }
    lastEncoderPos = currentEncoderPos;
  }
}

void handleButton() {
  encoderButton.update();
  
  if (encoderButton.fell()) {
    currentMode = (currentMode + 1) % 4;
    updateDisplay();
  }
}

void updateMotor() {
  if (isMotorOn && !endstopTriggered) {  // Motor only runs if endstop isn't pressed
    if (abs(currentRPS - targetRPS) > 0.01) {
      currentRPS += (currentRPS < targetRPS) ? acceleration * 0.05 : -acceleration * 0.05;
      currentRPS = constrain(currentRPS, minRPS, maxRPS);
    }
    
    float effectiveSpeed = currentRPS / MICROSTEPS * 2;
    stepper.setSpeed(effectiveSpeed * STEPS_PER_REVOLUTION);
    stepper.rotate(1);
  } else {
    stepper.setSpeed(0);
    stepper.stop();
    if (endstopTriggered) {
      isMotorOn = false;  // Turn off motor when endstop is triggered
    }
  }
}

void updateDisplay() {
  lcd.clear();
  
  // First line: Temperature
  lcd.setCursor(0, 0);
  lcd.print("T:");
  lcd.print((int)input);
  lcd.print("C S:");
  lcd.print((int)setpoint);
  lcd.print("C");
  
  // Second line
  lcd.setCursor(0, 1);
  switch (currentMode) {
    case MODE_ONOFF:
      lcd.print("MODE: ");
      lcd.print(isMotorOn ? "ON" : "OFF");
      if (endstopTriggered) lcd.print(" STOP!");
      break;
      
    case MODE_SPEED:
      lcd.print(targetRPS, 1);
      lcd.print("RPS ");
      lcd.print(rpsToMmS(targetRPS), 1);
      lcd.print("mm/s");
      if (endstopTriggered) lcd.print(" STOP!");
      break;
      
    case MODE_TEMP:
      lcd.print("SET TEMP > ");
      lcd.print((int)setpoint);
      break;
      
    case MODE_PWM:
      lcd.print("PWM:");
      lcd.print((int)output);
      lcd.print("/255 ");
      lcd.print((int)(output/255.0*100));
      lcd.print("%");
      break;
  }
}

What is "it" in this sentence?

My problem is that the set temperature does not correspond to the actual temperature.
For example, when I set the temperature to 200°C, it rises, but when I check the temperature on the hotend with another sensor, it does not correspond to the actual temperature.

I have another Arduino Nano board, and I connected another thermistor to it, just like on the main board. The temperature is displayed correctly there.

The code is below:

// 3950 THERMISTOR EXAMPLE.
// Written by Miguel Angel Califa Urquiza
// Released under an MIT license.

// Depends on the following Arduino libraries:
// - Arduino thermistor library: https://github.com/miguel5612/Arduino-ThermistorLibrary

#include <thermistor.h>

thermistor therm1(A0,0);  // Analog Pin which is connected to the 3950 temperature sensor, and 0 represents TEMP_SENSOR_0 (see configuration.h for more information).


void setup() {
  // put your setup code here, to run once: 
  Serial.begin(9600); //initialize port serial at 9600 Bauds.
}

void loop() {
  double temp = therm1.analog2temp(); // read temperature
  //Print temperature in port serial
  Serial.print("Temperatura: "); 
  Serial.println((String)temp);
  Serial.print("----------------------");
  delay(2000); //wait 2000 mS for next measure
}

That sounds like a calibration problem.

How far off is it at 200C? What thermistor library are you using? And what does the 0 mean in:

Maybe the library allows the thermistor to be tuned to match your hardware.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.