# How do I sample a -2 V to +2 V analog signal with a PIC microcontroller?

I am using a PIC micro with a 10bit ADC to take readings from an analog signal with a frequency less than 300 hz. However that analog signal is in the range of -2 V and +2 V. How can I condition the signal to get it into a usable range (assuming the input to the ADC has to be positive) Also I do not have a positive and negative power supply.

important note:
this answer was posted to solve the problem for -20V to +20V input, because that was what was asked. It's a clever method but doesn't work if the input voltage limit stays between the rails.

You'll have to scale the voltage with a resistor divider so that you get a voltage between -2.5V and +2.5V, and add 2.5V. (I'm presuming a 5V power supply for your PIC).

The following calculation looks long, but that's only because I explain every step in detail. In reality it's so easy that you can do it in your head in no time.

First this:

R1 is the resistor between $$\V_{IN}\$$ and $$\V_{OUT}\$$,
R2 is the resistor between $$\+5V\$$ and $$\V_{OUT}\$$, and
R3 is the resistor between $$\V_{OUT}\$$ and $$\GND\$$.

How many unknowns do we have? Three, R1, R2 and R3. Not quite, we can choose one value freely, and the other two are dependent on that one. Let's choose R3 = 1k. The mathematical way to find the other values is to create a set of two simultaneous equations from two ($$\V_{IN}\$$, $$\V_{OUT}\$$) pairs, and solve for the unknown resistor values. Any ($$\V_{IN}\$$, $$\V_{OUT}\$$) pairs will do, but we'll see that we can tremendously simplify things by carefully choosing those pairs, namely the extreme values: ($$\+20V\$$, $$\+5V\$$) and ($$\-20V\$$, $$\0V\$$).

First case: $$\V_{IN} = +20V\$$, $$\V_{OUT}=+5V\$$
Note that (and this is the key to the solution!) both ends of R2 see $$\+5V\$$, so there's no voltage drop, and therefore no current through R2. That means that $$\I_{R1}\$$ has to be the same as $$\I_{R3}\$$ (KCL).
$$\I_{R3}=\dfrac{+5V-0V}{1k\Omega}=5mA=I_{R1}\$$.
We know the current through R1, and also the voltage over it, so we can calculate its resistance: $$\R1=\dfrac{+20V-5V}{5mA}=3k\Omega\$$.
Found our first unknown!

Second case: $$\V_{IN} = -20V\$$, $$\V_{OUT}=0V\$$
The same thing as with R2 happens now with R3: no voltage drop, so no current. Again according to KCL, now $$\I_{R1}\$$ = $$\I_{R2}\$$.
$$\I_{R1}=\dfrac{-20V-0V}{3k\Omega}=6.67mA=I_{R2}\$$.
We know the current through R2, and also the voltage over it, so we can calculate its resistance: $$\R2=\dfrac{+5V-0V}{6.67mA}=0.75k\Omega\$$.
Found our second unknown!

So a solution is: $$\R1 = 3k\Omega, R2 = 0.75k\Omega, R3 = 1k\Omega\$$.

Like I said it's only the ratio between these values which is important, so I might as well pick $$\R1 = 12k\Omega, R2 = 3k\Omega, R3 = 4k\Omega\$$.
We can check this solution against another ($$\V_{IN}\$$, $$\V_{OUT}\$$) pair, e.g. ($$\0V\$$, $$\2.5V\$$). R1 and R3 are now parallel (they both have +2.5V-0V over them), so when we calculate their combined value we find $$\0.75k\Omega\$$, exactly the value of R2, and the value we needed to get $$\+2.5V\$$ from $$\+5V\$$! So our solution is indeed correct. [QC stamp goes here]

