How difficult is it to convert a sketch using MAX6675 boards to MAX31865

Hi everyone, total newbie to programming here but can take instructions well. I found a simple sketch for an ESP32 board to use up to four MAX6675 boards to emulate an Arduino with a TC4 (four channel thermocouple shield initially conceived for coffee roasting) but the TC4 isn't bulletproof and on the expensive side. I managed to wire up the hardware and got it working but I also happen to already have two MAX31865 boards on hand and there are plenty of praises about how RTDs beat thermocouples in most ways so I was wondering how difficult would it be to swap the MAX6675 library reference and related code to utilise a MAX31865 library and relevant code?

The code is below but unfortunately my ability in coding is only to remove the MAX6675 library reference and include the MAX31865 one from Adafruit although I'm using cheap Chinese MAX31865 boards.

#include <SerialCommands.h> // https://github.com/ppedro74/Arduino-SerialCommands
#include <BluetoothSerial.h> // Classic Bluetooth
#include <DHT.h> // DHT22
#include <Adafruit_MAX31865.h>

//#include <SPI.h> // MAX6675 over hardware SPI

// Bluetooth
#define ESP32_RTD_BLUETOOTH_NAME "U.A.F. Mk. 2" //Bluetooth device name
BluetoothSerial SerialBT;

// DHT22
#define DHTPIN                 22 // GPIO22 -> DHT22 Output
#define DHTTYPE             DHT22
DHT dht(DHTPIN, DHTTYPE);
double humidity;
double ambientc;
double ambientf;

// MAX6675
#define TC1_CS                 32 // GPIO32 -> CS MAX6675[TC1]
#define TC2_CS                 33 // GPIO33 -> CS MAX6675[TC2]
#define TC3_CS                 25 // GPIO25 -> CS MAX6675[TC3]
#define TC4_CS                 26 // GPIO26 -> CS MAX6675[TC4]
/* Note: All MAX6675
 *  MAX6675 to  EPS32
 *  VCC     ->  3.3V
 *  GND     ->  GND
 *  SCK     ->  GPIO18/CLK
 *  SO      ->  GPIO19/MISO
 */

bool unit_F               = false;

#define SMA                     5
int sma_idx                   = 0;
bool sma_filled           = false;
double tc1s[SMA], tc2s[SMA], tc3s[SMA], tc4s[SMA];
double tc1, tc2, tc3, tc4;

// DHT22
void readDHT(){
  float h = dht.readHumidity();
  float c = dht.readTemperature();
  float f = dht.readTemperature(true);

  if(!isnan(h)){
    humidity = h;
  }
  if(!isnan(c)){
    ambientc = c;
  }
  if(!isnan(f)){
    ambientf = f;
  }
}

// MAX6675
double readCelsius(uint8_t cs) {
  uint16_t v;

  digitalWrite(cs, LOW);
  v = SPI.transfer(0x00);
  v <<= 8;
  v |= SPI.transfer(0x00);
  digitalWrite(cs, HIGH);

  if (v & 0x4) {
    // uh oh, no thermocouple attached!
    return NAN; 
  }

  v >>= 3;

  return v*0.25;
}

double readFahrenheit(uint8_t cs) {
  return readCelsius(cs) * 1.8 + 32;
}

bool readTCs(){
  tc1s[sma_idx] = readCelsius(TC1_CS);
  tc2s[sma_idx] = readCelsius(TC2_CS);
  tc3s[sma_idx] = readCelsius(TC3_CS);
  tc4s[sma_idx] = readCelsius(TC4_CS);
  if(!isnan(tc1s[sma_idx]) && !isnan(tc1s[sma_idx]) && !isnan(tc1s[sma_idx]) && !isnan(tc1s[sma_idx])){
    sma_idx++;
    if(sma_idx >= SMA){
      sma_filled = true;
      sma_idx = 0;
    }
    tc1 = 0;
    tc2 = 0;
    tc3 = 0;
    tc4 = 0;
    if(sma_filled){
      for(int i = 0; i<SMA; i++){
        tc1 += tc1s[i];
        tc2 += tc2s[i];
        tc3 += tc3s[i];
        tc4 += tc4s[i];
      }
      tc1 /= SMA;
      tc2 /= SMA;
      tc3 /= SMA;
      tc4 /= SMA;
    }
    return true;
  }
  return false;
}


// USB & Bluetooth SerialCommands
char serialbt_cmds_buffer[32];
char serial_cmds_buffer[32];
SerialCommands serialbt_cmds(&SerialBT, serialbt_cmds_buffer, sizeof(serialbt_cmds_buffer), "\n", ";");
SerialCommands serial_cmds(&Serial, serial_cmds_buffer, sizeof(serial_cmds_buffer), "\n", ";");

//This is the default handler, and gets called when no other command matches. 
void cmd_unrecognized(SerialCommands* sender, const char* cmd){
  sender->GetSerial()->print("Unrecognized command [");
  sender->GetSerial()->print(cmd);
  sender->GetSerial()->println("]");
}

void cmdSetChannel(SerialCommands* sender){
  sender->GetSerial()->println("#OK");
}
SerialCommand serialCmdSetChannel("CHAN", cmdSetChannel);

