Help to Convert Voltage Divider Data to A2D Conversion Factor - Page 1
Forum section: electronics / projects

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 07:02:57 pm
content: I am trying to figure out how to program a 10-bit MCU A2D converter in C-language to read battery voltage(approx 14V), but I need just a little guidance on how to develop an equation to best accurately display the battery voltage from my data.I have no problem getting the A2D result in counts nor displaying the result in decimal on my display, justneed help trying to get get an idea on how to develop an equation.Attached is a simple voltage divider schematic that I am using to measure the battery voltage and uses an npn-output optoisolator to switch on the measurement when the battery voltage is to be sampled.I have measured the resistors, the voltage drops of the optoisolator, the measured voltages etc, and the attached shows the readings I get on my Fluke DVM.I notice the voltage drop across the optoisolator varies non-linearly a bit and I want to correct for that.Buthow do I solve this seemingly simple voltage divider coding problem to get a conversion count multiplier so the voltage in counts is to be most accurately converted to decimal volts?(I know I can just do many reprogramming attempts with guesses to zero-in on the required multiplier, but what is the science in that!)

author: nctnico
author_rank: Super Contributor
timestamp: January 15, 2017, 07:37:09 pm
content: Determine the full range in the resolution you want. In your case the maximum range could be 14 Volt = 14000 milli-Volt. Multiply the ADC reading with the full range (14000 in this case) and divide by the ADC range. For example: 3.5V in => reading=256 => 256*14000=3584000 => 3584000/1024=3500 (milli-Volt). You'll need to use 32 bit integers for the calculations to work.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 07:42:33 pm
content: Which MCU AD converter are you using?Whats the maximum battery voltage range of your source?That NPN optocoupler has a nasty unpredictable drop, can't you use something else? Do you need recommendations?14v fed into your current resistor divider will blow your ADC input, exceeding the 5v.My strategy usually involves selecting the appropriate resistor dividers which makes that AD results be a perfect multiple of you voltage reading.Example, with a 0 to 20.47v range, into an 10 bit ADC with a 5v v+ reference, I would use a 30.1k on the high side, and a 9.76k (hope I got my math right, there will be a full scale error of +0.05v right at 20.42v) connected to the ground. So long as the input of your ADC is cmos with super low input current, your ADC readout will equal 0.02v for each count.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 07:44:40 pm
content: Thanks nctnico, butthe idea here is to figure out how to calculate the required constant valuebut just to work with the measured test voltages and resistances.I don't know the A2D count value because the chip is not programmed yet.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 07:51:05 pm
content: BrianHG, what you suggest will certainly work and thanks for the help, but I don't want to have trimmers and hard to find precision resistors, just want to use some common values of the 1% resistors I have in my 1100-piece SMD resistor kit.I have chosen a voltage divider that is approx 3/1 ratio and that means that the A2D will be able to measure 14.2V near the top of the 10-bit range.I do know that I will display the voltage in millivolts so 14V =14000 and the displayed value will realistically rounded to the accuracy of approx < four digits displayed.I do know that the battery voltage will vary from a discharged voltage to a fully charged max of < approx 14V.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 08:04:50 pm
content: Quote from: martys on January 15, 2017, 07:51:05 pmI would select the following, 30.1k 1% on the high, 9.76k 1% on the low, these are standard 1% values. Your voltage range will be from 0 to 20.47v. Each reading on the ADC will equal 0.02v. There will be a full scale error of +0.05v right at 20.42v. This assumes the source voltage reff is 5v. Some ADCs have an internal voltage reference which may be more accurate and you could choose better matched 1% resistors.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 08:13:22 pm
content: Thanks again, BrianHG, but I don't have those very precise values and I don't want to add series/parallel trimmers. what I should say is that I bought an assortment of 1% metal-film SMD resistors in a kit but almost all have values exactly or within 1% of standard 5% standard values.These values should be sufficient to make any measurement if the MCU is best used to crunch the counts into an accurate output display.That being said, I want to have a general formula to convert the A2D count value I will get from the A2D result to voltage displayed in decimal.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 08:18:06 pm
content: For the ADC input pin:voltage_of_pin = (adc_val/1023*vRef);

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 08:22:04 pm
content: Sooo, for your circuit:voltage_at_top_of_res_network = (adc_val/1023*vRef) * ((R_hi + R_low) / R_low);I still recommend changing that optocoupler for something else. If you have an 20v capable open-drain output on your CPU, I would recommend a P-Channel mosfet. It will get rid of that unpredictable voltage drop, though if the battery drops below 3v, the readout would distort. A fet optocoupler might do better.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 08:24:02 pm
content: Thanks again , BrianHG, but I don't have nor expect to have the adc_value before programming the chip..and I already know the voltage at the A2D pin and at the top of the divider by measurements with the test setup data I present.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 08:31:31 pm
content: Ok, so I understand,#define vRef 4.9800#define Rtop 9.9800#define Rbot 5.1000float decimal_voltage;decimal_voltage = (adc_val/1023*vRef) * ((Rtop + Rbot) / Rbot);Is not your problem, It's how to convert the float 'decimal_voltage', which is the decimal voltage, into a decimal for display?

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 08:41:54 pm
content: Thanks again, BrianHG, but I want to calculate rather than guesstimate the conversion factor used to multiply the A2D counts to the correct decimal mV value to be displayed..so I don't initially know the count, just have the data shown from my Fluke measurements.Even though the NPN output optocoupler Ron has some small non-linearity and some temperature/current slope to its Ron values, these parts are in-expensive, easily acquired, provide complete isolation and almost zero-battery drain when turned off.There should be no problem for a MCU to use some math to correct for these small opto Ron errors.BTW, just to kindly remind you that your #define statements seem to exaggerate/ignore the number of significant digits of real-world accuracy, especially with the parts and measurements involved (10-bit accuracy is is an ideal that is not easily achievable) and then it is necessary to realize the accuracy/limitations of the measurements I've made so 32-bit calculations might be a bit too Fluke 87V-ish.)The idea is Best Measurements I Can Make --->C-Code before any initial programming of MCU.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 08:51:43 pm
content: Quote from: martys on January 15, 2017, 08:41:54 pmWithout knowing the plot of that slope, I cannot recommend anything further than my last code.Is the error linear, or, logarithmic?How does changing the LED current in the optocoupler affect this offset?If it is an unnatural curve, you might need to use a corrective lookup table.A 1024 byte table, using the ADC value as a lookup, to add the offset error to your voltage readout would be the maximum flexible result.Have you tried using 10x valued resistors. The mv offset error in the optocoupler may become insignificant with a 100k and 50k, or any value near these would work since you have the formula in my last code.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 08:58:18 pm
content: Quote from: martys on January 15, 2017, 08:41:54 pmMy example is a guide. Yes, the float is overkill. You may modify thing as you like, for example:Code:#define vRef 4.98#define Rtop 9.98#define Rbot 5.10int mv;mv = ((float)((adc_val/1023*vRef) * ((Rtop + Rbot) / Rbot) * 1000));The compiler will still handle the internal math in floats, but the output will be a 16bit integer in mv.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 09:04:02 pm
content: Thanks yet again BrianHG, but the Ron error of the opto-coupler is not the subject of my post, and is something trivial for me to manage with code using data that I've measured to get the MCU to correct/compensate.What I don't have is a way to convert from my data to a getting acounts to displayed decimal conversion constantbefore programming the chip..

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 09:17:06 pm
content: BrianMG, thanks for the input, but consider this re your suggestion to use high-valued resistors and 10/1 dividers.The A2D unbuffered input does not have an infinite input impedance and any voltage divider is significantly loaded by the A2D input impedance.An A2D unbuffered input is more subject to noise pickup and such errors are proportional to the equiv. input resistance of the voltage divider attached relative to the A2D input impedance.It is undesirable to use a higher voltage divider ratio than needed because the A2D resolution of the voltage to be measured is divided by the divider ratio..the higher the v-divider ratio the higher the resolution error.Example: 5V into a 10-bit A2D achieves approx a 4.882818mV/count resolution but using 10V and a 2/1 divider means that the voltage at the input of the A2D varies at 2 x 4.882818mv/count referenced to the actual voltage input, so resolution/accuracy is if effectively halved, and of course, there is also the > +/- half to one digit count uncertainty and non-linearity bit count errors to be added.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 09:24:56 pm
content: You mean something like this:Code:#define vRef 4.98#define Rtop 9.98#define Rbot 5.10int decivolts;unsigned char buf; //temp ascii stringdecivolts = ((float)((adc_val/1023*vRef) * ((Rtop + Rbot) / Rbot) * 10));buf = ftoa(decivolts/10); // This converts a float to ascii. I did the x10, divide by 10 so you only get 1 decimal place instead of 10+ decimals...buf will now contain an ascii, number by number representation of 'decivolts/10'.You can search and display character by character remembering that the final char will be a 0.If you want always 4 digits, a trick would be to:Code:buf = ftoa(decivolts+1000);Print out characters 2,3, manually insert a dp, then 4 to always give you a fixed # of characters every time.Subtracting 48 from each character allows you to also render a 7 segment display at the same time.Is this what you wanted?

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 09:28:53 pm
content: Thanks again BriganHG, especially for the display rounding hints, but no.I don't know the adc_val initially.All I have is an unprogrammed chip and I need a formula from the data measured.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 09:30:48 pm
content: Quote from: martys on January 15, 2017, 09:17:06 pmWhich is why I asked which ADC MCU you are using. Some are buffered, some arent. For the CMOS input buffered ones, I would have just also recommended adding a cap from Vin to GND. You are measuring a battery after all, you fast do you need to sample.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 09:44:05 pm
content: BrianHg, thanks again, I am using one of the PIC 18F25Kxx series MCU with unbuffered A2D inputs.Adding a simple R-C filter lowers noise but does subtract the divider error unless the sampling time is much greater than the RC time-constant of this input filter by at least 5x. The trade offs are: adding noise cancelling, does not compensate for the increased voltage-divider error that imits resolution and of course, the cost of adding more parts which increases complexity, increases PCB size, decreases reliability and is compromising the compactness of the finished PCB and product.But I still have not an answer to my post.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 09:58:53 pm
content: Quote from: martys on January 15, 2017, 09:28:53 pmI don't understand,#define vRef 4.98 <<< Data you measured in volts.#define Rtop 9.98 <<< Data you measured in kohm.#define Rbot 5.10 <<< Data you measured in kohm.#define Approx_voltage_drop_across_optocoupler 0.11 <<< Data you provided in between the 2 battery voltages.VOLTAGE = (( (the actual adc_val sampler register) /1023*vRef) * (Rtop + Rbot) / Rbot)) + Approx_voltage_drop_across_optocoupler(you cant predict this one unless)Are you are asking me what the "adc_val" will be? Regardless of your circuit, it should be a fixed number when you feed 1.529v to the ADC pin? Doesn't the ADC data sheet tell you?You listed the optocoupler as a resistor, it is not a resistor, it is a transistor output. Without the current curve and initial voltage drop, I wouldn't go any further than this small correction. If you were using a FET output optocoupler, the output behaves exactly like a resistor & I would measure it's impedance with your Ohm meter and add that value to the Rtop returning you a perfect voltage equation.Correcting for that transistor optocoupler will require a table of your circuit being run from 0v through 15v, measuring the drop all along the way, plotting that voltage drop into a table. Then, using that table to correct you voltage reading. 2 points are not enough as there is an unusual curve to the optocoupler's voltage drop at lower currents. The transistor is not acting like a resistor, it's acting like a constant current source with a leakage value.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 10:11:28 pm
content: Thanks again BrianHG, but the voltage drop across the opto-coupler is not the subject of my posted question.In fact, by measurement, the voltage drop across the opto-coupler is fairly constant and changes only by approx 32mv from 5V input to 17.3 volts input and stays in value fairly close to the higher reading within the the readings of interest (Battery V approx range of 10-14V), and so the error is is very easy to compensate for using only a very few data points and I can interpolate an accurate correction considering this error to closely obey a curve that is both monotonic and a scaler over the voltage range of interest.But this not the subject of my post.However I do now see that what what I simply didn't quite understand at first for some reason: I can calculate the A2D count required in your formula after now realizing that 1024 counts= Vref =4.98V which would yield a mV/count factor and then by simply dividing this value into the displayed measured voltage in decimal I can use this value to multiply A2D result counts to get the answer to my post!What I really wanted was a simple explanation using conversion factor ratio multiplications to achieve the answer.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 10:22:32 pm
content: Ok, then my formula is fine.Just use it.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 10:49:12 pm
content: Quote from: martys on January 15, 2017, 10:11:28 pmYup, all you had to do if you wanted the mv / adc count was in the place of 'adc_value', just put a1. If your adc_val is 1, you get the voltage of a 1 count in volts coming out of my equation, ignoring the optocoupler offset since that is a fixed addition. Putting in by 1024, then dividing by 1024 is also equal to 1.

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 11:09:30 pm
content: I have a background in physical chemistry and a plucking knowledge of electrical engineering, but I was taught and quickly realized the use of conversion factors, but somehow I couldn't get the ratios to line up.I can understand that using a J-FET could be the answer to turning on sampling, but the input/output are not isolated and there is possible errors due to charge injection if very fast sampling is neededTheinterface to drive the J-FETs would be much more complicatedand and input voltage range would be much more limited than with a optocoupler or HV optocoupler.Despite some correctable and small offset errors, many of them can be ganged to turn on with only one logic level bit and so allow many sensors to be measured to be simultaneously presented to all A2D inputs at the same time.Then, the desired selected A2D multiplexed input would yield the result.What about if this is a battery operated instrument that must eliminate current drain when in a "sleep" state. Wouldn't the J-FET drivers consume current when not being used?Wouldn't high voltages require a high-voltage bias supply or other IC interface to turn on/off the required expensive HV J-FETs?

