I'm fairly new to the Arduino platform. I want to monitor voltage from a 13.8v power supply that I just repaired to keep an eye on it while I'm away.
To do this, I have an Arduino Diecimila board that I want to use on a linux box in conjunction with cron and a shell script to check it say once an hour.
I'm just not sure where to begin. My first hurdle is getting voltage into the board to make it readable, I was thinking of using the analog in pins, but can they handle 13.8v?
So here's what I want to do in a nutshell:
Feed 13.8v in from the power supply to the Arduino
Take the value that is read and make it human readable (like 13.84 volts or something)
Write a script to run in cron that will pull the data (via USB) from the Arduino board on demand
Parse the results out to a file for further processing
I'm thinking on the Arduino side of things I can run code in a loop consistently and then when the script goes to pull the data over USB it will give me whatever reading is picked up at that time?
Just trying to wrap my head around this.... I can handle the linux side of it, but not so sure with the Arduino. Where to begin!!??
The analog pins can take only 5V (well... 5.5V but you should shoot for 5V max). So, you need a voltage divider circuit to step the incoming 13.8V down to 5. For ease of calculation lets say the input is a max of 14V and you want to step that down to 5V. 14/5 = 2.8 so you need a 2.8 to 1 step down. 1K and 2K is close enough. Then 2/3 of the voltage bleeds to ground and one third goes to the arduino pin. If you are worried about too much amperage getting through then use bigger resistors. So long as one is twice the size of the other. You could probably get away with 10k and 5.1K.
The analog in values can range from 0 - 1023. But 1023 is the value when the input matches the voltage of the arduino reference voltage. That should normally be 5V. The easiest thing to do is to create the voltage divider and then hook up a known voltage (test with a multimeter). See what value you get out of the arduino. Maybe do that a time or two more with a couple of other voltages in range. Find out how many values per incoming volt you get and use that as a linear reference. For instance, if you have 13V incoming and you used a perfect third divider then the voltage at the arduino pin would be four and a third volts. The reading would be 886 approximately. 886 / 13 = 68 values per original volt. Use that to figure out how many volts the original input was. If the reading is 680 then the original voltage was 10v. The arduino could then sent a human readable text string over it's Serial->USB connection.
Ok I've been playing with this all afternoon and I was able to get a value of 1023 with 5v on Analog pin 0 and ground, cool!
I used the following code:
int Vin = 0;
int val = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
val = analogRead(Vin);
Serial.println(val);
delay(1000);
}
As expected, I get 1023 every second with 5v supplied to pin 0. The next challenge is how to take this number and make it into a human readable voltage value? I know now that 1023 = 5v, so how would I convert that or a lower number?
Now, like I said, the relationship should be linear. If you get a value of 1023 for 5V then you'd get a value of 512 for 2.5V. It's a direct correlation. The only complication comes in with the fact that you needed a voltage divider to get the 13.8V to the arduino. Every measurement has to be scaled accordingly.
It might look something like this:
int Vin = 0;
int val = 0;
#define VDIVIDE 2.8f
void setup() {
Serial.begin(9600);
}
void loop() {
float result;
val = analogRead(Vin);
result = val / (1023.0f / 5.0f) * VDIVIDE;
Serial.println(result);
delay(1000);
}
You would need the 013 version of arduino because I don't think the println command supported floats before then. This all could be scaled and then integer math could be used. In this example VDIVIDE is the amount that the voltage was stepped down by the voltage divider. You would need to calibrate it via the procedure I outlined in my last post.
Unfortunately map is integer only. It still could be possible to use. The new map function would have to be something like this:
voltage = map(analogRead(Vin), 0, 1023, 0, 1400)
That would be: Map the analog value to a voltage 0 to 14 and shifted two places over. This is a fixed point calculation. At the end you shift the decimal back to places and you get the value to a hundredth of a voltage. Of course, you can't actually get a real hundredth of a volt precision. It would be possible to change it to tenth of a volt precision too:
voltage = map(analogRead(Vin), 0, 1023, 0, 140)
Also: There is no guarentee that 1023 would correspond to 14V. It still has to be calibrated as I've said before. One still has to input a known voltage and find the proper calibration from there.
Let's say that you want to use map. You input a regulated 12 volts. You test with a multimeter and sure enough it's 12V exactly. So you hook it up to the voltage divider and hook the voltage divider up to the arduino. Then you output what readings you are getting. Let's say that you let it run for 5 seconds and there is one reading a second. The readings are:
923
921
923
922
922
So you average them up and get pretty close to 922. Since you now know both the exact input voltage and the averaged reading you can plug them into map:
voltage = map(analogRead(Vin), 0, 922, 0, 1200)
This gives you a hundredths of a volt reading that is calibrated to the hardware at hand.