I’m still very much in the prototyping and design phase of this project – trying out component circuits with a hodge-podge of jumper wires and breakout boards to ultimately create a working prototype.
An analog to digital converter (A2D) takes an analog signal within a specific voltage range and estimates the numerical value that best represents that signal. Because the Resistance-Temperature-Device (RTD) used in this project changes resistance as temperature changes, we need a way to accurately and reliably measure the subtle changes in resistance that will occur. I’m aiming for an accuracy of 0.1°C or better for this project which translates to a change of only 0.0379Ω per 0.1°C. So here’s the rationale: if we pass a fixed current across the RTD, then the voltage will always be proportional to the resistance according to Ohm’s law. If we can find a suitably sensitive device to measure the small changes in voltage, we have a way to measure the PT100 resistance and thus estimate the temperature. Moreover, the RTD is only expected to have ~80Ω worth of change in the temperature range that Silvia will be operating. At the low currents that we’ll be using on the RTD, we’re looking at only 120mV of voltage change. That’s a fraction of the total 0V-5V range that normal A2Ds use as a reference (including the A2D on the Arduino Pro Mini). So, we need a way to scale up that 120mV to something that’s easier to quantify. Most people would turn to an Op Amp based circuit. This type of device effectively feeds back on itself to scale an analog signal in amplitude. However, this requires a bit of external circuitry and can be subject to electrical noise if the circuit isn’t clean.
Enter the ADS1247 – an all-in-one device that: has 24 bits of resolution (21 effective bits, or 2.1 x 106 possible values), generates a fixed current on its analog pins, and can scale input voltages using a Programmable Gate Array (PGA) (similar to an op-amp circuit). This chip can communicate with the Arduino via 3 pins dedicated to the SPI communication bus.
I will eventually publish the full schematic, however the basic design for a circuit incorporating the ADS1247 chip is simple and follows a similar design to the TI published example (see Example 7). Effectively I will use a low tolerance 140Ω (0.05% tolerance) resistor as RREF to centre the 80Ω resistance swing at the half-way point (~140Ω at 100°C) and a 750Ω (0.05% tolerance) resistor as RBIAS to create a reference voltage (±2.25V). I’ll set the analog input pins to output a fixed 1500μA current and the PGA to multiply the ±60mV voltage developed across the analog input pins by 32 to ±1.92V (and well within the ±2.25V reference range). With this setup, I expect to obtain a maximum resolution of ~8.4 x 10-9 V per bit. Fantastic!
While this design is fine in theory, I wanted to try it in practice. More importantly, I wanted to see if I could even get it working smoothly with the Arduino. So I wired up a prototype circuit based on TI Example 7 using a couple of resistors as RREF and RBIAS, as well as a trim-pot to simulate the RTD. The only other component required was a 10μF capacitor between VREFCOM and VREFOUT to stabilize the internal voltage reference.
I coded up the Arduino as follows:
unsigned long A2DVal=0x0;
SPI.setClockDivider(SPI_CLOCK_DIV16); //1MHz Bus Speed
delay(2000); //Give you time to open up the Serial monitor as it will restart the Arduino but not ADS1247
SPI.begin(); //Turn on the SPI Bus
SPI.transfer(0x06); //Reset the ADS1247
delay(2); //Minimum 0.6ms required for Reset to finish.
SPI.transfer(0x16); //Issue SDATAC
SPI.transfer(0x40); //Set MUX0 Register (00h) Write 01h
SPI.transfer(0x42); //Set MUX1 Register (02h) Write 38h - Select internal reference always on, internal ref connected to REF0 pins. Use 33h if wanting an on chip temp read.
SPI.transfer(0x43); //Set SYS0 Register (03h) Write 52h - PGA:32, Sample at 20sps
SPI.transfer(0x4A); //Set IDAC0 Register (0Ah) Write 07h - Select 1.5mA reference current for RTD
SPI.transfer(0x4B); //Set IDAC1 Register (0Bh) Write 01h - Output reference current on ANIN0,1
//Reset A2D Storage Value
A2DVal = 0x0;
SPI.transfer(0x12); //Issue RDATA
A2DVal |= SPI.transfer(0xFF); //Write NOP, Read First Byte and Mask to A2DVal
A2DVal <<= 8; //Left Bit-Shift A2DVal by 8 bits
A2DVal |= SPI.transfer(0xFF); //Write NOP, Read Second Byte and Mask to A2DVal
A2DVal <<= 8;
A2DVal |= SPI.transfer(0xFF); //Write NOP, Read Third Byte and Mask to A2DVal
//SPI.transfer(0x22); //Read Register 0x2
//SPI.transfer(0x00); //N - 1 Bytes To Be Read
//A2DVal |= SPI.transfer(0xFF); //Mask to A2DVal
The ADS1247 also has an onboard temperature sensor that can be read instead of the analog inputs by writing to MUX1 register with 33h. When doing this, the value returned by the Arduino was 0764XXh where XX (the least significant byte) fluctuated. I could push this up to 0771XXh when I blew on it with my breath or touched the chip with my finger! I also tried out the actual analog inputs (MUX1 should be set to 38h) and was able to get the value to change according to the trim pot.
It’s now just a matter of sourcing some low tolerance resistors for the final circuit – let me know if anyone knows of any vendors!
More to come soon.