New project - Megamometer


 
No cooking this weekend...I added the LCD and a thermocouple amplifier over the last week. The thermocouple amplifier is needed to increase the resolution of the millivolt readings that are given off by the thermocouple. I am using a breakout board form Adafruit that was easy to solder and add the code to get it to work. Now I can report my firebox temps !

Megamometer_LCD2.jpg


I am still trying to figure out the best way to get my code to work with the LCD display, the log and the serial port. So far, I think I have spent the most time trying to figure out how to do the programming on this section of the project. As it turns out, the LCD uses ASCII characters, and sending it a "double" or "integer" type of number will not work. There are ways to get it done, and it involves use of "strings" and "buffers" as a way to interpret or convert the characters.

In the photo, the time was set using the USB cable at compile time, so when the device is powered off and on it starts where it left off - not the actual time.

Currently stuck steering the output of the hexprint reads for the timestamp chip to the logs and to the LCD. I have exactly what I want going to the serial port, but have not found the way to get the info into the buffers for the log, or off to the LCD <yet>...
 
Hi -

Sorry for opening this thread back up. Hopefully someone can point me correctly. I'm using the same temp probes as Gary (CDN AD-DTTC). I have an Arduino Uno and I'm using the source from his link http://www.arduino.cc/playgrou...onentLib/Thermistor2 (second example as well). I used the application to come up with my coefficients for A B and C.

page1.jpg


I'm using the following code:


#include <math.h>

#define ThermistorPIN 0 // Analog Pin 0

float vcc = 4.91; // only used for display purposes, if used
// set to the measured Vcc.
float pad = 10000; // balance/pad resistor value, set this to
// the measured resistance of your pad resistor
float thermr = 10000; // thermistor nominal resistance

float Thermistor(int RawADC) {
long Resistance;
float Temp; // Dual-Purpose variable to save space.

Resistance=((1024 * pad / RawADC) - pad);
Temp = log(Resistance); // Saving the Log(resistance) so not to calculate it 4 times later
Temp = 1 / (0.000546403 + (0.000195178 * Temp) + (0.000000234256 * Temp * Temp * Temp));
Temp = Temp - 457.87; // Convert Kelvin to Farenheit

// BEGIN- Remove these lines for the function not to display anything
Serial.print("ADC: ");
Serial.print(RawADC);
Serial.print("/1024"); // Print out RAW ADC Number
Serial.print(", vcc: ");
Serial.print(vcc,2);
Serial.print(", pad: ");
Serial.print(pad/1000,3);
Serial.print(" Kohms, Volts: ");
Serial.print(((RawADC*vcc)/1024.0),3);
Serial.print(", Resistance: ");
Serial.print(Resistance);
Serial.print(" ohms, ");
// END- Remove these lines for the function not to display anything

// Uncomment this line for the function to return Fahrenheit instead.
//temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert to Fahrenheit
return Temp; // Return the Temperature
}

void setup() {
Serial.begin(9600);
}

void loop() {
float temp;
temp=Thermistor(analogRead(ThermistorPIN)); // read ADC and convert it to Celsius
Serial.print("Farenheit: ");
Serial.print(temp,1); // display Farenheit
Serial.println("");
delay(5000); // Delay a bit...
}

And here is the serial debug info I get:

serialreading.jpg


The only thing correct is the ADC value of 976. When I compare that to the table generated by the coefficient app, it matches up exactly to the cozy 75 degrees Fahrenheit. Where is my calculation going wrong in the code?

table.jpg


Sorry for the long reply. I'm racking my brain over this, I should be able to figure it out. Thanks in advance.

Matt
 
Sorry - if it wasn't clear (I'm not use to this Forum yet), my ADC output value is correct (976/1024) as it's a nice 76 degrees in here, and that matches the table generated by the coefficient application. It's somewhere in my code, and I'm not exactly sure what all the different variables are referncing. My probe is half bridged with 10k Ohm resistor, and 5v on the arduino.
 
