I bought a pressure transmitter off of ebay that outputs a 4-20 mA current signal, because I like to live it up. The 4-20 mA current is very common in industrial control systems, so it's relatively easy to find various transmitters with this output. However, an Arduino can't natively read a current signal with its analog input pins - they measure voltage. We need to convert this current signal to a voltage. Fortunately, this is a piece of cake to do with a simple circuit.
Precious peppy pressure |
The transmitter I bought is a Setra 209 model (datasheet here). It takes a 9-30V input, and acts as a current controller to put out a 4 to 20 milliamp signal proportional to the pressure it senses, with a span of zero to 100 psig. Plotting it out:
We can use a simple resistor circuit to generate a voltage readable to the Arduino that is proportional to the current. The Arduino AnalogRead function gives a 0-1023 value output proportional to the measured voltage on the analog input pin, with 0 corresponding to 0V or Ground (duh) and 1023 corresponding to the reference voltage (5V for the plain jane Arduino if nothing's connected to the Aref pin).
The standard Arduino's analog input pins can read zero to 5 volts. If 5 volts is our maximum signal at 20 milliamps, that requires a resistance of 250 ohms:
R = V/I
R = 5 V/ 0.02 A = 250 ohms
If this were instead a 3.3V microcontroller, we'd require a 165 ohm resistor to read the full range output by the same math. Whichever reference voltage, you can use a lower resistor, but it cuts down the readable span.
We can now convert the measured voltage back to whatever units our signal is in. To do this, we just need a little algebra! We can plot an x-y chart, where the x-axis is the measured current/voltage/AnalogRead output and the y-axis is the process variable (pressure in this case).
I live my life by the principles of slope intercept form |
Usually, a precision resistor is used for the reference resistor, with a low temperature coefficient (change in resistance with temperature), but for my purposes, an ordinary resistor suffices. I had a nominally 220 ohm resistor I measured as 217 ohms actual resistance, and a 33 ohm resistor that measured true, which combined in series gave 250 ohms. We don't need exactly the correct resistance, though - we can compensate in code. Here's everything breadboarded up - not much to it:
The transmitter worked like a champ, with the measured signal tracking the manual gauge I had connected to it as I varied the pressure.
One other nice feature of the 4-20 mA signal scheme is that the low end of the signal output is 4 milliamps, not zero. This makes it easy to detect errors, as happened on the above data logging run when I bumped the wire around 10,000 milliseconds in. The raw reading went to zero, when it should have bottomed out at about 200 if it were a real zero signal. This tells me that something is up with the wiring at this point, and the data can't be trusted. If I wrote a program to use this transmitter reading as an input, I would know to handle any zero signal readings as an error, not as a true data point.
Here's the code:
Here's the code:
float PressureReading;
float ResistorValue = 250; //reference resistor resistance
float Pmax = 100; //Max of process variable range
float Pmin = 0; //Min of process variable range
float Vref = 5; //Reference voltage for AnalogRead
void setup() {
Serial.begin(9600);
Serial.println("Time, Raw reading, Corrected reading");
}
void loop() {
Serial.print(millis());
Serial.print(",");
//Read the voltage across the reference resistor
PressureReading = analogRead(A3);
Serial.print(PressureReading);
Serial.print(",");
//Convert the voltage signal to a pressure reading
PressureReading =(Pmax-Pmin)*Vref/(1023*ResistorValue*(0.02-0.004))*(PressureReading-1023*0.004*ResistorValue/Vref);
Serial.println(PressureReading);
delay(500);
}