RTD / PT100 1000 measurement: Library for MCP 3551 22bit ADC.

Update 2021:
The old library is now here:

So far I did not check if it is still running with a recent arduino ide. Feel free to give me feedback.

thanks for sharing!

maybe one or two sample sketches?

I'm gonna do that whenever my RTD measurement circuit is complete.

Hey Guys,

the library with example is now online and works with every PT100...PT1000. You'll need a MCP3551 AD and only two 0.1% resistors with 6.8k. All about 3 Euro!!!

For more information you can read AN1154 from MCP.

deleted by k4ktus

1 Like

Hi,
I successfully setup a PT100 -MCP3551 with the help of your sketch and digrams. Thanks a lot. But I am facing some problems. Please help me..

  1. My LCD is not working when I use your sketch. I pinpointed that this is happening once the MCP3551.h is inserted in the program. If I remove the same LCD is working but what the use without MCP3551.h :frowning:
  2. Can you explain how you find out the values in
    float temperature = (RTD * (255.8723 + RTD * (9.6 + RTD * 0.878)));
  3. Can you explain the calibration procedure a little... When I click on the push button after replacing the PT100 with a 100R resistor, the temperature is showing zero. But after restarting arduino, the value is changing to older one. I noted a -5 degree C difference in the actual and theoretical reading. I want to correct this and save this value permanently. Any ideas for that??
    Please find my sketch below..
#include <LiquidCrystal.h>
#include <MCP3551.h>
#include <SPI.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int pushButton = 7;
const int MCPPin = 10;
float calRAdevice1 = 13340;
float RTD;
const int RZero = 100;
MCP3551 myRTD(MCPPin);
void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);  
  lcd.setCursor(0, 0);                                           
  lcd.print("MCP3551& PT100");   
  delay (1000);
  pinMode(pushButton, INPUT);
}
void loop() {  
  int buttonState = digitalRead(pushButton);
  bool rtdReady = myRTD.getCode();
  if(rtdReady)
  { // Serial.println(getRTD1.byteCode);    
    //calculate RTD acc. MCP AN1154:
    RTD = calRAdevice1 * (float(myRTD.byteCode) / ( 2097152.0 - float(myRTD.byteCode)));    
    //This is part of a calculation for T(RTD)
    RTD = (RTD / RZero) - 1;
    float temperature = (RTD * (255.8723 + RTD * (9.6 + RTD * 0.878)));    
    Serial.println("Temperature: "); 
    Serial.println(temperature);
    Serial.println("code "); 
    Serial.println((float(myRTD.byteCode)));
    Serial.println("RTD "); 
    Serial.println(RTD);    
    lcd.setCursor(0, 0);                                          
    lcd.print("TEMPERATURE ");                                   
    lcd.setCursor(0, 1);                                          
    lcd.print(temperature);
    delay (1000);
    // A simple method for calibration at 0°C with iced water:
    if (buttonState){
      char n=0;
      float temp=0;
      do 
      {
        if (myRTD.getCode());
        {
          temp+= float(myRTD.byteCode);
          n++;
        } 			
      }
      while (n<10); 
      temp /= 10;	
      calRAdevice1 = RZero;
      calRAdevice1 /= ( temp /( 2097152.0 - temp)); 
      delay(2000);
      Serial.print("Ra: "); 
      Serial.println(calRAdevice1);
    }
  }
}

I think you must assign other pins to the LCD, 11 and 12 are SPI pins. see - SPI - Arduino Reference -

Hi robtillaart,
I connected MCP3551 to ICSP MISO and SCK. In this case I need to change pin 11 and 12 as well? Because in the SPI table i have seen for Uno MOSI - 11 or ICSP-4 MISO -12 or ICSP-1 SCK -13 or ICSP-3 SS (slave) - 10.
I think I can't connect LCD 11 and 12 to any other pins. Infact I tried it... So there is no chance that I can't connect MCP3551 and LCD togother? :frowning:

arduinofankerala:
Hi robtillaart,
I connected MCP3551 to ICSP MISO and SCK. In this case I need to change pin 11 and 12 as well? Because in the SPI table i have seen for Uno MOSI - 11 or ICSP-4 MISO -12 or ICSP-1 SCK -13 or ICSP-3 SS (slave) - 10.

Yes you need to change pin 11 and 12 .

I think I can't connect LCD 11 and 12 to any other pins. Infact I tried it... So there is no chance that I can't connect MCP3551 and LCD togother? :frowning:

Why can't you connect the LCD

LiquidCrystal lcd(9, 8, 5, 4, 3, 2);

??

Oh! Thank you. There was some connection problem earlier and it worked fine on pins 8 and 9.

Hi there,

I'd like to try your code and principle of measurement. Could you provide a schematic on how to setup the MCP3551, the two resistors and the PT100? That would be great.
Thanks for your efforts.

Greetings,
J.

Everything you want is there in the first post.

Hi there,

how did you manage to set the reference voltage (VREF) to 2V? Wouldn't that effect any other analog reading on the Arduino? Did you use a separate LDO? If so, which, and what Capacitors did you choose?

