Edit PID code to receive data from TC Breakoutboard MAX31855

Hi all

I have a code for a PID Temperature controller that I made a while back.

It was basically an arduino reading an analog voltage signal from a TC amplifier, a 2x16LCD (without serial backpack), a few buttons for some control, and the digital PID output went to a MOSFET to control a heater.

Now I have a new kit I am messing with. What is different now is I have my temperature being supplied via one wire (SPI) from a Thermocouple Amplifier MAX31855 breakout board, I also have a 2x16 LCD from sparkfun that’s got the serial backpack for one wire control, lastly I have added a analog (0-5v) LED bar graph so I can monitor the output. This new version will also have the 3 buttons (on/off, temp up, temp down)

Now I want to basically migrate all I had (funtion-wise) from the old code into a simpler code for the new hardware since the hardware has been simplified to digital communication.

Here’s the original code. .

#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <PID_v1.h> 
#include <SPI.h>

double Setpoint, Input, Output;
double Kp=4, Ki=1, Kd=2, LoLIM=10, HiLIM=255; 

double SampleTime=250;
LiquidCrystal lcd(12, 11, 8, 4, 3, 2);

const int onPin = 5;     //pin to trigger heater
const int upPin = 6;     //  pin to increase temp
const int downPin = 7;   //pin to decrease temp
int buttonState = 0;     // variable for reading the pin status
int DownPushed = 0;
int UpPushed = 0;
int OnPushed = 0;
int PID_ON = 0;
int UpdScr = 0;
int inpt;
int gap;
int S_gap;
int count;
int EEPROM_ADDR;

void UpdateEEPROM() {

  int val, wr;
  val = (int) Setpoint;
  wr = val>>8;
  EEPROM.write(EEPROM_ADDR, wr);
  wr = val & 0XFF;
  EEPROM.write(EEPROM_ADDR+1, wr);

};

void LoadEEPROM() {
  int val;
  val = EEPROM.read(EEPROM_ADDR);
  val = val <<8;
  val +=EEPROM.read(EEPROM_ADDR+1);
  Setpoint = val;

};
unsigned long lastTime, lShowTime; 

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);


void setup()
{
  Serial.begin( 19200 );
  //initialize the variables we're linked to
  Input = analogRead(0);
  LoadEEPROM();
  if( (Setpoint +1.) < 0.001)
    Setpoint = 575;    //    Setpoint = xxx;   

  // Declare inputs
  pinMode(onPin, INPUT);    // declare pushbutton as input, turn PID ON
  pinMode(upPin, INPUT);    // declare pushbutton as input, increase Setpoint
  pinMode(downPin, INPUT);  // declare pushbutton as input, decrease Setpoint
  
  //turn the PID on STANDBY
  myPID.SetOutputLimits(LoLIM, HiLIM);
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(SampleTime);
  myPID.SetTunings(Kp, Ki, Kd);

  lShowTime = lastTime = millis();

  // set up the LCD's number of columns and rows:
  lcd.begin(16,2);

  count = 0;
  EEPROM_ADDR = 30;
  
}