author: Mr.B
author_rank: Unknown
timestamp: January 15, 2017, 11:10:39 pm
content: Slight side question:What is the optocoupler for?If it is to save power drain from the battery when not measuring then I would eliminate the complication of the opto altogether and use higher resistance values.10 meg on the top and 5.49 meg on the bottom. (both are standard 1% values)14v full scale results in 4.96v for the ADC.Current consumption = ~ 9e-7 A (almost nothing)Edit: 0.9 microamps

author: martys
author_rank: Regular Contributor
timestamp: January 15, 2017, 11:29:49 pm
content: Yes, Mr. B, the idea here is a battery-powered instrument that will have almost zero-power usage when in a "sleep" mode and occasionally wakes up to check the battery voltage or other conditions.As I mention in the post, high-resistance voltage dividers create a large error that is not constant nor easily defined over the A2D voltage input range and also may vary from one part to another of even from from one input on a device to another input pin.When high resistance dividers are used with buffers then the use of buffer increases cost, may not allow for almost zero "sleep" power consumption. This increases complexity, cost, component size and reduces battery use life and time between needing recharge. High valued resistors may need more PCB area to reduce leakages and noise pickup at the A2D input will increase also introducing error.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2017, 11:56:31 pm
content: You could try this mosfet optocoupler in DC configuration:http://www.digikey.com/product-detail/en/ixys-integrated-circuits-division/LCA110/CLA101-ND/203107Feeding the LED with 200ma gives you a <10 ohm resistor. Though is costs more than a transistor optocoupler.A P-mosfet like this:http://www.digikey.com/product-detail/en/vishay-siliconix/SI2377EDS-T1-GE3/SI2377EDS-T1-GE3CT-ND/2441907would have an on resistance of 0.1 Ohm, and it requires an additional 2N3904 transistor + 3 resistors, but, if your battery drops below 1.2v, it's reading would quickly drop down to 0v at around between the 1.2v and 0.8v. Below 0.8v, it would read as 0v. A battery voltage above 1.2v would give you a proper readout.This solution would cost about the same as a transistor out optocoupler, draws 0 current when turned off.Costs less if your PIC has an open-drain output pin which can support 20v or more, you wouldn't need the 2n3904 transistor and less 1 resistor.Also, with the ridiculously low on resistance, it will be fairly immune to aging and temperature change & the PIC IO will only need to drive under 1ma since you are not driving an LED.

author: martys
author_rank: Regular Contributor
timestamp: January 16, 2017, 12:25:39 am
content: BrianHG, Thanks again for giving me insight into other ways to accomplish my project.But Holy Cow! 200ma is completely out of the question for this battery-use optimized piece of equipment. The interface and the JFET intself is much more complicated and costly.I am turning on the optocouplers(I am using "817" type) using only a few-mSec of 3.3mA strobed current per opto and then only for the settling time of the A2D input andI am turning on (interfacing) multiple optocouplers at once using only one valuable pin on the MCU.The on-resistance of these optocoupler is not of any significance as it can be reasonably modeled as being low and fairly constant over temperature and the voltage drop and it has shown to have a consistent temperature coefficient from unit to unit.My PICC MCU, like most other MCU's I've noticed commonly available seem to lack a driving pin that can handle more than the MCU Vdd, but the 25-mA source/sink drive current of most PICC MCU's port pins is very convenient to drive multiple Optos.