void cmdSetUnits(SerialCommands* sender){
  char* units = sender->Next();
  if (units[0] == 'F'){
    unit_F = true;
    sender->GetSerial()->println("#OK Farenheit");
  }else if (units[0] == 'C'){
    unit_F = false;
    sender->GetSerial()->println("#OK Celsius");
  }
}
SerialCommand serialCmdSetUnits("UNITS", cmdSetUnits);

void cmdSetFilter(SerialCommands* sender){
  sender->GetSerial()->println("#OK");
}
SerialCommand serialCmdSetFilter("FILT", cmdSetFilter);

void cmdRead(SerialCommands* sender){
  readDHT();
  if(unit_F){
    sender->GetSerial()->print(ambientf);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc1 * 1.8 + 32);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc2 * 1.8 + 32);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc3 * 1.8 + 32);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc4 * 1.8 + 32);
    sender->GetSerial()->print(",0.00,0.00,0.00"); // Heater, Fan, PID set value
  }else{
    sender->GetSerial()->print(ambientc);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc1);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc2);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc3);
    sender->GetSerial()->print(",");
    sender->GetSerial()->print(tc4);
    sender->GetSerial()->print(",0.00,0.00,0.00"); // Heater, Fan, PID set value
  }
  sender->GetSerial()->println("");
}
SerialCommand serialCmdRead("READ", cmdRead);


void setup(){
  // DHT22 for ambient and humidity
  pinMode(DHTPIN, INPUT);
  dht.begin();

  // Thermocouple (MAX6675 x4 over hardware SPI)
  pinMode(TC1_CS, OUTPUT);
  pinMode(TC2_CS, OUTPUT);
  pinMode(TC3_CS, OUTPUT);
  pinMode(TC4_CS, OUTPUT);
  digitalWrite(TC1_CS, HIGH);
  digitalWrite(TC2_CS, HIGH);
  digitalWrite(TC3_CS, HIGH);
  digitalWrite(TC4_CS, HIGH);
  SPI.begin();
  SPI.beginTransaction (SPISettings (1000000, MSBFIRST, SPI_MODE0));

  // USB Serial
  Serial.begin(115200);
  serial_cmds.SetDefaultHandler(cmd_unrecognized);
  serial_cmds.AddCommand(&serialCmdSetChannel);
  serial_cmds.AddCommand(&serialCmdSetUnits);
  serial_cmds.AddCommand(&serialCmdSetFilter);
  serial_cmds.AddCommand(&serialCmdRead);
  // Bluetooth Serial
  SerialBT.begin(ROAST_ESP32_BLUETOOTH_NAME);
  serialbt_cmds.SetDefaultHandler(cmd_unrecognized);
  serialbt_cmds.AddCommand(&serialCmdSetChannel);
  serialbt_cmds.AddCommand(&serialCmdSetUnits);
  serialbt_cmds.AddCommand(&serialCmdSetFilter);
  serialbt_cmds.AddCommand(&serialCmdRead);

  sma_idx = 0;
  sma_filled = true;
  tc1 = 0;
  tc2 = 0;
  tc3 = 0;
  tc4 = 0;
}

void loop(){
  serialbt_cmds.ReadSerial();
  serial_cmds.ReadSerial();
  if(readTCs()){
    delay(200);
  }
}

No! Usually we have to ask, go for it.

Use the <CODE/> tool in the message composition window when you do.

a7

depends on your programming knowledge.
MAX31865 has a four-pin interface
MAX6675 has a three pin interface

My suggestion is that you post your existing code and your attempt to modify the code to use the MAX31865-lib instead of the MAX6675-lib combined with questions about the details.

best regards Stefan

I would not have seen it except I re-read your first post.

It is preferred that you not do major editing or additions to posts. In a larger thread you would see that it would make some answers meaningless.

I've looked at both libraries. Both come with very simple example sketches. Have you studied those?

If you look closely, you will see which very few lines of code have anything at all to do with interfacing to your device.

Perhaps a place to start would be to learn about how the SPI bus works. If you have a grip on that you will get very far along. There may be a few subtleties, again looking closely at the small sketches will turn up clues.

Like I saw that one of the chips needs at least 250 milliseconds between readings. If the original code used the one that does not (and even it may, dunno) that would be the kind of detai I am talking about.

One of the chips offers some additional outputs. If yuor origianl code exploiuted those, you may find you have a harder job.

Please post, in your next contribution to this discussion, code you have that would work for the sensors you don't have, and say again if you didn't, where that code came from.

a7

1 Like

Interesting you failed to mention what type of thermocouple you are using. The MAX31855 is K-type only . The Max31856 can handle K, J, N, R, S, T, E, or B type thermocouples. The MAX6675 is being discontinued.

My original post had already explained that I'm currently using MAX6675 boards. Antique or otherwise, they're still commonly used and cheaply available but I also have MAX31865 boards on hand which was why I was thinking of switching to PT100s if it's not too difficult for a person with totally no C++ knowledge to edit some code.

I used to be in small animal surgery and have pretty extensive experience there and somehow or other, I find doing a major amputation easier than learning coding. :joy:

1 Like

Sorry, I thought it'll be easier for others seeing my post for the first time.

No problem some details were missing such as thermocouple type. If you are using a type J it will not work.

Currently using Type Ks but that's irrelevant because my question was about switching over to MAX31865s and RTDs.

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