void loop()
{
  Input = analogRead(0);

  buttonState = digitalRead(onPin);

  if (buttonState == HIGH) {
    // turn HEATER on, but prime first:
    myPID.SetMode(AUTOMATIC);
    PID_ON =1;                
  } 
  else {
    myPID.SetMode(MANUAL);
    Output = 0;
    PID_ON =0;
  }

  myPID.Compute();
  analogWrite(9,Output);
  // I would not change these lines, because you are expecting 250 ms for a "push"
  // that is if you hold button for more then 1/4 second, 
  if(digitalRead(upPin)==HIGH) {
    if (millis()-lastTime >= 250) {
      Setpoint+=5;
      UpdateEEPROM();
      lastTime=millis();
      UpdScr = 1;
    }
  }

  if(digitalRead(downPin)==HIGH) {
    if (millis()-lastTime >= 250) {
      Setpoint-=5;
      UpdateEEPROM();
      lastTime=millis();
      UpdScr = 1;
    }
  }

  //and output to LCD

  if( (millis() - lShowTime > 100 ) || UpdScr ) {
    UpdScr = 0;
    lcd.setCursor(0,0);
    //if heater is on - show *
    //if not - empty
    if( PID_ON ==1 ) {
      lcd.print("*");
    }
    else {
      lcd.print(" ");
    }
    lcd.print("SET.TEMP-> ");
    lcd.print((int)(Setpoint) );
    lcd.setCursor( 0,1);
    lcd.print("AIR.TEMP-> ");
    inpt = (inpt *5 + Input)/6;
    count = (count +1)%6;

    if(count == 0) {
      if( inpt < 100) lcd.print( " ");
      lcd.print( inpt );
    }


    lShowTime = millis();  
  }

}

I guess I just would like to know the best way to send the serial data from the MAX31855 board to the “Input” of the PID, achieve a similar readout on the new LCD as I had on my older LCD, and eventually be able to send the output level of the PID to the analog LED bar graph(there must be a trick to convert the digital PID output to analog).

Any help is greatly appreciated!! Tips, code, or reference material!!

Serial LCD Kit Quickstart Guide - SparkFun Electronics <–LCD

http://forum.arduino.cc/index.php?topic=208061.0 ← MAX31855 Thermocouple Amp Board

GitHub - thisdroneeatspeople/SparkSoftLCD: Single-pin Arduino Serial Interface Library for SparkFun Serial LCDs <— Something I should probably use?

Here’s a sample of code to read the MAX31855 TC Board

//
//    FILE: max31855_demo1.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.01
// PURPOSE: thermocouple lib demo application
//    DATE: 2014-01-02
//     URL:
//
// Released to the public domain
//

#include "MAX31855.h"

const int doPin = 7;
const int csPin = 6;
const int clPin = 5;

MAX31855 tc(clPin, csPin, doPin);

void setup()
{
  Serial.begin(115200);
  Serial.print("Start max31855_demo: ");
  Serial.println(MAX31855_VERSION);
  Serial.println();

  tc.begin();
}

void loop()
{
  int status = tc.read();
  if (status != 0)
  {
    Serial.print("stat:\t\t");
    Serial.println(status);
  }

  float temp = tc.getTemperature();
  int m = temp*10 - 200;
  Serial.print(temp);
  Serial.print('\t');
  for (int i=0; i< m; i++) Serial.write(']');
  Serial.println();
}

Well I now realize the entries for the EEPROM are so hold the Setpoint value so when I adjust it through my pushbuttons it retains whatever its set at while the loop runs.

I got the LCD to work and display the temperature from the serial breakout board… Its a butchered modification but its working so far.

The weird thing is at the end when I try and send the “Setpoint” to the LCD its a number like 27,135 instead of the default 575.

I put

LCD.print((int)Setpoint);

Something makes me think that:

UpdateEEPROM()

LoadEEPROM()

have something to do with that.

How can I plug the thermocouple.readFarenheit() into the PID input instead of how it previously was done by Input = analogRead(0)

Here’s what i’ve done.

#include <EEPROM.h>
#include <PID_v1.h> 
#include <SPI.h>
#include "Adafruit_MAX31855.h"
#include <SoftwareSerial.h>

double Setpoint, Input, Output;
double Kp=4, Ki=1, Kd=2, LoLIM=10, HiLIM=255; 

double SampleTime=250;


const int onPin = 8;     //pin to trigger heater
const int upPin = 9;     //  pin to increase temp
const int downPin = 11;   //pin to decrease temp
int buttonState = 0;     // variable for reading the pin status
int DownPushed = 0;
int UpPushed = 0;
int OnPushed = 0;
int PID_ON = 0;
int UpdScr = 0;
int inpt;
int gap;
int S_gap;
int count;
int EEPROM_ADDR;


