Home and Links
 Your PC and Security
 Server NAS
 DVD making
 Raspberry Pi
 PIC projects
 Other projects
 Next >>
[Measuring resistance with a PIC10F206] [How to measure a variable resistance] [Application] [Detailed explanation] [Charging / discharging limits] [Choosing the Capacitor value] [Calibration] [Timing to angle calculations] [Converting timing to Degrees by LUT] [Building the LUT]
PIC10F206 as a position sensor

Measuring resistance with a PIC10F206

The PIC10F206 has only 4 i/o lines - and at least 1 of those will have to be 'reserved' to communicate with the rest of the system - so why use it ? Well, CPC 'remaindered' their stock at 25p each, so grabbing a few dozen was irresistible :-)

The 10F206 chip does have a couple of advantages over some of the 'higher pin count' alternatives
First, it's got an internal 4MHz OSC (so delivers 1 MIPS performance with no external components).
Next the i/o pins have 'weak pull ups' (internal 'pull Hi') which will also minimise the need for external components
Finally, it has one (8 bit) counter/timer and one 'analogue' comparator, which, when used together, can be used to form a basic A-D converter for 'resistance measurement'


How to measure a variable resistance

The basic approach (shown right) is to measure the time taken to discharge a capacitor, via the variable resistance, to the 'lo' (or 'sense') voltage.

To achieve maximum repeatable accuracy, the PIC internal 0.6v Vref is used as the 'sense' voltage, however in many applications (such as detecting one of up to 16 buttons (or the combination of 4 switches)), the normal pin input 'logic 0' level will be 'good enough'

When detecting a potentiometer position, a combination of the internal Vref, 8 bit counter-timer and 'calibration' can achieve an accuracy of 1 in 256 (or 0.25%). Even without calibration it should be possible to achieve better than 1 in 100 (1%).

The same approach can be used to detect the settings of up to 8 switches (using 'binary' switch resistance values allows any combination of switch settings to be determined).

If only one switch (button) can be set (pushed) at any one time (i.e. they are all 'momentary action' types) the resistors can be simple multiples.

If the maximum is 5k, and a 100 ohm resistor 'step' is used, it would be possible to 'spot' any one of up to 50 buttons (the first is set to100R, the next 200R then 300R and so on). This would allow an entire keyboard to be 'sensed' (although in practice a 'matrix' arrangement would be used)



Typically, the potentiometer is used used to detect axial position - for example the 'tilt' position of an Alt-Az telescope mount (such as that used by a Dobsonian telescope).

A rotary potentiometer fitted to the axis can be used to 'sense' the position, however some sort of 'calibration' step will be needed (since the 'end' positions are unlikely to be '0 ohms' or '(5k) ohms')

To measure a linear position (eg. position of a camera on a Macro Focusing trolley), a 'rack and pinion' can be used, with the potentiometer fitted to the pinion or (with somewhat lower accuracy) a 'pulley wheel' system

To improve sensing accuracy for applications with a restricted range of movement, a geared connection to the Potentiometer can be used.
In the case of the Alt-Az telescope mount example, the total 'tilt' is only 100 degrees or so. This can be 'multiplied up' using a 3:1 gear to make use of a full turn** pot. (or by a higher ratio if a 5 or 10 turn Pot is used)
For example, a 5 turn Pot. has about 5x 360 degrees before hitting the end stops. If this only needs to measure 100 degrees, then in theory** it can be geared by 5x360/100 = 18:1 (a single turn can be geared by 3.6:1, a 10 turn by 36:1). Of course, whilst a multi-turn Pot. means smaller movements can be 'spotted', the higher the gear ratio the more likely back-lash will be a problem.
**Pots., especially cheap ones, don't offer anything like 360 degrees of travel = in fact, you will be lucky to get 240 degrees out of most 'single turn' Pots. (so gear 2.5:1 if you are lucky, or 2:1 to be safe (you don't want to run into either end stop) !


Detailed explanation

The 10F206 internal comparator can be used to compare the voltage on GP0 (pin n) or GP1 (pin x) to an internal 0v6 'reference' voltage. That allows these 2 pins to be used as 'sense/set' pins for quite accurate voltage sensing. Somewhat less accurate is to use the pin in 'digital input' mode and wait for a '0' to be detected

The 'wiper' on the potentiometer is wired up so the it discharges the capacitor to ground. To measure the resistance, we start by charging the capacitor to a 'known' voltage (actually, this is done by setting the 'sense/set' i/o pin to logic 'Hi' and enable it as an output = so the 'known voltage' is digital logic '1').

The 'sense/set' pin is then switched to 'sense' (input) mode and compared to the 0v6 Vref. By timing how long it takes to reach 0v6, the resistance can be calculated


Charging / discharging limits

A PIC output pin can source 25mA at Vdd-0v7. If Vdd is 5.2v, and the capacitor starts at '0', then we need to fit a 'charge up' current limit resistor (R1), which will be (5.2 - 0.7)/25mA = 180 ohms.

From this we can calculate how long it will take to 'fully charge up' the capacitor

Next we need to consider the 'discharge limit' resistor (R2). Without R2, when the variable resistance (potentiometer) reaches '0' the capacitor would never charge up. So R2 has to be high enough (compared to R1) to let the capacitor 'charge up' but low enough to allow the PIC to sense the Potentiometer setting across it's entire range. Assuming a 5k Pot, we can set R2 = 1k (so the measured 'discharge' resistance will vary from 1k to 6k).

