Author Topic: LM335 with Arduino  (Read 3871 times)

0 Members and 1 Guest are viewing this topic.

Offline skillz21Topic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: au
LM335 with Arduino
« on: September 15, 2017, 10:09:58 am »
I found this code online on how to use an LM335 with Arduino. In the code, there is a part where you have to enter in the voltage of the 5v rail of the Arduino. Unfortunately, this changes when other loads are connected (Like a HC-05... I have some questions on that, later). is there a way to change the code, so that the voltage is measured by the Arduino constantly so that the calibration voltage changes each time the voltage changes?

Code:

class LM335
{
  float cal;
  int pin;
  public:
  LM335(float mCal, int mPin);
  float measureV();
  float measureK();
  float measureC();
  float measureF();
  float measureRankine();
};

LM335::LM335(float mCal, int mPin)
{
  cal = mCal;
  pin = mPin;
}
float LM335::measureV()
{
  float retVal = (float) analogRead(pin);
  retVal = (retVal*cal)/1024.0;
  return retVal;
}
float LM335::measureK()
{
  return measureV()/0.01;//10mV/k
}
float LM335::measureC()
{
  return (measureV()/0.01)-273.15;
}
float LM335::measureF()
{
  return (((measureV()/0.01)-273.15)*1.8)+32;
}
float LM335::measureRankine()
{
  return measureF() + 458.67;
}

LM335 mTemp(4.98, 0);//supply volts, analog pin

void setup()
{
  Serial.begin(9600);
}
void loop()
{
  /*Serial.print(mTemp.measureV());
  Serial.println(" volts");
  Serial.println("Temperatures: ");
  Serial.print("Kelvin: ");
  Serial.println(mTemp.measureK());
  Serial.print("Fahrenheit: ");
  Serial.println(mTemp.measureF());
  Serial.println("Celsius: ");*/
  Serial.print(mTemp.measureC());
  /*Serial.print("Rankine: ");
  Serial.println(mTemp.measureRankine());*/
  delay(10);
}
 

Offline skillz21Topic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: au
Re: LM335 with Arduino
« Reply #1 on: September 15, 2017, 10:50:34 am »
For the Bluetooth part, I'm trying to make an app, with MIT AI2. Does anyone know how to trigger an action from an inbound message from a Bluetooth module?
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: LM335 with Arduino
« Reply #2 on: September 15, 2017, 11:00:40 am »
A/D, the problem with Atmel is no onchip absolute reference. So for accuracy
one has to

1) Add a known reference and measure it as part of the T measurement process.

2) Add a known reference and use it to power the Arduino rail.

3) Use a T sensor that has its own internal reference and outputs its result over SPI or I2C or One Wire.


Regards, Dana.
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline Monkeh

  • Super Contributor
  • ***
  • Posts: 7992
  • Country: gb
Re: LM335 with Arduino
« Reply #3 on: September 15, 2017, 11:03:55 am »
A/D, the problem with Atmel is no onchip absolute reference.

Err.. they do have one.

https://www.arduino.cc/en/Reference/AnalogReference
 

Offline skillz21Topic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: au
Re: LM335 with Arduino
« Reply #4 on: September 15, 2017, 12:16:43 pm »
A/D, the problem with Atmel is no onchip absolute reference.

Err.. they do have one.

https://www.arduino.cc/en/Reference/AnalogReference
That's what I was thinking, could I use that?
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: LM335 with Arduino
« Reply #5 on: September 15, 2017, 01:56:25 pm »
My error, thanks for catching that.

Note, I looked at 2560 reference, its kind of sloppy -

1V Ref ranges from  1V to 1.2V, thats not even 4 bits absolute accurate,
even though A/D is capable of 10 bits.

So the prior comments about solutions still apply if you want > 4 bits absolute
accuracy. Do an end to end error budget to see what total error will be.

Using external Vref -

http://tronixstuff.com/2013/12/12/arduino-tutorials-chapter-22-aref-pin/

If you desire much higher onchip accuracy PSOC has an onboard ref
good for +/- 1% for low end, PSOC 4, +/- .1% for PSOC 5LP.