EDIT: After checking your link and the calculator app, the only thing I can think of is to check to make sure your resistor is on the low side of the thermistor and not like this
<pre class="ip-ubbcode-code-pre">
5V -> Thermistor -V- 10K Resistor -> GND
|
ADC
</pre>
Do you have a multimeter to be able to check the voltage at the ADC junction and the thermistor resistance when out of circuit?
 
5V -> 10 Resistor-V- Thermistor -> GND
|
ADC

It's setup with the resistor on the 5V side, not ground...

Thanks for catching the Fahrenheit calc issue... but I'm still no closer.

do I need to change the pad ohms variable to match the actual Thermistor resistance, or is that the resistor value in my bridge? Looks like this Thermistor is somewhere in the neighborhood of 220KOhm.

I think these two values are wrong in my code, but I'm not sure what to set them to...

float pad = 10000; // balance/pad resistor value, set this to
// the measured resistance of your pad resistor
float thermr = 10000; // thermistor nominal resistance

Thanks for your help,
Matt
 
Posted October 11, 2011 12:58 PM Hide Post
EDIT: After checking your link and the calculator app, the only thing I can think of is to check to make sure your resistor is on the low side of the thermistor and not like this

5V -> Thermistor -V- 10K Resistor -> GND
|
ADC


Do you have a multimeter to be able to check the voltage at the ADC junction and the thermistor resistance when out of circuit?


My ADC readings are accurate, at least they match when I manually compare the ADC reading to the actual temperature chart created by the calculator app. It's gotta be somewhere in the calculations or formula that I have.

Right now, it's showing an ADC value of 977. When I compare that to my chart, it's dead on temp. Then when I take my temperature (under the arm), the ADC value moves to 97 degrees (I'm surprised it's that accurate) based on my chart lookup. I have also noticed that as my ADC value decreases (as is the resistance) with temperature (from what I understand is normal for NTC Therms) my calculation is also decreasing the Celsius reading, (even though the calc is incorrect). I figured even if my formula was off, that the Celsius reading would get higher, not lower. So something has to be up with the way my formula reads, as well as the calc it's performing. I'm so close, but feel miles away!!
 
Here is the latest code I'm using. I'd really appreciate any help people can devote. Matt

One last rambling thought... my circuit IS not as the author writes in his code. See below...


<pre class="ip-ubbcode-code-pre">
Author shows this schematic:

5V -> Thermistor -V- 10K Resistor -> GND
|
ADC

Mine is:


5V -> 10 Resistor-V- Thermistor -> GND
|
ADC

This being backwards have any issue?

#include <math.h>

#define ThermistorPIN 0 // Analog Pin 0

float vcc = 4.91; // only used for display purposes, if used
// set to the measured Vcc.
float pad = 230000; // balance/pad resistor value, set this to
// the measured resistance of your pad resistor
float thermr = 230000; // thermistor nominal resistance

float Thermistor(int RawADC) {
long Resistance;
float Temp; // Dual-Purpose variable to save space.
float Temp2;

Resistance=((1024 * pad / RawADC) - pad);
Temp = log(Resistance); // Saving the Log(resistance) so not to calculate it 4 times later
Temp = 1 / (0.000546403 + (0.000195178 * Temp) + (0.000000234256 * Temp * Temp * Temp));
Temp2=Temp;
Temp = Temp - 273.15; // Convert Kelvin to Celsius

// BEGIN- Remove these lines for the function not to display anything
Serial.print("ADC: ");
Serial.print(RawADC);
Serial.print("/1024"); // Print out RAW ADC Number
Serial.print(", vcc: ");
Serial.print(vcc,2);
Serial.print(", pad: ");
Serial.print(pad/1000,3);
Serial.print(" Kohms, Volts: ");
Serial.print(((RawADC*vcc)/1024.0),3);
Serial.print(", Resistance: ");
Serial.print(Resistance);
Serial.print(" ohms, ");
Serial.print(", K: ");
Serial.print(Temp2);
// END- Remove these lines for the function not to display anything

// Uncomment this line for the function to return Fahrenheit instead.
//temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert to Fahrenheit
return Temp; // Return the Temperature
}