int thermoCLK = 5;
int thermoCS = 4;
int thermoDO = 3;
// Initialize the Thermocouple
Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);

float degF = 0.00;
// variable to store the value 
 

double c = thermocouple.readCelsius();

void UpdateEEPROM() {

  int val, wr;
  val = (int) Setpoint;
  wr = val>>8;
  EEPROM.write(EEPROM_ADDR, wr);
  wr = val & 0XFF;
  EEPROM.write(EEPROM_ADDR+1, wr);

};

void LoadEEPROM() {
  int val;
  val = EEPROM.read(EEPROM_ADDR);
  val = val <<8;
  val +=EEPROM.read(EEPROM_ADDR+1);
  Setpoint = val;

};
unsigned long lastTime, lShowTime; 

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);


#define txPin 2

SoftwareSerial LCD = SoftwareSerial(0, txPin);
// since the LCD does not send data back to the Arduino, we should only define the txPin
const int LCDdelay=10;  // conservative, 2 actually works



void setup()
{
  pinMode(txPin, OUTPUT);
  LCD.begin(9600);
  clearLCD();
  lcdPosition(0,0);
  LCD.print("TEST");
  delay(1000);
  clearLCD();
  
  
    
  Input = analogRead(0);
  LoadEEPROM();
  if( (Setpoint +1.) < 0.001)
    Setpoint = 575;    //    Setpoint = xxx;   

  // Declare inputs
  pinMode(onPin, INPUT);    // declare pushbutton as input, turn PID ON
  pinMode(upPin, INPUT);    // declare pushbutton as input, increase Setpoint
  pinMode(downPin, INPUT);  // declare pushbutton as input, decrease Setpoint
  
  //turn the PID on STANDBY
  myPID.SetOutputLimits(LoLIM, HiLIM);
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(SampleTime);
  myPID.SetTunings(Kp, Ki, Kd);

  lShowTime = lastTime = millis();


  count = 0;
  EEPROM_ADDR = 30;
  
}

void loop()
{
    Input = analogRead(0);
  degF = (thermocouple.readFarenheit());


  buttonState = digitalRead(onPin);

  if (buttonState == LOW) {
    // turn HEATER on, but prime first:
    myPID.SetMode(AUTOMATIC);
    PID_ON =1;                
  } 
  else {
    myPID.SetMode(MANUAL);
    Output = 0;
    PID_ON =0;
  }

  myPID.Compute();
  analogWrite(9,Output);
  // I would not change these lines, because you are expecting 250 ms for a "push"
  // that is if you hold button for more then 1/4 second, 
  if(digitalRead(upPin)==HIGH) {
    if (millis()-lastTime >= 250) {
      Setpoint+=5;
      UpdateEEPROM();
      lastTime=millis();
      UpdScr = 1;
    }
  }

  if(digitalRead(downPin)==HIGH) {
    if (millis()-lastTime >= 250) {
      Setpoint-=5;
      UpdateEEPROM();
      lastTime=millis();
      UpdScr = 1;
    }
  }

  //and output to LCD status and readings
  if( PID_ON ==1 ) {
      lcdPosition(0,0);
      LCD.print("*");
    }
    else {
      lcdPosition(0,0);
      LCD.print(" ");
    }
  lcdPosition(0,1);
    LCD.print("SetPoint= ");
    lcdPosition(0,10);
    LCD.print((int)Setpoint);
    lcdPosition(1,1);
    LCD.print("AirTemp=");
    lcdPosition(1,9);
    LCD.print((int)degF);
    
}

How can I plug the thermocouple.readFarenheit() into the PID input instead of how it previously was done by Input = analogRead(0)

I admit that I have not read your post thoroughly, but the simple answer would seem to be.

  Input = thermocouple.readFarenheit();

There may be issues with data types though because Input is a double and it looks like thermocouple.readFarenheit() returns a float in you program.