Regards, Dana.
« Last Edit: September 15, 2017, 02:10:58 pm by danadak »
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: LM335 with Arduino
« Reply #6 on: September 15, 2017, 03:52:48 pm »
Quote
1V Ref ranges from  1V to 1.2V, thats not even 4 bits absolute accurate,
even though A/D is capable of 10 bits.

 Range variation is that much from chip to chip but is more likely 10X better for variation on any specific chip. The actual chip band-gap voltage can be measured and compensated in firmware.

Arduino ADC is useful and can be adequate for many applications, however it is not a instrumentation quality ADC. I use TI I2C ADC ( adafruit https://www.adafruit.com/product/1085 ) when a project requires decent accuracy with built-in reference. Asian clones of this are very inexpensive.


 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2254
  • Country: ca
Re: LM335 with Arduino
« Reply #7 on: September 15, 2017, 04:17:56 pm »
You can't simply use the Arduino's internal 1.1 V reference because doing so limits the ADC range to 0 to 1.1 V full scale. The LM335 output is around 3 V at room temperature (300 Kelvin at 0.01 V/Kelvin). You could work around this by scaling the LM335 output with a voltage divider. (Note this will also increase the impedance at the ADC input, so you'll need to add a capacitor from input to ground to help). To calibrate the system, you would need to measure your reference voltage by measuring the AREF pin. You'll also need to adjust for you voltage divider by either scaling that voltage up accordingly, or by modifying the calculations in the code.

Alternatively, you can use an external reference connected to the VREF pin. A plain old TL431, with appropriate voltage setting resistors, can be set to an arbitrary value. Around 4 V should work well.
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: LM335 with Arduino
« Reply #8 on: September 15, 2017, 04:34:17 pm »
There is a way of using internal ref with high precision, approach mainly for
high volume production.

Basically during production test a cal routine is activated in DUT, it sends
a request to an external high accuracy/precision DC generator, and that
request, a specific V, is then supplied to the A/D input. The A/D value then
read and stored. After a sweep is done a least squares curve fit to the data
is performed (or a power series curve). The equation is then used in normal
mode each time the A/D returns a value to correct its deviation. This can be
done over T as well.


Regards, Dana.

Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline Monkeh

  • Super Contributor
  • ***
  • Posts: 7992
  • Country: gb
Re: LM335 with Arduino
« Reply #9 on: September 15, 2017, 05:22:51 pm »
Never said it had a good reference, just that it had one.. ;)
 

Offline Boschi

  • Regular Contributor
  • *
  • Posts: 85
  • Country: it
  • just a arduino-guy
Re: LM335 with Arduino
« Reply #10 on: September 15, 2017, 07:19:44 pm »
Well, its stable enough over the temperature range, and the way that dana propose is the best one, but if you only want to know the temperature whitout very good precision its possible to use the internal themperature sensor of the atmega.

You just set the Vref to 1.1 volt, tweak the analog input multiplexer register to read the internal sensor and do a analog read.

Inviato dal mio A0001 utilizzando Tapatalk

 

Offline HB9EVI

  • Frequent Contributor
  • **
  • Posts: 722
  • Country: ch
Re: LM335 with Arduino
« Reply #11 on: September 15, 2017, 09:17:06 pm »
I'm not using the Atmel internal references; what they thought about the 1.1V reference in certain uC, likely only god knows.
In general I prefer binary-wise convenient references like 2.048V or 4.096V; for less accurate needs I go for the MCP1541, what would likely be my choice also in combination with the LM335. For higher accuracy I choose an ADR420 or a REF3040
 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: LM335 with Arduino
« Reply #12 on: September 15, 2017, 10:57:42 pm »
Well, its stable enough over the temperature range, and the way that dana propose is the best one, but if you only want to know the temperature whitout very good precision its possible to use the internal themperature sensor of the atmega.

You just set the Vref to 1.1 volt, tweak the analog input multiplexer register to read the internal sensor and do a analog read.

Inviato dal mio A0001 utilizzando Tapatalk

 The problem is that the internal die temp is more an indication of current draw on output pins that would dominate over any indication of ambient temp.

 

Offline skillz21Topic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: au
Re: LM335 with Arduino
« Reply #13 on: September 15, 2017, 11:57:53 pm »
Woah.... that's a lot of replies. Anyway, I don't really understand what you guys mean, can't I just input the 5v back into, say A1, and then read that, then set the voltage value in the code, to that? Also, can't I just input 5v into the AREF pin?
 

Offline skillz21Topic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: au
Re: LM335 with Arduino
« Reply #14 on: September 16, 2017, 12:00:18 am »
Also, do you know anything about the app side of things? MIT App inventor?
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: LM335 with Arduino
« Reply #15 on: September 16, 2017, 12:25:51 am »
Start with basics -

1) What is your accuracy goal for T measurements ?