The last thing to do is to connect $$\V_{OUT}\$$ to the PIC's ADC. ADCs often have rather low input resistances, so this may disturb our carefully calculated equilibrium. Nothing to worry about, however, we simply have to increase R3 so that $$\R3 // R_{ADC} = 1k\Omega\$$. Suppose $$\R_{ADC} = 5k\Omega\$$, then $$\\dfrac{1}{1k\Omega}=\dfrac{1}{R3}+\dfrac{1}{R_{ADC}}=\dfrac{1}{R3}+\dfrac{1}{5k\Omega}\$$. From this we find $$\R3=1.25k\Omega\$$.

edit
OK, that was clever and very simple, even if I say so myself. ;-) But why wouldn't this work if the input voltage stays between the rails? In the above situations we always had a resistor which had no current flowing through it, so that, following KCL, the current coming into the $$\V_{OUT}\$$ node via one resistor would leave via the other one. That meant that one voltage had to be higher than $$\V_{OUT}\$$, and the other lower. If both voltages are lower there would only flow current away from that node, and KCL forbids that.

• -20V in will result in a little below 0V out. Jun 24, 2011 at 17:05
• (and maybe Olin Lathrop): I was trying to find out how you find the value of the 7k resistor. I noticed that when the input voltage is 2.5V there won't flow current to the node, whatever the resistor value, because no voltage difference. But that 2.5V in is not mid-range, while the 2.5V out is too. Doesn't that mean that the divider should have two different resistors? If you know what I mean. Jun 24, 2011 at 17:47
• Maybe that also explains @Olin Lathrop's comment. Jun 24, 2011 at 17:48
• @Frederico: Yes, it won't be completely symmetric. I discuss this in my answer. It is possible to adjust the three resistors to map -20 to +20 volts to 0 to 5 volts, but both Steven and I showed the simpler cases where you get a litle assymetry. Jun 24, 2011 at 18:41

The easiest way is to use a "resistor divider".

You didn't say what voltage this PIC is running at and therefore the A/D input range is, so let's use 5V for the example. Your input voltage range is 40V, and the output 5V, so you need something that attenuates by at least 8. You also need the result to be centered on 1/2 Vdd, which is 2.5V, whereas your input voltage is centered on 0V.

This can be accomplished with 3 resistors. One end of all three resistors are connected together and to the PIC A/D input pin. The other end of R1 goes to the input signal, R2 goes to Vdd, and R3 goes to ground. The resistor divider is formed by the R1 and the parallel combination of R2 and R3. You can adjust R2 and R3 to center the resulting range at 2.5V, but for simplicity explaining this we'll live with a little bit of assymetry and attenuate a little bit more to make sure both ends are limited to the Vss-Vdd range.

Let's say the PIC wants the analog signal to have a impedance of 10 kΩ or less. Again for simplicity, let's make R2 and R3 20 kΩ. The impedance feeding the PIC will be no more than the parallel combination of those, which is 10 kΩ. To get attenuation of 8, R1 needs to be 7 times R2//R3, which is 70 kΩ. However, since the result won't be exactly symmetric, we need to attenuate a little more to make sure -20V in won't result in less than 0V into the PIC. That actually requires attenuation of 9, so R1 must be at least 8 times R2//R3, which is 80 kΩ. The standard value of 82 kΩ will allow for some slop and margin but you still get most of the A/D range to measure the original signal.

Here is a example of finding the exact solution to a similar problem. This has no assymetry and has a particular specified output impedance. This form of solution can always be used when the A/D range is wholly within the input voltage range.