void setup() {
Serial.begin(9800);
}

void loop() {
float temp;
temp=Thermistor(analogRead(ThermistorPIN)); // read ADC and convert it to Celsius
Serial.print("Celsius: ");
Serial.print(temp,1); // display Celsius
//temp = (temp * 9.0)/ 5.0 + 32.0; // converts to Fahrenheit
//Serial.print(", Fahrenheit: ");
//Serial.print(temp,1); // display Fahrenheit
Serial.println("");
delay(5000); // Delay a bit...
}
</pre>
 
Originally posted by Matthew Fox:
Here is the latest code I'm using. I'd really appreciate any help people can devote. Matt

One last rambling thought... my circuit IS not as the author writes in his code. See below...


<pre class="ip-ubbcode-code-pre">
Author shows this schematic:

5V -> Thermistor -V- 10K Resistor -> GND
|
ADC

Mine is:


5V -> 10 Resistor-V- Thermistor -> GND
|
ADC
<snip>
</pre>

The equation in your code snippet is for a configuration that has the thermistor between the ADC reference voltage and the ADC input and with a fixed R to ground. For your configuration, thermistor grounded the equation should be something like:

Rt = Cadc * Rseries / (Cmax - Cadc)

where
<UL TYPE=SQUARE>
<LI>Rt = thermistor value
<LI>Cadc = the code read by the ADC
<LI>Cmax = the max ADC value, 1024 for a 10-bit
<LI>Rseries = "pad", the resistor in series with the thermistor.
[/list]
 
Thank you! You got me on the right direction. I started completely over with the formulas, and also found some other ways to do the calculation from other posts. Here is the working code for anyone else in the world that might ever want this lol.. Thanks for all who helped

<pre class="ip-ubbcode-code-pre">


int firstSensor = 5; // first analog sensor

void setup()
{
// start serial port at 9600 bps:
Serial.begin(9600);
}

void loop()
{
// read the analog input
float a5 = analogRead(5);
Serial.print("analogread = ");
Serial.print(a5);
Serial.print("\n");

// calculate voltage
float voltage = a5 / 1024 * 5.0;
Serial.print("voltage = ");
Serial.print(voltage);
Serial.print("\n");

// calculate resistance
float resistance = (10000 * voltage) / (5.0 - voltage);
Serial.print("resistance = ");
Serial.print(resistance);
Serial.print("\n");

// calcuate temperature. Use these values for A, B, and C till you
// get everything working, and then do some measurements to calibrate
// your thermistor in circuit.
float logcubed = log(resistance);
logcubed = logcubed * logcubed * logcubed;
float kelvin = 1.0 / (-7.5e-4 + 6.23e-4 * log(resistance) - 1.73e-6 * (logcubed));

// Convert to Fahrenheit
float f = (kelvin - 273.15) * 9.0/5.0 + 32.0;
Serial.print("temp = ");
Serial.print(f);
Serial.print("\n");

// delay 1s to let the ADC recover:
delay(1000);
} </pre>
 
I notice that the pad resistor value is important and can be adjusted to give you a coarse "offset"... I am using 220K resistors and a value of 220000 in my code. My room temps look close enough.

I want to be sure that temps are closest where it matters most to me - approaching the 180-200 degree mark.

I would say that the ABC numbers could be used for fine tuning the temps throughout the range... how close are your probes using the ABC defaults in your new code example ?

I moved my starting pin to be the highest numbered analog pin so I could make easier use of the physical pin layout on the Mega. In my code, I decrease the index to read the 8 probes then pop out and read the thermocouple().

I never thought about this too much, but is it a better or more robust design to have the meat probe on the ground side of the circuit ?
 