2) How often do you want to measure the T, SPS ?

3) What is the max worst case range of T you will want to measure ?


Regards, Dana.
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3024
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: LM335 with Arduino
« Reply #16 on: September 16, 2017, 01:30:59 am »
It is possible to read the Vcc by an AVR itself, you do this by reading the internal reference relative to Vcc, since you "know" the internal reference, and you don't know Vcc, but you do know that a full Vcc read will give you a certain result of the ADC, it's easy to "solve for Vcc".

However as noted the internal reference isn't that accurate, indeed it can be really inaccurate.  However, it is pretty stable, so what you do, is calibrate it first.  You do your "read the Vcc" code, get the result that it calcualted, then you actually measure your Vcc (with a multimeter) and then you can calculate what the internal reference actually is (or, just a scaling factor) and adjust that in your code (or eeprom or however you want to store it).  Once you have calibrated that once you are good-enough.

Here is some code for doing that, readVcc() on an ATMega328 (Arduino Uno, Pro-Mini, Nano), but the theory is the same for other AVR, just the registers might be different.  This was ripped out of one of my programs, I think it should be stand-alone though.  You can see that when I calibrated the internal "1.1v" reference on whatever I was putting this code onto, I found it was 1.081 (and some change), so quite far out, but it is relatively stable at that.

Code: [Select]

/** Read the AVR's own VCC.
 * 
 *  Note that the internalReference must be calibrated
 *  perform a reading, and get the result, measure the actual Vcc
 * 
 *  if the actual Vcc is lower, the internalReference needs to decrease
 *    internalReference = internalReference * ( readVcc / realVcc )
 *   
 *  if the actual Vcc is higher, the internalReference needs to increase
 *    internalReference = internalReference * ( realVcc / readVcc )
 *   
 * 
 */

float readVcc(uint8_t force)
{
  uint32_t result = 0;
  const uint8_t  analogDiscard = 1;
  const uint8_t  analogSamples = 5;
  const float    internalReference = 1.081187434;
 
  static float    lastReading = 0;
  static uint32_t lastRefVoltageUpdate = 0;
  if(!force && (lastReading != 0 && (millis() - lastRefVoltageUpdate) < 10000))
  {
    return lastReading;
  }
 
  lastRefVoltageUpdate = millis();

  // Connect the internal 1.1v to the ADC MUX
  // (leave the Analog Reference as Vcc_
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle

  // Discard some results to get better accuracy
  for(uint8_t dummy = 0; dummy < analogDiscard; dummy++)
  {
    ADCSRA |= _BV(ADSC); // Convert
    while (bit_is_set(ADCSRA,ADSC));
  }

  uint32_t resultSum = 0;
  // Average some conversions
  for(uint8_t dummy = 0; dummy < analogSamples; dummy++)
  {
    ADCSRA |= _BV(ADSC); // Convert
    while (bit_is_set(ADCSRA,ADSC));
    result = ADCL;
    result |= ADCH<<8;
   
    resultSum += result;
  }
 
  // Read the ADC result
  // result = ADCL;
  // result |= ADCH<<8;
  result = resultSum / analogSamples;

  // We know we measured 1.1v   
  // So the result 0 to 1023 is a proportion of Vcc
 
  // 1.1 = (Result / 1023) * Vcc
  // 1.1 = Vcc * (Result / 1023)
  // 1.1 / (Result / 1023) = Vcc
 
  lastReading = (internalReference / ( (float)result / 1023.0 ));

  return lastReading; 
}




1023 vs 1024

Additional because somebody might point it out in my code...

