Go Down

### Topic: Monitoring voltage from a power supply (Read 2188 times)previous topic - next topic

##### Feb 15, 2009, 05:14 pm
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!!??

#### Collin80

#1
##### Feb 15, 2009, 06:10 pmLast Edit: Feb 15, 2009, 06:11 pm by AdderD Reason: 1
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.

#2
##### Feb 15, 2009, 09:27 pm
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:
Code: [Select]
`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?

I'm getting closer...

#### Collin80

#3
##### Feb 15, 2009, 09:37 pm
Cool, that is a start!

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:

Code: [Select]
`int Vin = 0;int val = 0;#define VDIVIDE 2.8fvoid 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.

#4
##### Feb 15, 2009, 09:54 pm
Hmm ok, now help me pick this code apart so I understand it lol.

Quote
#define VDIVIDE 2.8f

What does this accomplish? I don't understand the "f"

Quote
float result;

What does it mean to float something?

Quote
result = val / (1023.0f / 5.0f) * VDIVIDE;

Again, the "f" is throwing me off!!??

#### Collin80

#5
##### Feb 15, 2009, 09:56 pm
In C an f at the end of a number indicates that it's a float. It just assures that C will assign the numeric literal the correct type.

A float is a floating point #. In other words, it can have a fractional component.

#### jerrya.net

#6
##### Feb 16, 2009, 02:43 am
Could this be a use for the map() function to make this conversion easy to read?

map(value, fromLow, fromHigh, toLow, toHigh)

http://arduino.cc/en/Reference/Map

So for this 5v test case you could say something like

voltage = map(analogRead(Vin), 0, 1023, 0, 5);

#### Collin80

#7
##### Feb 16, 2009, 02:51 am
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.

#### jerrya.net

#8
##### Feb 16, 2009, 02:59 am
Ah, right there on the page I linked to, it says it returns a long. Not sure how I missed that.  :-/

Naturally, you will need to calibrate the input regardless of the math used.

#### Collin80

#9
##### Feb 16, 2009, 03:11 am
Yeah, using map is still an excellent idea.

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.

Go Up

Please enter a valid email to subscribe