Thermocouple confusion

I posted this to another thread from a while back, but since it may no longer be followed I'm posting it as a fresh thread

I'm going to be using the AD595 with a type K thermocouple for a kiln controller.

so far I'm just trying to get a value to show on an LCD that is the analog value converted to degrees F

the AD595 puts out a linear 0 - 5v for the input from the thermocouple. that said, I plan to use a pot for test purposes, the formula for converting the voltage to degrees F is as follows.

Temp(F) = (355.2823 * Volts) - 16.7674

now I need to convert the analog input from 0-1023 back to volts

so I'm figuring I'll be dividing 5 by 1024 giving me an awkward decimal for the constant

in other words I'll be multipyling the input value 0-1023 by 5/1024

multiplying that by 355.2823

and subtracting 16.7674

to render the temperature in degrees F

that's where it gets hazy for me

for one thing I don't see any reason to include the entire math library if I'm only going to be using a single function, and I'm not even sure that is in there. I see other examples where they do use math.h but memory is going to be precious in this application so I'm looking to keep it as lean as possible.

can I just define a constant as the fraction 5/1024

the following is what I have with some things I know to be incorrect such as how to define the constant and the math function converting the volts to the temperature value in degrees F

I also know I could simplify it by multiplying 5*355.2823 and dividing that by 1024 (giving me 1.7348 for the constant - constVolt in the example below) then I only need to multiply it by the sensorValue and subtract 16.7674

in other words (constVolt*sensorValue)-16.7674

with constVolt now defined as 1.7348

So here is what I have so far

thanks for any input and Advice,

Carl

/*

Analog input from T/C amp displayed as value on LCD

*Varied 0-5Vdc to analog input 0

*LCD RS pin to digital pin 12
*LCD Enable pin to digital pin 11
*LCD D4 to digital pin 5
*LCD D5 to digital pin 4
*LCD D6 to digital pin 3
*LCD D7 to digital pin 2
*LCD R/W pin to GND
*LCD V0 Pin to 0-5V for contrast

*/

// include library code
#include <LiquidCrystal.h>

// initialize with the numbers of interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int sensorPin =A0; //select input pin for thermocouple amplifier
int sensorValue =0; //variable to store the value coming from the sensor
float temp =0; //variable to store calculated temp

#define constVolt 5/1024 //constant converting analog value 0-1023 to 0-5v

void setup() {
//setup the LCD's number of columns and rows
lcd.begin(20, 4);
}