I'll test the temp range on my probe this weekend. Likewise I'm hoping for the better part of the accuracy to be on the high end (200 degree). It's right on accurate at room temp. I used an Aburins PID controller to do my calibration and come up with my ABC coefficient values. I have found the PID to be very accurate.

The fact that my resistor (btw I'm using 10kohm resistor) was on the positive side was pure accident. I'm not sure weather it really matters other than having your code set respectively.

You have a great design and thank you for sharing. Your post has been a tremendous help.

Now to figure out this Arduino Uno WIFI and pachube thing....
 
Ohh btw - those weren't my personal coefficients up above. For the CDN AD-DTTC probes, mine are:

<pre class="ip-ubbcode-code-pre">
const float a = 0.000546403; //Steinhart-Hart Equation
const float b = 0.000195178; //constants
const float c = 0.000000234256;
</pre>
 
Originally posted by Matthew Fox:
Thank you! You got me on the right direction. I started completely over with the formulas, and also found some other ways to do the calculation from other posts. Here is the working code for anyone else in the world that might ever want this lol.. Thanks for all who helped
Yeah that's why I asked about the orientation of the resistors, because it does make a difference. I played around with them in each orientation when I was doing my original designs, which is why the HeaterMeter code still has the optimized (smallest code space) formulas in it:
https://github.com/CapnBry/Hea...er/grillpid.cpp#L125

I put my probes on the low side (1) because it was 83 bytes smaller code and (2) because the braided maverick probes use the exposed braid as their second conductor. It seemed like a good idea to me to have those be attached directly to ground. I think Bob originally also mentioned something about grounding sleeve.
 
Shazzbot. I measured my probes and see the same thing - the braided sheath is just 1-2 ohms away from the circuit. With the device powered on, I measured 4.81v from the probe or sheath to ground.

With the probes at 4.8v, and all that bare stainless touching my metal shelves, I think I will be changing my wiring around to the low side.

Yeah that's why I asked about the orientation of the resistors, because it does make a difference. I played around with them in each orientation when I was doing my original designs, which is why the HeaterMeter code still has the optimized (smallest code space) formulas in it:
https://github.com/CapnBry/Hea...er/grillpid.cpp#L125

I started this project attempting to read your Heatermeter code, then reviewed Homebrew and Tempmon looking for something I could read "strait through" instead of "jumping all around". I have basic C skills and do not grasp the format of CPP yet.

I would say my code is starting to look like something now (spaghetti) - it is now at 650 lines, but it is made mostly from utility sketches for the specific hardware I am using but I plan to borrow more directly form this forum as I add in the PID and WiFi and graphing and display methods and...

It does compile clean and it logs everything but the formatted timestamp to the log. I have been hung up trying to get the time from my RTC chip written to the log file. I can print the timestamp to the LCD and the serial port from within the function, but cant seem to write to the log file from within that function.

That has prevented me from working on adding the PID loop and fan, but when I get the log sorted out I want to see how I could add some of your stuff from grillpid... just #include grillpid.h and call the functions I need ? Your stuff is in cpp format, not sure how to get there from here.

I want to show the logs cooking 8 turkeys at once. gotta get this thing done.
 
Ok, here is a snippet from within the timestamp read function... the code is reading hour, minute and seconds from registers on a DS1307 chip:

This is what the hexprint function looks like:
<pre class="ip-ubbcode-code-pre">
void hexPrint(uint8_t v)
{
Serial.print(v >> 4, HEX);
Serial.print(v & 0XF, HEX); </pre>
... and this is a section of the timestamp read function
<pre class="ip-ubbcode-code-pre"> // hour
hexPrint(r[2]);
Serial.print(':');

// minute
hexPrint(r[1]);
Serial.print(':');

// second
hexPrintln(r[0]);

lcd.setCursor(0, 1); //MM move cursor (position, line)
lcd << _HEX(r[5]) << '/' << _HEX(r[4]) << ' ' << _HEX(r[2]) << ':' << _HEX(r[1]) ; //MM new in v.4c print time to LCD at (position, line)

//Still need to get the timestamp to the log file, this don't work....
bout << _HEX(r[5]); << '/' << _HEX(r[4]) << ' ' << _HEX(r[2]) << ':' << _HEX(r[1]) ; //MM attempting to print timestamp to log file
</pre>

The bottom line is what I am trying to get to work. I can do concatenation and print to the LCD, but have not figured out how to get the time to the log file that uses a buffer. Apparently there is a type conversion problem. Do I need to make the timestamp into a string or something ?
 
Originally posted by Gary Graham:
The bottom line is what I am trying to get to work. I can do concatenation and print to the LCD, but have not figured out how to get the time to the log file that uses a buffer. Apparently there is a type conversion problem. Do I need to make the timestamp into a string or something ?
What type is "bout"? char bout[somenumber]? Yes you do need to convert the binary to printable characters, you can use something like this (assuming it is a character array):
snprintf(bout, sizeof(bout), "%x/%x %x:%x", r[5], r[4], r[2], r[1]);

If bout is not a character array and actually an IO stream, then your error might be that there's an extra semicolon in your statement:
<pre class="ip-ubbcode-code-pre">
bout << _HEX(r[5]); <--
</pre>
That might just be a typo when you posted it though.
 
Thanks Brian, bout appears to be short for buffer out. It is code that works in another sketch, but I am having trouble calling it from my sketch.

you were right about the typo - I had shortened that line and commented out the remainder and did not remove the; when I posted.

I tried the snprintf statement and got this in the compiler:
Megamometer_04c:512: error: invalid conversion from 'const void*' to 'char*'
Megamometer_04c:512: error: initializing argument 1 of 'int snprintf(char*, size_t, const char*, ...)'

Would it be better to have the timestamp routine return a string to the loop for display/logging ? I notice that the LCD print does not add a padding 0 when characters are less than 2 digits, but the serial print add the padding zero.

I will post a link to my project code so if anyone wants to take a look in context everything will be there.
 
Here is a link to the Megamometer code, which is still a work in progress.

///////////////////////
// Megamometer v0.4c //
///////////////////////
/*
A multi channel, data logging thermistor probe reader for making and recording several temperature measurements over extended time periods. This is a collection of other sketches that meet the basic needs for measuring and recording temperatures from 8 thermistor food probes and one thermocouple for higher temps, like the firebox.

The sketch starts when power is applied, and a line with a timestamp and temperature data for each probe is written to a .csv file on the SD card at an interval you can specify in milliseconds. This project will eventually have PID controller capabilities for closed loop control of the cooker one day...

Software used in this sketch:
sketch 1 Reads thermistor probes Thermistor on the Arduino forum at http://arduino.cc/playground/ComponentLib/Thermistor2
sketch 2 Writes timestamp and temp to SD card: Analoglogger2 in the SDfat library
sketch 3 MAX6675 Thermocouple LCDThermocouple from http://www.ladyada.net/learn/s...rs/thermocouple.html
sketch 4 DFRobot LCD display with buttons LCD4Bit_mod from the LCD4Bit library to enable use of a 1602 (16 character x 2 lines) LCD
sketch 5 from softD1307 timestamp is a function taken from the return date and time using SoftI2cMaster

Hardware used:
Arduino Mega 2560 main board see http://www.adafruit.com/products/191 for example
Adafruit Data Logger Shield from http://www.adafruit.com/products/243
Adafruit thermocouple amplifier from http://www.adafruit.com/products
DFRobot LCD keypad shield see http://dfrobot.com/
Assorted jumper wires
(8) 220k ohm thermistor food probes I used CDN AD-DTTC2010 from cheftools.com
(8) 220K ohm resistors 1/4 watt color code is red|red|yellow|gold
(8) 2.5mm jacks
9v battery and connector wire with power jack will give about 3:15 of operating time monitoring and logging 8 probes.
For overnight cooks, I suggest using a 9v AC/DC adapter.

Tip on software/hardware compatibility with the Mega:
1) If the SD card will not initialize or can not be found, look for the SDfatlib package and the MegaSoftSPI.txt file.

2) This tip eliminates 4 extra wires, and allows the use of the Adafruit data logger shield without modification of the pinout for the (4) SPI bus pins.
From MegaSoftSPI.txt:
Features have been added to support an unmodified Adafruit GPS Shield or Datalogging Shield on an Arduino Mega.
Define MEGA_SOFT_SPI to be non-zero in SdFatConfig.h to use software SPI on Mega Arduinos. Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
Defining MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used on Mega Arduinos.
Software SPI works well with GPS Shield V1.1 but many SD cards will fail with GPS Shield V1.0.

3) Having an issue with my hardware where the DS1307 Real Time Clock will work only if the i2C bus is under software control.
See http://forums.adafruit.com/vie...796&p=119674#p119674

Where you see comments with the MM notation these were added for the MegaMometer project so you can see where I am commenting.

Note: I have downloaded additonal libraries to support the hardware for this project. If you do not have these libraries installed, you will probably see these messages (and related errors) in the compiler:
Megamometer_04c.cpp:82:19: error: SdFat.h: No such file or directory
Megamometer_04c.cpp:83:53: error: SdFatUtil.h: No such file or directory
Megamometer_04c.cpp:85:50: error: SoftI2cMaster.h: No such file or directory
Megamometer_04c.cpp:86:50: error: TwiMaster.h: No such file or directory
Megamometer_04c.cpp:87:56: error: max6675.h: No such file or directory
Megamometer_04c.cpp:90:117: error: Streaming.h: No such file or directory

Here is the code for the Megamometer Arduino project. (right click and "save as...")
 
Originally posted by Gary Graham:
Thanks Brian, bout appears to be short for buffer out. It is code that works in another sketch, but I am having trouble calling it from my sketch.
Ah yes because it was local to the other method it is defined in. I see in the source you shared that you've also tried defining it in displayTime() as well. I'd suggest replacing the LCD and logging code with one formatted kajigger that writes right to your buffer instead of the intermediate stream. I assume the classes have overloads for accepting a char * to <<.
<pre class="ip-ubbcode-code-pre">
snprintf(buf, sizeof(buf), "%02x/%02x %02x:%02x", r[5], r[4], r[2], r[1]);
lcd << buf
logfile << buf
</pre>
As far as whether to return a string, I'd say probably not. You might want to have it just load the value into a global variable which is a structure like
<pre class="ip-ubbcode-code-pre">
struct __date_time {
unsigned char secs, mins, hours, days, months;
} CurrentTime;
</pre>
Then you've got the flexibility to format it however you want (for example like the LCD doesn't want seconds but the log file does).
 
Thanks ! This is great!! the log, serial and LCD are all working.

Now for the "One step forward, two steps back".

I figured that I would mess with the hardware and software at the same time and multiply my sorrows by changing a pin header on the thermocouple amp board so I can mount it in the case better, I re-wired the thermistor polarity and also started making the updates in the thermistor code. So much for change management, eh ?

So the thermocouple is not logging, and I am checking my work on the hardware. The thermistors are reading the wrong direction, but everything else is looking good.

I am starting to transpose the thermistor function that I have been using, while at the same time considering a switch to try and use some sections of the HM code. I looked at this when I first started my project and could not figure out how to "unplug" all the correct stuff from the various .h and .cpp files to get it into a new .pde file.

The rest of my project is making it more like Heatermeter or Homebrew or Tempmon to do the control and graphing and wifi with the additional probes...

What is the best way to pick and choose the related classes, functions and declarations and other code sections from all the files that I would need to use the TempProbe class stuff ?
 

 

Back
Top