Part I: The voltage divider.

Because eight bit mircocontrollers lack floating point instructions using floating point can consume a lot of processor cycles.

In this article I will illustrate how to measure up to 100VDC with an analog to digital converter, ADC, with a positive voltage reference of 5V, +Vref, and a negative voltage reference at gnd -Vref.

The input to the the ADC must never exceed the 5V value of +Vref. We can use a simple voltage divider to accomplish this. To specify the resistors in out divider need to find the divider ratio.

dividerRatio = VmaxInput/VmaxOutput

100V/5V = 20

Note that our result 20 is a pure number and this is how we use it.

View attachment voltageDivider.png

Resistor must be R1=19xR2.

Scaled Voltage = Original Voltage (R2/(R1+R2)

If we pick R2 to be 1 we need an R2 of 19 to get a ratio of 20.

sv = ov (1R/(1R+19R)

sv = ov (1/20)

Which is exactly what we want but for the fact that this bit of circuit will waste more current then we would like.

I = V/R = 100V/20R = 5A

and

P = I**2(R) = 5*5*20 = 500 watts !

Looks like we need to reduce that current with more resistance. We can multiply R1 and R2 by any number as long as we do it to both. The 20:1 ratio will remain the same. Lets multiply both resistors by 1000 for a R1 of 1K and R2 of 19K. You may have to use 2 resistors in series to get 19K. Lets calculate the current for our new circuit.

I = V/R = 100V/20000R = .005A or 5mA

and

P = I**2(R) = .005*.005*2000 = .05 watts

At this point we have a circuit that will scale 100V to 5V.

Part II: The micro controller code.

Lets start by assuming our micro controller has a 10 bit ADC , Analog to Digital Converter. Each conversion will result in a number between 0 and 1023. 0 volts maps to 0 and 5V to 1023.

Recall that we are not interested in the voltage at the ADC but rather then the input to the voltage divide. For that voltage 0V still maps to 0 but 100V maps to 1023. Knowing this we can calculate the value in volts of each count. Lets call it vpc. A calculator gives the following result.

vpc = 100V/1024 = 0.0977

Actually the calculator result was 0.09765625 but that is way more precision the we have with 1% resistors.

At this point we could just multiply the ADC result by .0977 using floating point math. But the floating point library routines take a lot of memory and are slow.

This is where scaling comes in. I like scaling by 1000 because it allows us to intrepert the readings directly as mV rather then V. So lets scale the input voltage by 1000 and and round to the nearest integer.

vpc = (1000*100V)/1024 = 97.6 = 98

We have some error in this method. At full scale the error is.

error = (1024*98)-100000 = 352

Recall that we scaled the original value by 1000. To get the true error we need to divide the 254 by 1000 which means our actual error is 0.25V for a full scale reading.

We need to be careful to use a data type that will accept the largest possible number resulting from the adc reading times the vpc.

In our example that is 1024*98 or 100352, in hex this is 0x18800, a 17 bit number. Had we chosen a 16 bit unsigned int we would have been in trouble. We need to use a 24 bit data type (unsigned short long) or a 32 bit data type (unsigned long).

Because eight bit mircocontrollers lack floating point instructions using floating point can consume a lot of processor cycles.

In this article I will illustrate how to measure up to 100VDC with an analog to digital converter, ADC, with a positive voltage reference of 5V, +Vref, and a negative voltage reference at gnd -Vref.

The input to the the ADC must never exceed the 5V value of +Vref. We can use a simple voltage divider to accomplish this. To specify the resistors in out divider need to find the divider ratio.

dividerRatio = VmaxInput/VmaxOutput

100V/5V = 20

Note that our result 20 is a pure number and this is how we use it.

View attachment voltageDivider.png

Resistor must be R1=19xR2.

Scaled Voltage = Original Voltage (R2/(R1+R2)

If we pick R2 to be 1 we need an R2 of 19 to get a ratio of 20.

sv = ov (1R/(1R+19R)

sv = ov (1/20)

Which is exactly what we want but for the fact that this bit of circuit will waste more current then we would like.

I = V/R = 100V/20R = 5A

and

P = I**2(R) = 5*5*20 = 500 watts !

Looks like we need to reduce that current with more resistance. We can multiply R1 and R2 by any number as long as we do it to both. The 20:1 ratio will remain the same. Lets multiply both resistors by 1000 for a R1 of 1K and R2 of 19K. You may have to use 2 resistors in series to get 19K. Lets calculate the current for our new circuit.

I = V/R = 100V/20000R = .005A or 5mA

and

P = I**2(R) = .005*.005*2000 = .05 watts

At this point we have a circuit that will scale 100V to 5V.

Part II: The micro controller code.

Lets start by assuming our micro controller has a 10 bit ADC , Analog to Digital Converter. Each conversion will result in a number between 0 and 1023. 0 volts maps to 0 and 5V to 1023.

Recall that we are not interested in the voltage at the ADC but rather then the input to the voltage divide. For that voltage 0V still maps to 0 but 100V maps to 1023. Knowing this we can calculate the value in volts of each count. Lets call it vpc. A calculator gives the following result.

vpc = 100V/1024 = 0.0977

Actually the calculator result was 0.09765625 but that is way more precision the we have with 1% resistors.

At this point we could just multiply the ADC result by .0977 using floating point math. But the floating point library routines take a lot of memory and are slow.

This is where scaling comes in. I like scaling by 1000 because it allows us to intrepert the readings directly as mV rather then V. So lets scale the input voltage by 1000 and and round to the nearest integer.

vpc = (1000*100V)/1024 = 97.6 = 98

We have some error in this method. At full scale the error is.

error = (1024*98)-100000 = 352

Recall that we scaled the original value by 1000. To get the true error we need to divide the 254 by 1000 which means our actual error is 0.25V for a full scale reading.

We need to be careful to use a data type that will accept the largest possible number resulting from the adc reading times the vpc.

In our example that is 1024*98 or 100352, in hex this is 0x18800, a 17 bit number. Had we chosen a 16 bit unsigned int we would have been in trouble. We need to use a 24 bit data type (unsigned short long) or a 32 bit data type (unsigned long).