Thermocouple Time Response Assistance

Hello.

I'm trying to send thermocouple measurements to a file on my computer and measure the time response of the sensor by dumping it in ice-water. I have been successful (sort of) but there are a couple areas I don't understand and would like some assistance.

Below is my current code (thanks in large part to Adafruit). I am using a program called "Gobetwino" to save the recorded data to a text file on my computer.

I would like to sample and send data to Gobetwino as fast as possible without messing with the default Arduino clock speeds. I have only been successful, however, in recording 1 temp measurement every 67 milliseconds.

Gobetwino requires the serial message to be sent as a string in a very specific format. I am sending both the measurement and the millis() to Gobetwino as a message. I have a high level of confusion in understanding how many bits this means I am actually sending.

For example, the temperature measurement is usually in the form of "25.34" or "0.03" while the millis() variable might equal "564" or "1113456". My confusion is that if more or less integers are present, I don't understand how many bits of data these values represent?

I did a sizeof() command on both the millis() and temperature strings and both returned a "6" each. I believe this means I am sending a total of 12 BYTES (which would equal 12 x 8 = 96 BITS per message).

Taking 9600 BAUD, (or 9600 bits/sec) and dividing by 96 bits/message = 100 messages/sec

Dividing 1 second (1000 milliseconds) by 100 messages = 10 milliseconds/message

This is nowhere near the 67 milliseconds per message I'm actually recording. I understand the code itself will take some time to run, but I don't believe it should take that much time? I'm missing something crucial here in my understanding of strings, bits, and bytes, so any help is greatly appreciated. The strange part is that the 67 milliseconds between readings doesn't change when I change the BAUD to 115200 either.

Finally, it's really annoying that I'm sending the temp reading and the millis() as basically one string of numbers. It's not a huge deal because when I import the text file into excel I can delineate the data columns by fixed width. The problem, however, is when the temp drops from a two digit number to a 1 digit number (such as from 25 to 1), the text file doesn't add a leading zero to the single digit number (01) so the column spacing gets off and I have to manually go through all the data and add leading zeros.

EXAMPLE:

TEMP|MILLIS

25.43|564
22.32|668
4.687|69 -----> Column now off by 1 position
0.029|09


The solution, I think, would be to add a "deliminator" such as a "," between the strings when it is sent to Gobetwino. Unfortunately, I can't figure out how to do this in Arduino code.

Any and all help is greatly appreciated. I'm also extremely open to suggestions on how to make this code run and capture data more effectively.

Thanks in advance.

Respectfully,
Chase Brumfield

APOLOGIES: Just realized I left out a crucial piece of informaiton. I am using the MAX31855K found HERE.