Capacitor time and voltage calculations can be hard to understand**, however all we need to note is that the discharge time (to reach the 0v6 reference) is a direct (linear) function of the resistance (i.e. if you double the resistance, this takes double the time). This means we need to use 'Linear' Pots (rather than the 'Log' type used in audio systems) **If the capacitor starts at 4.5v, then after time 't' it will reach a voltage V given by the formula: V = 4.5 e^-(t/RC) (where e = the natural log base, 2.718281828459) From this it is possible to calculate how long it will take to reach 0v6


Choosing the Capacitor value

I started by considering a 10uF Cap. This will discharge from 4.5v to 0v6 via 6k resistance in 120mS. The same cap, discharged via a 1k resistor, will reach 0v6 in 20mS (I used the on-line calculator found here = note, you need to set 'Supply voltage = 0' to get the discharge time)

The PIC timer/counter thus needs to measure times between 20 and 120mS, and if the counter is clocked every 0.5mS we get an accuracy of 0.5mS and a max count of 125mS. Can this be done ?
Well, the PIC10F206 internal 4MHz OSC is divided by 4 (= 1MHz / 1uS) and fed to the pre-scaler.  The pre-scaler can be set to further divide the clock by 8 'powers of 2' from 1/2 (000) to 1/256 (111). Setting the maximum divide (1/256) we get a counter clock of 256uS (or about 1/4mS) giving a max count 256 of 64mS (i.e. half what we wanted)
Plainly a smaller Capacitor (or smaller Pot.) is needed. Dropping the cap. to 4u7, I get a minimum (1k) time of 9.5mS, max. of 57mS which is more like it.
To reach 57mS using a 256uS clock = a count of 222 (just within the max. 256)

Note, component tolerances will make it impossible to 'pre-set' the expected counts - the sum of the 'worst case' capacitor, resistor and supply voltage variations are likely to reach 10% (or even more), so it's quite possible that the 'count 222' limit will be reached at 200 (or 248).



Whilst we can pre-measure and select capacitor and resistors (and use a precision voltage regulator for the Vdd supply), the actual '0 degree' and '90 degree' positions will depend on how the axle gear is 'mated' to the potentiometer gear and how 'level' the mount is positioned on the ground

So, at power-on the PIC will need to discover the residual resistance at the 'end stops' of the travel

In the Dobsonian example, the user would start by moving the telescope tube to the vertical (90 degree) and horizontal (0 degree) positions. A spirit level mounted on the end of the tube can be used for this (and a button press used to tell the PIC when the tube is aligned so it can take a reading).
From these two readings, the PIC 'should' be able to calculate actual degrees from vertical directly from the timing count.
Clever code will ensure the order of measurements is irrelevant. A single PIC pin can be used to control 2 LED's and sense a button, so the extra 'overhead' is not high (although the PIC will have to wait for the button to be pushed, then respond with LED so the user releases the button (and the PIC must check the button has been released before using the other LED)

(+) One pin dual LED and button detect


Timing to angle calculations

When calculating actual degrees, the PIC will need to take into account the fact that the 'start' voltage of the capacitor will vary depending on the Potentiometer value (when the PIC is charging the Cap, the Pot will provide a 'path to ground' thus acting as a voltage divider and preventing the Cap from reaching the full (Vdd-0v7) logic '1' voltage).

The effect on the start voltage will be more significant when the Pot. is at the 'zero' end of travel, leaving only the discharge limit resistor (1k) 'in circuit'. At this position, instead of 4v5, the Capacitor will reach only 1000/1180 of 4v5 = 3v81.
Whilst there is no problem with measurement (the discharge time to 0v6 will be 8.7mS = count of 38-39) it does make it rather more complicated to calculate the 'inclination' (in degrees) from the 'raw discharge times'.


Converting timing to Degrees by LUT

To convert times to degrees, a 'Look Up Table' can be pre-generated and used together with the 'calibration' values.

A simple LUT would consist of 256 locations (256 being the max. counter/timer value) each containing a 2 digit BCD (4bits each = 1 byte).
However the 10F206 only has 512 words of program memory, and a simple LUT would use half of this.
To save space, instead of a LUT containing 256 output values, a better approach is a LUT containing 100 count values (i.e. the count for each degree value).
This saves 156 locations at the 'cost' of slightly more complex PIC code.

Instead of a simple 'use the count as the address to look-up the value', the code has to 'scan' the LUT to find the address curtaining the closest LUT count (and then convert the address of that location into the output ASCII).


Building the LUT

There are two possible approaches to building the LUT = (1) calculate the values 'theoretically', or (2) start by programming the PIC to output the 'raw count' and then form the LUT by tabulating actual counts whilst moving the axis in small (eg 1 degree) steps

The problem with 'theoretical' calculations is that it's very difficult (if not impossible) to take 'everything' into account.
Some things - like the power supply voltage and resistor / capacitor accuracy and even 'leakage currents' - should only result in 'offsets' that the 'calibration' step should compensate for. However other things - like the 'linearity' of the potentiometer (resistance V's rotation angle) - can't be 'calibrated out' from two 'end values'

The only way to avoid lots of calculations (and re-calculations when the 'real world' fails to match the 'theory') is to actually measure the timer count values. This not only 'takes into account' any non-linearity' in the Pot. position-resistance behaviour, but also 'allows for' factors we aren't aware of

To tabulate to '1 degree step' accuracy, a laser pen can be (temporally) fitted to the end of the tube and 'aimed' at a zoomed-up scale (marked in degrees) on some far wall / ceiling (giving 100 values = 100 position LUT)
Alternatively, a protractor and 'plumb-bob' on the tube end should be enough to get well within 5 degree accuracy - and the 'intermediate' values (to get from the 20 measured to the full 100 position LUT)
If we store only the 25 measured values (rather than 100 values) we save 75 program locations, although at a cost of extra complexity (as extra code is needed to 'interpolate' between two values)

Next page :- Variable resistance measurement