void loop() {
// read value from T/C:
sensorValue = analogRead(sensorPin);
// convert to degrees F
temp = (constVolt)(sensorValue)(355.2823)-16.7674
//set the cursor to column 0, line 1
lcd.setCursor(0,1);
// print temp value
lcd.print(temp);

for one thing I don't see any reason to include the entire math library if I'm only going to be using a single function, and I'm not even sure that is in there.

Including a header file in the source code and including a library in the compiler/linker output are two different things.

The compiler will see the header file, and compile the corresponding source file, to create an object file. The linker will then pick stuff it needs, and only what it needs from the object file.

If you don't actually reference anything from the library, nothing will end up on the hex file/on the Arduino.

But, the whole discussion is academic, anyway. The math.h library includes sin(), cos(), and stuff like that, not simple multiplication and division operations.

can I just define a constant as the fraction 5/1024

If you define a constant as 5/1024, the computation still needs to be performed, so the same code gets linked in. As a constant, though, 5/1024 is 0. Now, 5.0/1024.0 will be approximately 0.0048828.

Keep in mind that

#define constVolt 5/1024

simply defines a name and a value. The preprocessor will find all occurrences of the name (constVolt) and substitute the value (5/1024) in its place BEFORE the compiler is invoked. So, everywhere constVolt is referenced will generate code to divide 5 by 1024 (as integers) producing 0, resulting in no net savings.

On the other hand

const float constVolt = 5.0/1024.0;

will result in the computation 5.0 divided by 1024.0 being performed once, and stored in constVolt, resulting (potentially) in some performance and memory savings.

Finally, magic numbers like 355.2823 have no place in the code. There should be a const float of #define statement that assigns that value to a variable or name, with some comments that describe where that number came from, so that if you need to revise it, or someone else wants to use the code with a slightly different sensor, the change is easily made.

I'm a big fan of the Map function myself and if you wanted to display the temp in F out to two decimal places you could try this instead

temp = map(sensorValue*100,0,102300,3074,92309)/100;

If you wanted better precision and accuracy then you'd be better off using a MAX6675 since the temperature is already converted to a digital reading. Plus there is a library written for it already.

This would address part of your question, and maybe give you an idea how to deal with the rest, without using any floating point or math.

/* Measure the battery voltage and encode and transmit a
 * telemetry message back to the sender.
 */
void encode_voltage(void)
{
  long voltage;
  char buf[8];
  
  /* The AtoD reading is 0V..5V yielding readings of 0..1023
   * Voltage is computed from reading by dividing by 204.6.
   * We want to do this calculation using integer fixed point
   * Arithmetic to calculate volts x 100.  This will be reading
   * divided by 2.046.  To retain accuracy we first multiply
   * by 64K, then divide by 65536 * 2.046 -- 134087.  Next we
   * add the voltage offset provided by the 10V zener diode,
   * which is 9.87V or 987.  The final fixed point integer
   * value is converted to two decimal point fraction by
   * inserting a decimal point.
   */
  voltage = analogRead(ANL_VOLTAGE_PIN);
  voltage <<= 16; 
  voltage /= 134087;
  voltage += 987;
  sprintf(buf, "%5ld", voltage);
  buf[6] = 0; buf[5] = buf[4]; buf[4] = buf[3];
  buf[3] = '.';
  memcpy(voltage_message + 1, buf + 1, 5);

  frame_send((uint8_t *)voltage_message , VMSG_LENGTH);
}

Thanks everyone for the input, it makes a lot of sense I think I've implemented What was suggested in the updated code below. one thing I need verified is if I used the #define function properly. especially the negative value for tempOffset

Including a header file in the source code and including a library in the compiler/linker output are two different things.

The compiler will see the header file, and compile the corresponding source file, to create an object file. The linker will then pick stuff it needs, and only what it needs from the object file.

I think I understand this, including a library in the program doesn't add any more to the compiled than the functions used in the program so It cant hurt to include it. but so far I haven't used it and don't foresee needing it so I haven't included it.

wayneft mentioned the map function, it does look like a potentially simplfied approach; but at this point I think it's good for me to do it long hand as I need to learn the basic syntax; perhaps in the future I'll change it over once I better understand it.

Gardner said:

This would address part of your question, and maybe give you an idea how to deal with the rest, without using any floating point or math.

is there an advantage to avoiding floating point? does it use more memory than the method you mention??

Thanks again for all the input, the next step for me will be implementing a 4x4 matrix keypad for input of the schedule of the firing. so you'll likely see a message on the board to that effect

As for the remarks in the code I posted below I think it would make sense to whoever was reading it.

Another thing I' like to add to is the lcd.print (temp)
If I want to add something like Current Temp : (temp) degrees F
would it be that simple

lcd.print Current Temp : (temp) degrees F

also if I want to use the degree symbol where do I access that character? do I need to use it's ASCII value? that's where things get muddy for me.

Thanks in advance,

Carl

/*

Analog input from T/C amp displayed as value on LCD

*Varied 0-5Vdc to analog input 0

*LCD RS pin to digital pin 12
*LCD Enable pin to digital pin 11
*LCD D4 to digital pin 5
*LCD D5 to digital pin 4
*LCD D6 to digital pin 3
*LCD D7 to digital pin 2
*LCD R/W pin to GND
*LCD V0 Pin to 0-5V for contrast

*/

// include library code
#include <LiquidCrystal.h>

// initialize with the numbers of interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int sensorPin =A0; //select input pin for thermocouple amplifier
int sensorValue =0; //variable to store the value coming from the sensor
float temp =0; //variable to store calculated temp

#define const float constVolt 5.0/1024.0 //constant converting analog value 0-1023 to 0-5v; when multiplied by sensorValue becomes X in linear equation Y=mX+b
#define const float tempSlope 355.2823 //constant for slope(m) of linear equation Y=mX+b
#define const float tempOffset -16.7664 //constant for y intercept(b) of linear equation Y=mX+b
//temp = tempSlope * constVolt * sensorValue + tempOffset

void setup() {
//setup the LCD's number of columns and rows
lcd.begin(20, 4);
}

void loop() {
// read value from T/C:
sensorValue = analogRead(sensorPin);
// convert to degrees F
temp = (tempSlope)(constVolt)(sensorValue)+(tempOffset)
//set the cursor to column 0, line 1
lcd.setCursor(0,1);
// print temp value
lcd.print(temp);

If I want to add something like Current Temp : (temp) degrees F
would it be that simple

lcd.print Current Temp : (temp) degrees F

Not quite.

lcd.print("Current Temp: ");
lcd.print(temp);
lcd.print(" degrees F");

is there an advantage to avoiding floating point? does it use more memory than the method you mention?

There is no native support (i.e. not hardware dedicated to floating point processing) for floating point math, so it's slow.

if I don't need precision beyond one degree, but need to use the finer detail for the slope and offset, would it be easiest to use the a multiple of the constants and then as the last function divide

Temp(F) = ((35528 * Volts) - 1676)/100

Versus

Temp(F) = (355.2823 * Volts) - 16.7674

does that still need to be floating point if I need 2 decimal places resolution on the input voltage?

thanks in advance,

Carl

Floating point arithmetic is slow. But, if it is the only thing that the Arduino is doing, besides displaying the results on the screen, then, it doesn't matter that it is slow. So, you should use floating point arithmetic, because it is straightforward and easy to understand.

Whether or not the Arduino is doing anything else is unknown, since you didn't post all of your code.

The code you last posted has issues, though.

#define const float constVolt 5.0/1024.0 //constant converting analog value 0-1023 to 0-5v; when multiplied by sensorValue becomes X in linear equation Y=mX+b
#define const float tempSlope 355.2823 //constant for slope(m) of linear equation  Y=mX+b
#define const float tempOffset -16.7664 //constant for y intercept(b) of linear equation Y=mX+b
//temp = tempSlope * constVolt * sensorValue + tempOffset

The first word following the #define statement defines a key. The rest of the data on the line (up to any //) defines a value.

The pre-processor will look for the key anywhere else in the code, and substitute the value, before passing the code to the compiler.

So, you have defined three keys - const, const, and const. Hmmm. That's going to be a problem, don't you think.

Get rid of the #define part, and put an equal sign and semi-colon in the appropriate places in those lines.

const float constVolt = 5.0/1024.0;
const float tempSlope = 355.2823;
const float tempOffset = -16.7664;

thanks for clearing that up, as for the complete code, it's still very rough and incomplete. it will be reading the thermocouple and converting it to degrees F and displaying it on the LCD, but also will have an input function to program the rate of increase to set temperatures; via a keypad.

it will pretty much be a thermostat following a set pattern of steps of ramping at a certain rate of climb and holding for a certain amount of time at that temperature.

All the while it will display on the LCD the current temp and the temp it is ramping to. if things work out for that and I have extra room it's nice to be able to review the program, see how much longer it should take to reach the next temp or how much longer it is held at a certain temp. so far my code is very rough and I don't have much

I'm building it in steps, this is just a program to read the thermocouple and output to the lcd the temp

I get an error when I compile that constVolt cannot be used as a function, and also a bunch of references to java on lines that are not in the program

#include <math.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
#define thermocouplePIN0
const float constVolt = 5.0/1024.0; // Volts per analog digit
const float tempSlope = 355.2823; // slope of linear equation
const float tempOffset = -16.7664; // y int of linear equation
float volts = 0;
int temp = 0;


int thermocouplePin = 0;

void setup(){
  Serial.begin(9600);//hardware serial to PC
  lcd.begin(20,4); //sets up columns and rows
}

void loop()
{
 volts=constVolt(analogRead(thermocouplePin));           // read ADC and convert it to volts
 int temp=(tempSlope*volts)+tempOffset;                       // convert volts to temp in degrees F
 
 
lcd.print("Current Temp: "); //display temp
lcd.print(temp);
lcd.print(" degrees F");
delay (100);
}

this is the program for reading the keypad and displaying it on the LCD, it still needs tweaking on the hardware end, but it seems overall functional.

char keypressed = 0;
int keyboardPin = 0;    // Analog input pin that the keypad is attached to
int keyboardValue = 0;   // value read from the keyboard
int k = 0; //
int kbvalue = 0;//
int kbv = 0;
#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,5,4,3,2);

void setup(){
Serial.begin(9600);// hardware serial to PC
lcd.begin(16, 2); //sets up columns and rows
}

void loop()
{
  int sensorValue = analogRead(A0);
  Serial.println(sensorValue, DEC);
  delay(200);
  
  lcd.setCursor(0,1);
  keyboardValue = analogRead(keyboardPin);   // read the keyboard value (0 - 1023)
  while (keyboardValue < 25)
  {
    //do nothing until a key is pressed
    keyboardValue = analogRead(keyboardPin);
    delay(50);
  } //end of do nothing till a key is pressed
                                            
  int k = kbValue(keyboardValue);   // maps the value of the key being pressed "keypressed" i.e. 0-9
  
  Serial.println(k);  // print the value back to the Serial view window on your PC
  delay(1000);
}

// interpret the keyboard routine
int kbValue(int kbv)
{
  if (keyboardValue <=25)
 {
delay (30);}//debounces keypress; does nothing until a key is pressed
  else if ((keyboardValue >25) && (keyboardValue <=68)){keypressed = 1;}
  else if ((keyboardValue >68) && (keyboardValue <=108)){keypressed = 2;}
  else if ((keyboardValue >108) && (keyboardValue <=153)){keypressed = 3;}
  else if ((keyboardValue >153) && (keyboardValue <=179)){keypressed = 'enter';}// a key
  else if ((keyboardValue >179) && (keyboardValue <=225)){keypressed = 4;}
  else if ((keyboardValue >225) && (keyboardValue <=325)){keypressed = 5;}
  else if ((keyboardValue >325) && (keyboardValue <=415)){keypressed = 6;}
  else if ((keyboardValue >415) && (keyboardValue <=508)){keypressed = 'erase';} //b key
  else if ((keyboardValue >508) && (keyboardValue <=560)){keypressed = 7;}
  else if ((keyboardValue >560) && (keyboardValue <=680)){keypressed = 8;} 
  else if ((keyboardValue >680) && (keyboardValue <=773)){keypressed = 9;}
  else if ((keyboardValue >773) && (keyboardValue <=834)){keypressed = 'menu';} // c key
  else if ((keyboardValue >834) && (keyboardValue <=898)){keypressed = '.';} // menu key
  else if ((keyboardValue >898) && (keyboardValue <=945)){keypressed = 0;}
  else if ((keyboardValue >945) && (keyboardValue <=970)){keypressed = '-';} //enter key
  else if (keyboardValue >970){keypressed = '+';} //d key 

switch(keypressed){

case 0:
lcd.print(0);
delay(250);
// do 0
break;
  
case 1:
lcd.print(1);
delay(250);
// do 1
break;

case 2:
lcd.print(2);
delay(250);
// do 2
break;

case 3:
lcd.print(3);
delay(250);
// do 3
break;

case 4:
lcd.print(4);
delay(250);
//do 4
break;

case 5:
lcd.print(5);
delay(250);
// do 5
break;

case 6:
lcd.print(6);
delay(250);
// do 6
break;

case 7:
lcd.print(7);
delay(250);
// do 7
break;

case 8:
lcd.print(8);
delay(250);
// do 8
break;

case 9:
lcd.print(9);
delay(250);
// do 9
break;

case 'a':
lcd.print("a");
delay(250);
// do a
break;

case 'b':
lcd.print("b");
delay(250);
// do b
break;

case 'c':
lcd.print("c");
delay(250);
//do c
break;

case 'menu':
lcd.print("menu");
delay(250);
// do menu
break;

case 'enter':
lcd.print("enter");
delay(250);
// do enter
break;

case 'd':
lcd.print("d");
delay(250);
// do d
break;
}
 
while (keyboardValue >=25);          //wait until key no longer being pressed before continuing
  
return keypressed;
}

like I said it is very rough.

thanks for your patience,

Carl

you forgot the asterisk

volts=constVolt(analogRead*(thermocouplePin));

you forgot the asterisk

That's not where it goes...

volts=constVolt * analogRead(thermocouplePin);

This is where it goes...

thanks; brainfart