• +1 because as far as parts count goes, this is the easiest way to build what is required. Some notes: It is possible to take care of the asymetry in the uC's code, and by adding one capacitor in parallel to the resistor that goes to GND, the signal can be smoothed out (low-pass filter). The corner freq. is 1 / (2*piRC), where R is the parallel value of all three resistors and C is the value of the cap that is added (ADC needs cap. anyway!). Please calculate the accuracy of this setup considering all tolerances (R, ADC error in +/- max. LSB, Ref. error, ...) - it might be worse than expected. Jun 25, 2011 at 7:34
• @zebonaut - I did the calculation again and explained every step in detail in my updated answer (far less complicated that it looks!). It gives you an exact mapping of (-20V..+20V) to (0V..+5V) Jun 25, 2011 at 11:23
• @zebonaut: The capacitor might be useful as a anti-aliasing filter, but it does nothing about the assymetry. I didn't think the little assymetry was a big deal. It's easy enough to take care of in the firmware as you said. Jun 25, 2011 at 12:53
• If you want to compensate the asymmetry in software you will have to calculate the exact transfer function. If you have to do this anyway, why not use the right resistor values in the first place (not the ones from my first (erroneous) answer!) Jun 25, 2011 at 13:26
• @stevenvh: There is nothing wrong with using the "right" resistor values. I realized a exact mapping was possible (as I did mention in my answer), but decided not to get into the complexity of calculations and answer the conceptually simpler case that results in a little assymetry. In any case, you have to attenuate a little more to account for slop, and probably should calibrate in firmware anyway. Jun 25, 2011 at 13:33

This is the standard circuit for that. You need to scale the resistor values for your required impedance.

• Do you need to make sure your source impedance is relatively low if using that? Dec 6, 2010 at 17:04
• Leon, why not use a capacitor instead of the 1k resistor? Dec 6, 2010 at 17:41
• It's a DC-coupled solution. The series resistor is needed for proper operation. Dec 6, 2010 at 18:07
• @Leon Heller: I think this would be a better answer if you explained how to find the right values for the resistors. Jul 3, 2011 at 17:49

If the signal is not DC, or if a DC reference isn't important, the signal can be capacitively coupled to the input of the ADC.

Alternatively, if your ground for the PIC is floating, you could tie your signal ground to 1/2 VDD of the PIC.

• If you use capacitive coupling you get rid of the DC component, but the negative part of the signal will still go below ground, unless you provide a bias on the input pin by a resistive divider, like in Leon's circuit. Dec 7, 2010 at 8:27
• The supply voltage was not specified - it would work with a 5V ADC. If you were using a smaller Vdd, then you would need to scale the input. It would turn into Leon's circuit with a capacitor at that point.
– W5VO
Dec 7, 2010 at 16:44

The following circuit should do the job:

3.3V
+
|
\
/ 1k
\
|
|
\
/  1k
\
|
+-- Signal input (-2V to +2V)


It's a potential divider. At -2V, the output will be 0.65V; at +2V, 2.65V.

All noise on the 3.3V rail will get transferred to the input, so use a good voltage reference to reduce this problem.

This will work with other supplies too, but the offset will shift.

• Yes, it works, but it would be nice to use the full ADC range :-) Jul 3, 2011 at 15:46
• @stevenh You can do that using 0.65V and 2.65V references although you may as well use your circuit then. Jul 3, 2011 at 15:53
• AFAIK PICs only have a $V_{REF+}$ input, you can't set $V_{REF-}$. Like for most controllers this is always connected to $GND$. Jul 3, 2011 at 16:11
• @stevenh PIC24, dsPIC and PIC32 definitely have Vref-. I think some 18F do too. Jul 3, 2011 at 16:51
• Yeah, OK, I don't know them all (there's a lot of them). OP doesn't say which part he's using and he seems to be vanished, so it's no use asking him. Jul 3, 2011 at 17:18

Thomas' voltage adder with two identical resistors is indeed simple, but has the disadvantage that the input range to the ADC is reduced, which means that noise will have a bigger influence. Also the lower limit is at 0.65V. If your microcontroller doesn't have a $V_{ADCREF-}$ input (most controllers don't) that part of the input range will remain unused.
This is easy to fix: choose the resistor ratio so that $V_{ADC}$ will be 0V if the input is -2V. For a $V_{DD}$ of 5V this means the input resistor should be 2/5 of the pull-up resistor. At 2V input $V_{ADC}$ will be 2.86V. Set $V_{ADCREF+}$ to this level, and the -2V to +2V will cover the full ADC range.

If your $V_{DD}$ = 3.3V the input resistor should be 61% ($\frac{2V}{3.3V}$) of the pull-up. At +2V in $V_{ADC}$ will be 2.49V.