/*************************************************** 
  This is an example for the Adafruit Thermocouple Sensor w/MAX31855K

  Designed specifically to work with the Adafruit Thermocouple Sensor
  ----> https://www.adafruit.com/products/269

  These displays use SPI to communicate, 3 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
//The original Adafruit code has been edited by Chase Brumfield for this particular
//application

//Calibrate the thermocoupple and change variable "correction factor" as needed
//for more accurate readings

#include <SPI.h>
#include "Adafruit_MAX31855.h"

// Create a thermocouple instance with software SPI on any three
// digital IO pins.
#define MAXDO   3
#define MAXCS   4
#define MAXCLK  5

int correction_factor = 2; //specific to thermocouple used, amount the thermocouple 
                            //is reporting higher than real temp [C] (for calibration)

unsigned long time; //used for millis() at bottom of code

int num; //used as variable to display length of strings sent to "Gobetweeno"

// initialize the Thermocouple
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

void setup() {
 while (!Serial); // wait for Serial on Leonardo/Zero, etc
  
  Serial.begin(9600);
  
  Serial.println("MAX31855 test");
  // wait for MAX chip to stabilize
  delay(500);
}

void loop() {
   double c = thermocouple.readCelsius()-correction_factor;
   if (isnan(c)) {
     Serial.println("Something wrong with thermocouple!");
   } else {
/////////////////////////////////////////////////////////
//Below are commands for saving data with "Gobetweeno"
/////////////////////////////////////////////////////////
     time = millis();
     String stringTime = String(time); //converts "time" variable (milliseconds elapsed) into a string
     String stringC = String(c, 2); //Converts variable "c" to a string type and names it "stringC"
     //Serial.println(stringC);
     //num = sizeof(stringC); //trying to understand the number of bytes sent to serial
     //Serial.println(num);
     //Serial.println(stringTime);
     //num = sizeof(stringTime); //trying to understand the number of bytes sent to serial
     //Serial.println(num);
     Serial.print("#S|TEMPDATA|["); //The next 3 lines are for sending to "Gobetwino"
     Serial.print(stringC);  //See "Gobetwino" .pdf manual for clarification
     Serial.print(stringTime);  //See "Gobetwino" .pdf manual for clarification
     Serial.println("]#"); //See "Gobetwino" .pdf manual for clarification

//delay(10);
   }
}

Just found the attached image on PAGE 4 of the Datasheet. Does this mean that the MAX31855 is actually my limiting factor here with a conversion time of 70ms?

Thanks in advance.

The MAX31855 is not the right tool to study thermocouples. It's the tool you use when you don't care about the thermocouple and you want it to "just work dammit!"

At that level of time resolution, the Arduino is probably not the right tool either. analogRead() is a surprisingly slow function. I would go with a dedicated instrumentation amplifier and a recording oscilloscope for this project.

If you want to eliminate the serial communications overhead you could store your readings in an array and then send all the data over serial later. You will be limited by the amount of free SRAM. Don't do any conversion of the numbers to text until you send the data as this will incur overhead and use more memory. Of course this might not be necessary if the "Temperature Conversion Time" is the limiting factor.

cbrum11:
I have a high level of confusion in understanding how many bits this means I am actually sending.

For example, the temperature measurement is usually in the form of "25.34" or "0.03" while the millis() variable might equal "564" or "1113456". My confusion is that if more or less integers are present, I don't understand how many bits of data these values represent?

You're sending characters so it's one byte per character, so if the temperature is 25.34 and the timestamp is 564 then the string you're sending is:
#S|TEMPDATA|[25.34564]#
That's 23 bytes plus one for the newline so 24 bytes total. You can almost certainly use a higher baud rate than 9600.

cbrum11:
Finally, it's really annoying that I'm sending the temp reading and the millis() as basically one string of numbers. It's not a huge deal because when I import the text file into excel I can delineate the data columns by fixed width. The problem, however, is when the temp drops from a two digit number to a 1 digit number (such as from 25 to 1), the text file doesn't add a leading zero to the single digit number (01) so the column spacing gets off and I have to manually go through all the data and add leading zeros.

I'd send it as comma separated data:

    Serial.print(stringC);  //See "Gobetwino" .pdf manual for clarification
     Serial.print(',');  //See "Gobetwino" .pdf manual for clarification
     Serial.println(stringTime);  //See "Gobetwino" .pdf manual for clarification

Then you can just save the file as .csv file and it will be properly formatted in Excel without any extra work.

Thanks for the responses! The helpfulness of the people on these forums never ceases to amaze me.

MorganS:
The MAX31855 is not the right tool to study thermocouples. It's the tool you use when you don't care about the thermocouple and you want it to "just work dammit!"

At that level of time resolution, the Arduino is probably not the right tool either. analogRead() is a surprisingly slow function. I would go with a dedicated instrumentation amplifier and a recording oscilloscope for this project.

So, I've heard others talk about the "slowness" of the AnalogRead function, but in the Arduino documentation it says the following:

It takes about 100 microseconds (0.0001 s) to read an analog input, so the maximum reading rate is about 10,000 times a second.

I'm pretty new to coding and micro-controllers, but for this particular application (unless I'm thinking about it wrong) that doesn't seem to be the limiting factor? My thermocouple is approximately 30 gauge [.01mm diameter]. I used THIS GRAPH to estimate a time constant of about .25 seconds or 250 milliseconds.

I believe 5 time constants is a generally accepted standard, thus, the thermocouple itself likely won't reach the actual ice water temp for approximately 1.25 seconds or 1250 milliseconds [250 ms x 5 time constants].

I'm just doing this with the Arduino to learn a little coding and better understand how to manipulate different types of variables. I agree with you completely, an Oscilliscope would be a much better way to do this. Maybe I'll do both and compare them!

pert:
You're sending characters so it's one byte per character, so if the temperature is 25.34 and the timestamp is 564 then the string you're sending is:
#S|TEMPDATA|[25.34564]#
That's 23 bytes plus one for the newline so 24 bytes total. You can almost certainly use a higher baud rate than 9600.

This makes a lot of sense. Thanks. I still have an issue though.

24 bytes/message x 8 bits/byte = 192 bits/message

9600 bits/sec [divided by] 192 bits/message = 50 messages/sec

1000 milliseconds/second [divided by] 50 messages/sec = 20 milliseconds/message

This is still nowhere near the 67 milliseconds/message I'm currently seeing.

Do you think, since the thermocouple datasheet states a "typical" tempreature conversion time of 70ms, that is why I keep getting approximately 67 milliseconds between readings? Do you think this is also why that interval stays constant regardless of different baud rates?

pert:
If you want to eliminate the serial communications overhead you could store your readings in an array and then send all the data over serial later.

I like this idea a lot but unfortunately do not have the skills yet to accomplish it. I'll do some research and maybe try this down the road.

Serial.print(',');

DOH! This is so easy @Pert. Thanks! Is the "," still considered 1 char?

Thanks again for all your assistance. It's amazing to me that all this stuff actually works! haha.

-Chase

cbrum11:
This is still nowhere near the 67 milliseconds/message I'm currently seeing.

Do you think, since the thermocouple datasheet states a "typical" tempreature conversion time of 70ms, that is why I keep getting approximately 67 milliseconds between readings? Do you think this is also why that interval stays constant regardless of different baud rates?

It's easy enough to test with something like this:

unsigned long readStart = micros();
double c = thermocouple.readCelsius();
unsigned long readEnd = micros();
Serial.print("Thermocouple read duration: ");
Serial.print(readEnd - readStart);
Serial.println(" us");

The remaining portion of the 67 ms is your String conversions and serial communication. I do use the MAX31855K but response time isn't so crucial in my application and I really don't know exactly what is meant by the "Temperature Conversion Time" in the datasheet. I think MorganS's advice is good but it's still interesting to see how fast you can get readings from the MAX31855K. Even if what you learn isn't relevant to this project it's certainly generally useful knowledge.

Take a look at the software SPI code in the Adafruit library (Adafruit-MAX31855-library/Adafruit_MAX31855.cpp at master · adafruit/Adafruit-MAX31855-library · GitHub):

  } else {
    // software SPI

    digitalWrite(sclk, LOW);
    delay(1);

    for (i=31; i>=0; i--) {
      digitalWrite(sclk, LOW);
      delay(1);
      d <<= 1;
      if (digitalRead(miso)) {
	d |= 1;
      }
      
      digitalWrite(sclk, HIGH);
      delay(1);
    }
}

That's 65 ms of delays as well as the relatively slow digitalWrite() calls!

I think you would see a significant reduction in the duration of the readCelcius() call if you connect the MAX31855K to the hardware SPI pins on your Arduino instead and only pass the CS pin to the constructor, which will cause the library to use the more efficient hardware SPI.

A PR of interest in the Adafruit MAX31855K library's repository:

The library code has been changed since that PR was submitted but there's still that unnecessary 1 ms delay after pulling the CS pin LOW whether you're using hardware or software SPI:

You can get a very minimal increase in your loop speed by adding this line to your sketch:

void serialEventRun() {}

It shaves off a meager ~2 us but only comes at the cost of not being able to use the serialEvent() feature, not much of a loss.

There's another easy trick you can use to speed things up a little if you're using an older version of the Arduino AVR Boards package but the more modern compiler and settings used in the latest versions is smart enough to do this automatically.

The String conversions are not necessary, you could just print time and c directly.

The extra characters you're sending for the gobetwino protocol will slow things down. You could instead print to the Arduino IDE's Serial Monitor without those characters and then just copy and paste the text off the screen or use a more advanced program that can write the serial data to a text file without needing the extra characters.

Now it may very well be that these optimizations are irrelevant if the MAX31855K is unable to produce temperature readings faster than you're requesting them.

cbrum11:
Is the "," still considered 1 char?

Correct