I use "1023" for ADC operations, others use "1024", there are valid arguments for and against either.

In short, we need to remember that an ADC result doesn't represent a specific voltage, it's a voltage range (of course since we have a discrete number of steps), assuming a 5v reference for sake of demonstration, it's roughly a 5mv range for each ADC result.

So we get 1024 boxes numbered 0 - 1023, box 0 (ADC result 0) contains any readings 0v to approx 5mv, box 1023 contains any readings approx 4.995v to 5v.

Dividing the reference by 1024 (number of boxes) you always wind up calculating to the lower value, 0 = 0v, and 1023 = 4.996v, that's totally fine and correct, provided you remember that it's actually "0-0.005mv" and "4.996-5v".

If you divide by 1023 (maximum box number), you will calculate the lower value of the range at the bottom (0 = 0v) and the upper value of the range at the top (1023 = 5v)

Both approaches have merit but I prefer 1023.

You are not really introducing any error that isn't already there, just moving it from always being a negative error of up to 5mv, to being an error that can vary +/-2.5mv (indeed, see this google sheet I made comparing 1023 to 1024 )

Of course 5mv is probably in the noise anyway on pretty much any sort of Arduino design, so this is all pretty academic.
« Last Edit: September 16, 2017, 01:37:30 am by sleemanj »
~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: LM335 with Arduino
« Reply #17 on: September 16, 2017, 12:30:26 pm »
You can get a Vref part for 50 cents or less, +/- .1%.

Take the easy way out. Or use a UP like PSOC that has onchip
ref.



Regards, Dana.
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline skillz21Topic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: au
Re: LM335 with Arduino
« Reply #18 on: September 17, 2017, 03:02:35 am »
Quick question, I added a potentiometer so I could manually change the calibration voltage of the LM335. But when i copy the part where i have to enter the VCC into the code, into the loop (from before the setup), it stops working, how do i change the code so that i can continually adjust the calibration voltage? also, is it possible to use the potentiometer and change the voltage range to 4v to 6v, intead of 0v to 6v as i have it now?
Thanks



#include <LiquidCrystal_I2C.h>

const int inPin = A0;
float inPinout1;
float inPinout2;
const int buzz = A1;
int sensorPin = A3;
float sensorValue = 0;
LiquidCrystal_I2C lcd(0x27, 16, 2);



class LM335
{
  float cal;
  int pin;
  public:
  LM335(float mCal, int mPin);
  float measureV();
  float measureK();
  float measureC();
  float measureF();
  float measureRankine();
};

LM335::LM335(float mCal, int mPin)
{
  cal = mCal;
  pin = mPin;
}
float LM335::measureV()
{
  float retVal = (float) analogRead(pin);
  retVal = (retVal*cal)/1024.0;
  return retVal;
}
float LM335::measureK()
{
  return measureV()/0.01;//10mV/k
}
float LM335::measureC()
{
  return (measureV()/0.01)-273.15;
}
float LM335::measureF()
{
  return (((measureV()/0.01)-273.15)*1.8)+32;
}
float LM335::measureRankine()
{
  return measureF() + 458.67;
}

LM335 mTemp(4.99, 2);//supply volts, analog pin




void setup() {
  pinMode(inPin, INPUT);
  pinMode(buzz, OUTPUT);
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
}

void loop() {
  {
    LM335 mTemp(sensorPin, 2);//supply volts, analog pin

   
    sensorValue = analogRead(sensorPin) / 170.5;
  inPinout1 = analogRead(inPin)/ 200.588;
  inPinout2 = inPinout1 / 200.588;
  Serial.println(inPinout1);
  lcd.setCursor(0, 0);
  lcd.print(analogRead(inPin)/200.588);
  lcd.setCursor(5, 0);
  lcd.print("Volts");
  lcd.setCursor(0, 1);
  lcd.print(mTemp.measureC());

    lcd.setCursor(8, 1);
  lcd.print(sensorValue);
 
delay(50);
}
{
if(inPinout1 == 1.37){
digitalWrite(buzz, HIGH);
delay(1);
digitalWrite(buzz, LOW);
delay(1);

 
}}
}
« Last Edit: September 17, 2017, 03:50:18 am by skillz21 »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf