'Instant' Resistor Measurer
This project is a little old, but now that I have some time, I thought it would be nice to write it up! The device has been serving me well for a few years now.
Being somewhat red/green color blind, I’ve always had trouble reading through-hole resistor color codes (though I often wonder if those with full color vision have it much easier - some resistor bands are so ‘muddy’!) I make do with labeled pouches holding my resistors, and a multimeter to double-check. The multimeter is so slow. Surely it shouldn’t take seconds to sense a resistor value!
For years I dreamt of making a faster resistor measuring device with an instant readout.
The ‘final straw’ that pushed me to actually do that was that I bought a beautiful old metal Akro-Mils cabinet1 stuffed with old through-hole carbon composite resistors at the Silicon Valley Electronics Flea Market. The resistors were obviously sorted in the drawers at one time - but time and chaos had taken their mysterious toll, and they’d become pretty substantially mixed up.
I needed to sort these hundreds of resistors if I was to ever use them. With the multimeter, that would take for ever.
The ‘resistor measurer’ I built (call it an ohmmeter if you insist) works really well. It measures the value of a resistor fast enough to seem instant, and it optionally rounds to the nearest E24 or E96 value. I also designed and 3D-printed a benchtop case for it.
I’m quite pleased with the circuit I came up with to measure the resistance!
The device
The case has banana jack sockets to plug test leads into. I’ve used blue test leads - I switched blue from from the easier-to-find black and red after a debacle where, thinking they were the test leads from my multimeter, I connected the black and red test leads to a 170V nixie power supply. The circuit did not appreciate that 😬.
You could plug some surface mount tweezers in to the jacks here if you wanted to measure SMD components.
It also has a ‘fast test area’ on the top right with a recess to accept through hole resistors, using copper tape to make contact with its leads. A plate hinges on to it to ensure a good connection. This is pretty fast to use - just drop the resistor and close the plate - and was what I used when I was sorting the resistors.
The measured value is displayed on the LCD display in big numbers, and there’s an arrow on the display pointing to the ‘k’ or ‘M’ symbol on the casing to indicate units.
The entire thing was designed using only parts I had on hand. Some were other flea market finds! Most noticeably this plays out in the super weird screen - but a lot of the internal components are rather esoteric or old too. It could be made much smaller. I suspect that with appropriate modern components and a proper PCB with a more compact circuit layout it could even be embedded into a pair of probes or tweezers.
I’m very happy with the size, though - it sits nice and solidly on my workbench and is easy to read.
Design overview
The heart of the system is an ATmega8A with all its potential I/O pins except the reset pin in use. All measurements are done with its built in ADC, and it directly drives the LCD display.
A known reference precision resistor is placed inline with the resistor under test to form a voltage divider, and the voltage at the point between them is measured using the ADC. Given that one of the resistors is of a known value, it’s easy to calculate the value of the unknown resistor:
/*
- - --+-- - -
|
+----- 1024
|
+-+
| |
| | reference Ω
| |
+-+
|
+----- reading
|
+-+
| |
| | unknown Ω
| |
+-+
|
+----- 0
|
---
-
(reference + unknown) / 1024 == reference / (1024 - reading)
reference + unknown == 1024 * (reference / (1024 - reading))
unknown == 1024 * (reference / (1024 - reading)) - reference
unknown == (reference * 1024) / (1024 - reading) - reference
*/
While this works perfectly in theory, it’s made a bit more complicated by the fact that in real life just one reference resistor isn’t enough.
Imagine the system was trying to measure a 100Ω resistor, and the reference resistor was 100kΩ (or vice versa). The ratio between them would be 1000 : 1. The ATmega’s ADC only has 1024 points (10 bits) of resolution, so this isn’t good enough to get a precise result. Even if the ADC was precise enough, the reference resistor is ‘only’ accurate to within 1%, which would skew the result when being compared to a resistor that’s not close in value to it.
To combat this, five different reference resistors are used, and the code switches between them to find the one that gives the best resolution when used with the resistor under test. Making this switching possible without introducing voltage drops or fluctuations that would distort the result was a challenge, and I’m very pleased with the op-amp assisted solution I came up with.
Circuit design
Remember, I was using components I had on hand!
Power supply
First, the power supply. Op-amps usually require their supply to provide headroom both above and below the range of voltages that you want them to be able to output. Older op-amps, like the LM741s I had on-hand, require quite a lot of headroom - at least 2V on both sides. Because I was using an op-amp in the measurement section, I wanted to ensure I had overhead both above the microcontroller supply voltage (around 3V), and below its ground.
Here’s the circuit:
+VDC
and -VDC
are the +12V and ground inputs from a 12V DC power supply. The LED on the right (D7
) is a blue LED with around a 3V voltage drop. It is surrounded by two 1K resistors (R27
and R28
). This makes the voltages on this ‘ladder’: 0V at the bottom, below the bottom resistor; +4.5V above it and below the LED; +7.5V above the LED, below the top resistor; and 12V at the top.
The 4.5V and 7.5V points are buffered through two LM741 op-amps (U1
and U2
) and a couple of generic small transistors - the top one (Q7
) NPN and the bottom (Q8
) PNP.
Voltages are all relative, so for the rest of the circuit, I treat the buffered 4.5V as ground. This turns the buffered 7.5V into 3V, the 12V supply into 7.5V, and the -VDC (ground) from the power supply into -4.5V (that’s negative 4.5V).
KiCad Label | Logical Voltage |
---|---|
+VDC |
7.5V |
+3.3V |
3V |
GND |
0V |
-VDC |
-4.5V |
The logical voltages are all approximate - the blue LED is hardly a precision 3V device - but that’s fine. The rest of the circuit doesn’t rely on them being precise. All that’s required is that there’s enough voltage in the ‘middle’ to run the microcontroller, and enough headroom above its supply, and below its ground, for the rest of the measurement circuit - and the op-amp in it - to function across the entire microcontroller supply range.
The microcontroller and display
Before I go into things more in-depth, here’s the whole circuit. I don’t show this so that you can decipher it all - it’s just a bit awkward to talk about the microcontroller and display without a visual reference. I’ll zoom in on the measurement part (all those transistors, resistors and stuff on the bottom right) in the next section.
The brains of the operation here are an ATmega8A (U5
).
The super weird screen (DS1
) is a bare LCD I got years ago in a Kemo Electronic ‘grab-bag’ of displays from the now-defunct Maplin. It was somewhat documented back in 2013 on picaxeforum.co.uk. It’s the “2-4 LCD with pins”. From the available symbols on it, it looks like it was originally designed for a heating or air conditioning control unit. My thanks to ‘nick12ab’ for the time they spent a decade ago working out its pin-out!
Many online resources will tell you it’s not possible to drive a bare LCD from a microcontroller without a dedicated LCD driver - but that’s nonsense. A few resistors and some well timed code are ‘all’ you need! I mostly learned from this Dataweek article from way back in 2003 - but I later found that Microchip (nee Atmel) has an application note covering much the same thing - AVR340, Direct Driving of LCD Using General Purpose IO.
Apologies for the complexity of my LCD driving code. I was exploring C++ compile-time execution features when I implemented it. The result is a fairly efficient LCD driver - but it ended up, uh, quite esoteric. It works well though, so I haven’t changed it…
I won’t go into the LCD driving much further here because that’s not really what this post is about. Suffice to say, Pins 0-3 of the ATmega are set up to drive the ‘common’ pins of the LCD display. Pins 4-7 and 14-19 are set up to drive the segment pins of the LCD display.
The Analog-Digital Convertor of the ATmega is set up by code to operate over its entire supply voltage range (so 0 measurement means GND, 1024 measurement means supply voltage). C4
is the 0.1uF capacitor that the ATmega8A datasheet asks you to put between pin 21 and GND if you set up the ADC like this. Pin 28 is used as the ADC input.
Pins 23-27 are used to control the resistor selection transistors (Q1
- Q5
).
The measurement circuit
Let’s take a closer look at the measurement circuit - it’s the real ‘meat’ of this project:
The test terminal (JP1
) is what the resistor to be measured is connected across.
Resistors R11
to R15
are the reference resistors. They range from 200Ω to 2MΩ, each one an order of magnitude more resistive than the previous2.
The ATmega’s ADC is connected to the point(s) between the reference resistors and the resistor under test.
C10
should not, in theory, be required, but I found it helps readings stabilize more reliably.
PNP transistors Q1
- Q5
are used to select which reference resistor is ‘on’3. The lines connected to their bases with the 680Ω resistors (R17
- R21
) are connected to pins 23-27 of the ATmega. All but one of these pins are set as ‘high impedance’. This means that all but one of the transistor bases are pulled up to +VDC by the 22k resistors, so they are ‘off’. The remaining pin is pulled low. This forms a voltage divider between the 680Ω and 22kΩ resistor, which pulls the PNP transistor base much lower than its supply voltage, switching it on. This resistor is therefore the one that conducts through the test resistor.
The code on the ATmega cycles, activating the transistors one at a time, until it reads a ‘good’ ADC reading (I settled on between 233 and 787 - can’t quite remember how I calculated that range…), and uses that to calculate the value to display.
Okay - so what are those diodes (D2
- D6
), op-amp (U4
) and NPN transistor (Q6
) for?
For the calculations based on the ADC values to work, the point at the top of the test resistor (the points that the diodes are attached to) needs to be at exactly the same voltage as the ADC’s reference high voltage - which is identical to the ATmega’s supply voltage.
The resistors are connected to the bottom of the selection transistors Q1
- Q5
. That means that the top of the active resistor is one transistor’s voltage drop below its transistor’s supply voltage. So, the active transistor’s supply voltage needs to be above the ATmega’s supply voltage to compensate for this transistor voltage drop and ensure that the voltage at the top of the resistor is correct.
I glossed over the two op-amps in the power supply section, but I’ll go into more detail here, because (U4
) is really what makes this work. In simple terms, op-amps in a configuration like this alter their output voltage to make their + and - input voltages the same.
Diodes (D2
- D6
) are connected to the negative input of the op-amp. The positive input is connected via another diode to AREF
- the ADC’s reference voltage (which is, again, identical to the ATmega’s supply voltage). The output of the op-amp is connected to a voltage-following transistor, (Q6
), which supplies current to the selection transistors.
Diodes (D2
- D6
) ‘select’ the most positive voltage from the top of the resistors - which will be the one form the transistor that’s on - and feed it, minus a diode drop, into the negative input of the op-amp. The op-amp will try to alter its output so that its negative input is the same as what’s being fed to its positive input - which is the ADC reference voltage, also minus a diode drop.
So, this section basically forms a power supply that supplies the selection transistors with exactly the correct voltage to ensure that the voltage ‘under’ the one that’s ‘on’ is the same as AREF
!
It took me some time, as an op-amp neophyte, to come up with this, and I’m quite pleased it works so well! I’d love feedback (positive or negative) on it from anyone with more experience.
A nice thing about this whole scheme is that the supply voltage to the ATmega doesn’t need to be precise - the measurements are all working with reference to the supply, not a precise voltage reference - and the individual transistors don’t need to have identical characteristics. There will be some discrepancy if the voltage drop across D1
and D2
- D6
is not identical - but I have not found that it’s problematic in real life.
Lastly, you will notice in the pictures that there’s a button on the front of the device. It’s used to switch between displaying the closest E24 value, the closest E96 value, or the precise measured value. It’s not on the circuit diagram though! That’s because I had no microcontroller pins left to connect it to, so, instead, it shorts out the test connection when pressed. The code senses this apparent 0Ω resistor and treats is as a button press. In a hypothetical version of this device that was using a less weird display - and so didn’t have to dedicate so many pins to drive the LCD directly - I would move that button to a dedicated input pin.
Construction
Being an esoteric one-off, I didn’t order a real printed PCB for this. Instead, I laid out the circuit for perfboard.
I used KiCad’s PCB editor to lay it out - if you set up the grid snapping appropriately you can make all the connections on 2.54mm grid points, use the design rule checker to ensure you’ve done it well, then print out the diagram at 100% scale and paste it to the perfboard to create a sort of template.
When constructing it, I made the horizontal, purple, ‘back layer’ connections with mostly component leads on the back of the perfboard, and the ‘front layer’ red connections with a mix of jumper wire and component leads.
Now, before I show the finished PCB, I have to point out that the resistor measurer has been through a fire! It was damaged both by heat and firefighting water. I re-printed the case, and fixed up some corrosion and breaks in the circuit - but it’s now [even more] far from the neatest thing inside the case. You can still barely make out the circuit template on the paper where the inkjet ink was not washed off by the firefighting water.
Conclusion
I’ve put the project on GitHub. I can’t imagine anyone being able to use it directly since it relies on the esoteric components I had at the time I made it - but perhaps the code and circuit can provide a starting point for someone else.
If I were to work on it more, I’d change the components to something more modern and lay out a real PCB. Maybe some day I’ll do a version 2!
-
Sadly, no picture of the actual cabinet because it was destroyed in a fire that took out the back of the shed my electronics workbench lives in. The resistors, by then sorted and sealed in a box, survived. As did the Resistor Measurer - although the both the fire and the firefighting water took a toll on it - I needed to fix some corrosion and print a new case for it. ↩︎
-
The reason
R12
is 2.11kΩ, instead of 2kΩ, andR15
andR16
are two 1MΩ resistors rather than one 2MΩ one, is just because that’s the value of precision resistors I already had. One 2kΩ and one 2MΩ would be more sensible. ↩︎ -
These transistors are ‘upside-down’, with their collectors and emitters switched. This is an error! Luckily for me, they work well enough in reverse active mode that the circuit still works. Unfortunately I can’t just flip the transistors on the PCB, because the KT361 doesn’t have the base in the middle like most modern transistors. If I were to build another revision of this project, I’d definitely be changing the circuit diagram and layout… ↩︎