Thanks again,
J.

I used an LM7805(common 5v regulator) as vref and worked fine. But it's better to use an LM2940( capacitors as per datasheet).

Hi there,

but you massively loose resoution when using a 5V reference. Thats why in AN1154 a 2V regulator is used. I just thought that maybe the Vref from the Arduino was used to implement the suggested design. Anyhow, I'm trying to fetch a 2V regulator as one should be enough for a 2 Channel application.
But Im curious, did you measure the accuracy of your setup?

Greetings,
Jan

Past one week my setup under test and I got .1C accuracy. I used a 10 k pot as RA and adjusted the temperature by putting pt100 in ice. Also cross checked with another thermometer and it was perfect. Vref don't have any relation with arduino. You habe to give any external reference voltage to MCP3551( I suppose!)

Hi everybody,
Past one month I was testing the MCP3551-PT100 with a UNO and was very successful except very rarely reading shows -247 and ovf. But it happened very rare and for my application, it was okay. But two days back I switched from UNO to ATMEGA 2560 due to the need of extra pins and UNO stopped receiving sketch(some problem). When the time of connection, display shows correct room temperaure for 5-10 seconds then it went to -247 and ovf one after other. Then it didn't shown correct temperature till now. I checked all the connections and everything is OK(infact i changed only the MISO, SCK and SS connections related to MCP3551). I checked byteCode in serial and have seen that it is alternating between 0 and 2097151-2097140). Output showing '-247.14' and "ovf". Cant figure out whats happening..
somebody please help. Please find my sketch below..

#include <LiquidCrystal.h>
#include <MCP3551.h>
#include <SPI.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int pushButton = 8;
const int MCPPin = 53;
float calRAdevice1 = 13340;
float RTD;
const int RZero = 100;
MCP3551 myRTD(MCPPin);
double temperature;
void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);  
  lcd.setCursor(0, 0);                                           
  lcd.print("ADC& PT100");   
  delay (1000);
  pinMode(pushButton, INPUT);
}
void loop() {
  temperature = digitalLowPass(temperature, myRTD.getCode() ,0.90);   
  int buttonState = digitalRead(pushButton);
  bool rtdReady = myRTD.getCode();
  if(rtdReady)
  { // Serial.println(getRTD1.byteCode);    
    //calculate RTD acc. MCP AN1154:
    RTD = calRAdevice1 * (float(myRTD.byteCode) / ( 2097152.0 - float(myRTD.byteCode)));    
    //This is part of a calculation for T(RTD)
    RTD = (RTD / RZero) - 1;
    float temperature = (RTD * (255.8723 + RTD * (9.6 + RTD * 0.878)));    
    lcd.setCursor(0,1);
    lcd.print(temperature);
    Serial.println(temperature);
    Serial.println(myRTD.byteCode);
    delay (500);
  }
}  
double digitalLowPass(double last_smoothed, double new_value, double filterVal)
{
  double smoothed = (new_value * (1 - filterVal)) + (last_smoothed * filterVal);
  return smoothed;
}

ovf stands for OVERFLOW, so the value exceeds the limits of print.cpp A fix to be able to print the whole value exists here - Proposed update for the printFloat code of print.cpp - Libraries - Arduino Forum -

Can you give the source of the math?

I checked byteCode in serial and have seen that it is alternating between 0 and 2097151-2097140).

2097152.0 has so many digits the float precision might be corrupted: 2097152.0 - 2097151 ==> might be 0 ==> causing a divide by zero

can you change these lines to check?

...
  if (rtdReady)
  { 
    // calculate RTD acc. MCP AN1154:
    float divider = 2097152.0 - float(myRTD.byteCode;
    Serial.print("divider: ");
    Serial.println(divider, 4);
    
    RTD = calRAdevice1 * float(myRTDbyteCode) / divider;    
...

jabami:
Hi there,

how did you manage to set the reference voltage (VREF) to 2V? Wouldn't that effect any other analog reading on the Arduino? Did you use a separate LDO? If so, which, and what Capacitors did you choose?

Thanks again,
J.

Equation 3 and Equation 4 show that due to the ratiometric relation, VREF and RB cancel. They do not
influence the code to RTD-resistance conversion.

from AN.

So the only thing to look for would be the current flowing through the RTD.

@rest

To be serious I have not tested that example very well. The focus was laying on the communication and the bytecode processing of the libary.
Also I'm not sure how the 16 bit operations are handled on the 8 bit AVR. So there is a good change for whatever reason to have a division by zero.

RTD = calRAdevice1 * (float(myRTD.byteCode) / ( 2097152.0 - float(myRTD.byteCode)));

this is now also strange to me :smiley:
The only thing I can remember right now was that direct multiplication between calRAdevice and byteCode will always result in an overflow.

Also I'm not sure how the 16 bit operations are handled on the 8 bit AVR. So there is a good change for whatever reason to have a division by zero.

it is not 16 bit problem, it is a float (32bit IEEE754) problem.

The only thing I can remember right now was that direct multiplication between calRAdevice and byteCode will always result in an overflow.

what are typical values for bytecode?