The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Electronics Workbench

Electrical & Electronic gadgets

  • Clock-radio Backup Battery vs Current Drain

    Clock-radio battery hack
    Clock-radio battery hack

    The little red Battery Sentinel LED on our old Realistic (a.k.a. Tandy a.k.a. Radio Shack) clock radio was on this morning, which means that, once again, the backup battery needs attention.

    It’s supposed to use an ordinary 9V battery, but it ate two or three of those a year. Given the absurd cost of 9V batteries relative to AA cells, that stopped making sense pretty quickly.

    Most devices with backup batteries draw essentially zero power from them during normal operation. This gadget draws 6 µA.

    An alkaline 9V battery has a capacity of about 500 mAh, maybe more with a low-drain load like this. That should last for a few years:

    500e-3 / 6e-6 = 83k hours = 500 weeks = 10 years

    Alas, the clock battery monitor is really fussy and triggers the LED when the voltage drops under about 8.5 V.

    [Update: the clock does a “battery test” every day, which probably accounts for the short battery life. I haven’t measured that current… or the duration of the test.]

    Fortunately, the clock case has a recessed bottom that fits a standard AA cell holder like a glove. I wired up 1-1/2 4-cell holders (yes, I should have used 7 cells, but I wasn’t sure what the upper voltage limit might be) to a standard 9V battery snap connector and screwed the assembly to the case.

    Now all I must put up with are the weak AA cells I got from batteries.com; the most recent order was a disappointment.

    Memo to Self: That snap connector has red = negative / black = positive!

  • Old Kenmore Sewing Machine Foot Control Repair

    Foot control - inside view
    Foot control – inside view

    One of Mary’s first investments when she got out of college was a sewing machine and she’s been using it ever since. Of late, it’s gotten a bit sporadic and the foot control seemed to be at fault.

    The symptoms were that the foot control required too much travel (equivalently: foot pressure) to get up to speed, it started abruptly (poor speed regulation), and sometimes cut out without warning.

    So I took it apart to see what I could do.

    Two pins in the side hold the top cover in place and serve as pivots. Loosen the two visible screws in the center of two of the bottom feet, hold the top half of the case down, and slide the pins out.

    A wedge on the top half presses down on the middle of the steel bar, pressing it into the rheostat. A dab of silicone lube on the wedge greatly improved that action.

    Rheostat graphite wafers and contacts
    Rheostat graphite wafers and contacts

    The speed control itself is brutally simple: a carbon-pile rheostat in series with the 120 VAC 1 A sewing machine motor. The ceramic case and heatsink tab tell you that things get pretty toasty inside that Bakelite case.

    Disassembly is obvious, which is one of the nice things about old electrical gadgets: you can puzzle out how they work and how the parts fit together just by looking. A slew of graphite disks slides out from two cylindrical tunnels in the ceramic case, followed by two graphite contact buttons. The brass fittings on the front have carbon dust on their raised surfaces, but are basically just stamped & machined metal parts.

    No fancy electronics, no firmware, just a high-power (and utterly non-inductive!) carbon variable resistor.

    The rheostat has three modes, in increasing order of pressure:

    • Off — no pressure on the foot control
    • Resistive speed control — resistance varies with foot pressure
    • Full throttle — rheostat resistance shorted by front switch
    Rheostat speed control contacts
    Rheostat speed control contacts

    With no pressure on the foot control, there’s a generous gap between the contact bar on the back surface and the two graphite buttons sticking out of the ceramic case. There’s no way for the contacts to close by shaking or accident.

    A bit more foot pressure connects those two buttons through the shorting bar across the back. Light pressure on the graphite disks means a relatively high resistance, on the order of several hundred ohms, and relatively low current to the motor. Of course, that also means the motor has poor starting torque, but … a sewing machine doesn’t need a lot of torque.

    Increasing foot pressure squeezes the disks together and decreases the resistance. It drops to a few tens of ohms, perhaps lower, but it’s hard to get a stable measurement. The motor averages all that out and trundles along at a reasonably steady pace.

    Rheostat full-speed contacts
    Rheostat full-speed contacts

    Finally, the brass disk in the central case tunnel shorts the tabs on the two brass end contacts and lets the motor run at full speed. Increasing the foot pressure beyond that point doesn’t change anything; the spring-loaded shaft can’t deform the tabs.

    The steel shaft and contact disk can short one or the other of the two piles, but that just decreases the already small resistance by about half. That might give the motor a speed boost instantly before jumping to full speed.

    As nearly as I can tell, the carbon disks evaporated over the decades, as the piles seems quite loose and required a lot of foot motion to reach the first contact point. I lathe-turned a pair of brass disks about three wafers thick, so that they’d take up the empty space in the piles.

    I also filed the brass end fittings flat so that they contact the disks over more of their surface. The first two disks looked like they had hot spots: loose carbon collected in the areas where the contacts didn’t quite touch them. I doubt that actually improved anything, but it’s the thought that counts.

    The spacers worked reasonably well, although I wound up removing one graphite disk from each pile to ensure the full-speed contacts would close properly. They’re in a small plastic bag tucked under the aluminum heatsink tab, where they can’t get lost. With any luck, the bag won’t melt around them.

    Rheostat with brass spacer button
    Rheostat with brass spacer button

    A few days later, the sewing machine stopped working entirely. The foot control itself seemed to be working correctly, but a bit of poking around showed that the cord had a broken conductor just outside the strain relief. I cut the cord off at the strain relief, hacksawed the strain relief apart, then rewired it. The cord is now four inches shorter and everything works fine again.

    I think this would be a nice candidate for a PWM controller, but then I’d have to shoehorn all that circuitry into the base of the sewing machine or add another cord to the foot control. Ptui, this works well enough.

    Memo to Self: Replace the entire cord next time.

  • RC Snubber Resonant Design

    An RC snubber is just a resistor and capacitor in series that damps out the oscillations occurring when a switched inductive circuit turns off.

    How this is supposed to work is that the snubber capacitance forms a resonant tank circuit with the inductance, the resistor absorbs the tank’s energy, and the oscillations damp out quickly.

    In practice, snubber circuits tend to be ill-designed, simply because it seems there’s no good way to measure the actual inductance and stray capacitance at the switch. Folks tend to apply a 100-ohm resistor and a 100 nF capacitor and hope for the best. Sometimes that works. Most of the time it’s suboptimal.

    You can do better than that.

    Forward converter switch, transformer, and snubber
    Forward converter switch, transformer, and snubber

    Here’s the key chunk of simple-minded forward converter I’m doing for a Circuit Cellar column. It’s an LTSpice IV model, not an actual schematic, but the hardware is pretty close to what you see here. The “Stray” capacitance at C5 represents a measured value, not an actual component. The transformer parameters come from my measurements there.

    A microcontroller drives the transistor switch, which draws current through the transformer primary and transfers power to the secondary winding; the turns ratio is 1:25, so a 6 V input becomes a 150 V output. When the microcontroller shuts off the switch, the collector voltage pops up to about 11 V, at which point the stack of diodes turns on and the inductor begins to discharge. The diode forward-bias characteristics keep a more-or-less constant voltage until the current becomes essentially zero, so the collector voltage declines only slightly as the current drops.

    When the current drops enough that the diodes don’t conduct very much, the collector node is in a peculiar condition: there’s no place for the remaining energy to go!

    Undamped collector ringing
    Undamped collector ringing

    This scope shot shows the result. The drive pulse (top trace) pulls the collector voltage (bottom trace) to zero, it snaps up to 11.5 V, and then declines to about 10 V before the diodes switch off. At that point the collector voltage rings like a bell: 8 V peak-to-peak at 10 kHz. That’s a very low frequency because the primary reflects the fairly substantial stray capacitance in the zillion-turn secondary winding.

    In order to form a resonant circuit, you need some idea of the existing inductance and capacitance. You can’t just clip a meter in there to measure them, because their values depend on the frequency, layout, and actual hardware.

    One good experimental technique is pretty well summarized in Maxim’s AN-3835, which deals with Cold-Cathode Fluorescent Lamp drivers. Pay no attention to the CCFL stuff, as snubber fundamentals are the same wherever you go.

    Basically, you add a test capacitance across the transistor (from collector to ground, similar to C5 in the schematic) and measure the new ringing frequency. Fiddle with the test capacitance until the frequency is half of what it started at. Use reasonably short lead lengths, particularly for applications that don’t involve actual transformers or inductors; surface-mount capacitors are your friends.

    What you’re doing is fiddling with this equation:

    F = 1 / (2 π sqrt (L C))

    Because of the square root around LC, when you increase the capacitance by a factor of 4, the frequency decreases by a factor of 2. So the test capacitance required to cut the frequency in half is three times the original stray capacitance. Got that?

    Knowing the original stray capacitance, which is 1/3 the test capacitor value, and the original ringing frequency, you can figure out the actual inductance:

    L = 1 / ((2 π F)^2 C)

    Now the magic happens…

    You know the inductance and capacitance of the tank circuit and its resonant frequency. At that frequency, the inductive and capacitive reactances are equal:

    XL = 2 π F L
    XC = 1 / (2 π F C)

    In fact, they’re also equal to what’s called the characteristic impedance of the circuit:

    Z = sqrt(L / C)

    The resonant frequency is about 10 kHz and an additional 60-some-odd nF dropped the frequency to about 5 kHz. Fairly obviously, your stock of caps will affect the precision of the results. Let’s suppose the stray capacitance, shown as C5, is about

    C5 = 60 / 3 = 20 nF.

    The inductor is then:

    L = 13 mH

    The characteristic impedance works out to:

    Z = 800 ohms

    Take those numbers with a grain of salt, but twiddling the scope cursors will get you pretty close in your own circuit.

    In order to swamp any variations in the stray capacitance (during the production run or whatever), pick the snubber capacitance to be at least four times the stray capacitance, rounded up to the next standard value. In this case, that works out to the traditional 100 nF, but that need not be the case.

    Snubbed oscillation
    Snubbed ringing

    You want to kill the ringing stone cold dead, so pick the snubber resistance equal to the characteristic impedance. That makes it a tank circuit with:

    Q = R sqrt(C / L) = 1

    Which is a pretty low Q, all things considered.

    The scope shot shows the result with an 820 Ω resistor and a 100 nF capacitor: wham, no ringing!

    Notice that the collector voltage is slightly lower immediately after the transistor switches off, as compared to the undamped case, because there’s now some juice going into the RC snubber. The overall converter efficiency will drop and you can trade off Q for efficiency for resistor dissipation in the usual manner.

    Pretty slick, huh?

    Update: you might want to put the snubber directly across the winding in higher-powered systems, to keep the snubber current out of the power supply. In this case it doesn’t matter all that much.

  • Arduino Fast PWM: Faster

    Although you can change the Arduino runtime’s default PWM clock prescaler, as seen there, the default Phase-correct PWM might not produce the right type of output for the rest of your project’s circuitry.

    I needed a fixed-width pulse to drive current into a transformer primary winding, with a variable duty cycle (hence, period) to set the power supply’s output voltage. The simplest solution is Fast PWM mode: the output goes high when the timer resets to zero, goes low when the timer reaches the value setting the pulse width, and remains low until the timer reaches the value determining the PWM period.

    The best fit for those requirements is Fast PWM Mode 14, which stores the PWM period in ICRx and the PWM pulse width in OCRxA. See page 133 of the Fine Manual for details on the WGMx3:0 Waveform Generation Mode bits.

    I needed a 50 μs pulse width, which sets the upper limit on the timer clock period. Given the Diecimila’s 16 MHz clock, the timer prescaler can produce these ticks:

    • 1/1 = 62.5 ns
    • 1/8 = 500 ns
    • 1/64 = 4 μs
    • 1/256 = 16 μs
    • 1/1024 = 64 μs

    So anything smaller than 1/1024 would work. For example, three ticks at 1/256 works out to 48 μs, which is close enough for my purposes. A 1/8 prescaler produces an exact match at 100 ticks and gives a nice half-microsecond resolution for pulse width adjustments.

    The overall PWM period can vary from 200 μs to 10 ms, which sets the lower limit on the tick rate. The timer is 16 bits wide: 65535 counts must take more than 10 ms. The 1/1 prescaler is too fast at 4 ms, but the 1/8 prescaler runs for 32 ms.

    So I selected the 1/8 prescaler. The table on page 134 gives the CSx2:0 Clock-Select mode bits.

    Define the relevant values at the top of the program (uh, sketch)

    #define TIMER1_PRESCALE 8	// clock prescaler value
    #define TCCR1B_CS20 0x02	// CS2:0 bits = prescaler selection
    
    #define BOOST_PERIOD_DEFAULT	(microsecondsToClockCycles(2500) / TIMER1_PRESCALE)
    #define BOOST_ON_DEFAULT	(microsecondsToClockCycles(50) / TIMER1_PRESCALE)
    
    #define BOOST_PERIOD_MIN	(microsecondsToClockCycles(200) / TIMER1_PRESCALE)
    #define BOOST_PERIOD_MAX	(microsecondsToClockCycles(10000) / TIMER1_PRESCALE)
    

    The microsecondsToClockCycles() conversion comes from the Arduino headers; just use it in your code and it works. It’ll give you the right answer for 8 MHz units, too, but you must manually adjust the timer prescaler setting; that could be automated with some extra effort.

    Then, in the setup() routine, bash the timer into its new mode

    analogWrite(PIN_BOOSTER,1);	// let Arduino setup do its thing
    TCCR1B = 0x00;			// stop Timer1 clock for register updates
    
    TCCR1A = 0x82;			// Clear OC1A on match, Fast PWM Mode: lower WGM1x = 14
    ICR1 = BOOST_PERIOD_DEFAULT;	// drive PWM period
    OCR1A = BOOST_ON_DEFAULT;	// ON duration = drive pulse width
    TCNT1 = BOOST_ON_DEFAULT - 1;	// force immediate OCR1A compare on next tick
    TCCR1B = 0x18 | TCCR1B_CS20;	// upper WGM1x = 14, Clock Sel = prescaler, start running
    

    The Arduino analogWrite() function does all the heavy lifting to set the PWM machinery for normal use, followed by the tweakage for my purposes. All this happens so fast that the first normal PWM pulse would still be in progress, but turning the PWM timer clock off is a nice gesture anyway. Forcing a compare on the first timer tick means the first pulse may be a runt, but that’s OK: the rest will be just fine.

    What you don’t want is a booster transistor drive output stuck-at-HIGH for very long, as that will saturate the transformer core and put a dead short across the power supply: not a good state to be in. Fortunately, the ATmega168 wakes up with all its pins set as inputs until the firmware reconfigures them, so the booster transistor stays off.

    The PWM machinery is now producing an output set to the default values. In the loop() routine, you can adjust the timer period as needed

    noInterrupts();			// no distractions for a moment
    TCCR1B &= 0xf8;			// stop the timer - OC1A = booster may be active now
    
    TCNT1 = BOOST_ON_DEFAULT - 1;	// force immediate OCR1A compare on next tick
    ICR1 = BasePeriod;		// set new PWM period
    
    TCCR1B |= TCCR1B_CS20;		// start the timer with proper prescaler value
    interrupts();			// allow distractions again
    

    The ATmega168 hardware automagically handles the process of updating a 16-bit register from two 8-bit halves (see page 111 in the Manual), but you must ensure nobody else messes with the step-by-step process. I don’t know if the compiler turns off interrupts around the loads & stores, but this makes sure it works.

    Once again, setting the TCNTx register to force a compare on the next timer tick will cause a runt output pulse, but that’s better than a stuck-HIGH output lasting an entire PWM period. You can get fancier, but in my application this was just fine.

    You can update the PWM pulse width, too, using much the same hocus-pocus.

    And that’s all there is to it!

    Memo to Self: always let the Arduino runtime do its standard setup!

  • Reading a Quadrature Encoded Knob in Double-Quick Time

    The simple technique of reading a quadrature knob I described there works fine, except for the knob I picked for a recent project. That’s what I get for using surplus knobs, right?

    I picked this knob because it has a momentary push-on switch that I’ll be using for power; the gizmo should operate only when the knob is pressed. The rotary encoder part of the knob has 30 detents, but successive “clicks” correspond to rising and falling clock edges: the encoder has only 15 pulses in a full turn.

    So, while advancing the knob counter on, say, the falling edges of the A input worked, it meant that the count advanced only one step for every other click: half the clicks did nothing at all. Disconcerting, indeed, when you’re controlling a voltage in teeny little steps.

    Worse, the encoder contacts are painfully glitchy; the A input (and the B, for that matter) occasionally generated several pulses that turned into multiple counts for a single click.

    Fortunately, the fix for both those problems is a simple matter of software…

    The Arduino interrupt setup function can take advantage of the ATmega168’s ability to generate an interrupt on a pin change, at least for the two external interrupts that the Arduino runtime code supports. So it’s an easy matter to get control on both rising & falling edges of the A input, then make something happen on every click of the knob as you’d expect.

    The hardware is straightforward: connect the knob’s A output to INT0, the B  output to D7, and the common contact to circuit ground. Although you can use the internal pullups, they’re pretty high-value, so I added a 4.7 kΩ resistor to Vcc on each input. The code defining that setup:

    #define PIN_KNOB_A	2			// LSB - digital input for knob clock (must be 2 or 3!))
    #define IRQ_KNOB_A	(PIN_KNOB_A - 2)	//  set IRQ from pin
    #define PIN_KNOB_B	7			// MSB - digital input for knob quadrature
    

    Because we’ll get an interrupt for each click in either direction, we can’t simply look at the B input to tell which way the knob is turning. The classy way to do this is to remember where we were, then look at the new inputs and figure out where we are. This buys two things:

    • Action on each edge of the A input, thus each detent
    • Automatic deglitching of crappy input transitions

    So we need a state machine. Two states corresponding to the value of the A input will suffice:

    enum KNOB_STATES {KNOB_CLICK_0,KNOB_CLICK_1};

    A sketch (from one of these scratch pads) shows the states in relation to the knob inputs. Think of the knob as being between the detents for each state; the “click” happens when the state changes.

    Knob encoder states and inputs
    Knob encoder states and inputs

    In order to mechanize that, put it in table format. The knob state on the left shows where the knob was and the inputs along the top determine what we do.

    Knob state table
    Knob state table

    So, for example, if the knob was resting with input A = 0 (state KNOB_CLICK_0), then one detent clockwise means the inputs are 01. The second entry in the top row has a right-pointing arrow (→) showing that the knob turned clockwise and the next state is KNOB_CLICK_1. In that condition, the code can increment the knob’s position variable.

    The entries marked with X show glitches: an interrupt happened, but the inputs didn’t change out of that state. It could be due to noise or a glitchy transition, but we don’t care: if the inputs don’t change, the state doesn’t change, and the code won’t produce an output. Eventually the glitch will either vanish or turn into a stable input in one direction or the other, at which time it’s appropriate to generate an output.

    Two variables hold all the information we need:

    volatile char KnobCounter = 0;
    volatile char KnobState;
    

    KnobCounter holds the number of clicks the knob has made since the last time the mainline code read the value.

    KnobState holds the current (soon to be previous) state of the A input.

    Now we can start up the knob hardware interface:

    pinMode(PIN_KNOB_B,INPUT);
    digitalWrite(PIN_KNOB_B,HIGH);
    pinMode(PIN_KNOB_A,INPUT);
    digitalWrite(PIN_KNOB_A,HIGH);
    KnobState = digitalRead(PIN_KNOB_A);
    attachInterrupt(IRQ_KNOB_A,KnobHandler,CHANGE);
    

    An easy way to handle all the logic in the state table, at least for small values of state table, is to combine the state and input bits into a single value for a switch statement. With only eight possible combinations, here’s what it the interrupt handler looks like:

    void KnobHandler(void)
    {
    byte Inputs;
    	Inputs = digitalRead(PIN_KNOB_B) << 1 | digitalRead(PIN_KNOB_A);	// align raw inputs
    	Inputs ^= 0x02;								// fix direction
    
    	switch (KnobState << 2 | Inputs)
    	{
    	case 0x00 : // 0 00 - glitch
    		break;
    	case 0x01 : // 0 01 - UP to 1
    		KnobCounter++;
    		KnobState = KNOB_CLICK_1;
    		break;
    	case 0x03 :	// 0 11 - DOWN to 1
    		KnobCounter--;
    		KnobState = KNOB_CLICK_1;
    		break;
    	case 0x02 : // 0 10 - glitch
    		break;
    	case 0x04 : // 1 00 - DOWN to 0
    		KnobCounter--;
    		KnobState = KNOB_CLICK_0;
    		break;
    	case 0x05 : // 1 01 - glitch
    		break;
    	case 0x07 : // 1 11 - glitch
    		break;
    	case 0x06 :	// 1 10 - UP to 0
    		KnobCounter++;
    		KnobState = KNOB_CLICK_0;
    		break;
    	default :	// something is broken!
    		KnobCounter = 0;
    		KnobState = KNOB_CLICK_0;
    	}
    }
    

    Reading the knob counter in the main loop is the same as before:

    noInterrupts();
    KnobCountIs = KnobCounter;	// fetch the knob value
    KnobCounter = 0;		//  and indicate that we have it
    interrupts();
    

    And that’s all there is to it!

  • Reading a Quadrature Knob

    Most analog projects will benefit from an adjustment knob; the notion of pressing those UP and DOWN arrows just doesn’t give that wonderful tactile feedback. These days “knob” means a rotary encoder with quadrature outputs and some software converting digital bits into an adjustment value.

    Sounds scary, doesn’t it?

    This is actually pretty simple for most microcontrollers and the Arduino in particular. The Arduino website has some doc on the subject, but it seems far too complicated for most projects.

    A quadrature rotary encoder has two digital outputs, hereinafter known as A and B. The cheap ones are mechanical switch contacts that connect to a common third terminal (call it C), the fancy ones are smooth optical interrupters. You pay your money and get your choice of slickness and precision (clicks per turn). I take what I get from the usual surplus sources: they’re just fine for the one-off projects I crank out most of the time.

    How does quadrature encoding work?

    On each falling edge of the A signal, look at the B signal. If it’s HIGH, the knob has turned one click thataway. If it’s LOW, the knob has turned one click the other way. That’s all there is to it!

    Here’s how you build a knob into your code…

    Connect one of the outputs to an external interrupt, which means it goes to digital input D2 or D3 on the Arduino board. The former is INT0, the latter INT1, and if you need two interrupts for other parts of your project, then it gets a lot more complex than what you’ll see here. Let’s connect knob output A to pin D2.

    Connect the other output, which we’ll call B, to the digital input of your choice. Let’s connect knob output B to D7.

    Define the pins and the corresponding interrupt at the top of your program (yeah, in Arduino-speak that’s “sketch”, but it’s really a program):

    #define PIN_KNOB_A 2			// digital input for knob clock (must be 2 or 3!))
    #define IRQ_KNOB_A (PIN_KNOB_A - 2)	//  set IRQ from pin
    #define PIN_KNOB_B 7			// digital input for knob quadrature
    

    The external circuitry depends on whether you have a cheap knob or fancy encoder. Assuming you have a cheap knob with mechanical contacts, the C contact goes to circuit common (a.k.a, “ground”). If you have a fancy knob with actual documentation, RTFM and do what it say.

    The two inputs need resistors (“pullups”) connected to the supply voltage: when the contact is open, the pin sees a voltage at the power supply (“HIGH“), when it’s closed the voltage is near zero (“LOW“).

    Ordinary digital inputs have an internal pullup resistor on the ATmega168 (or whatever the Arduino board uses) that will suffice for the B signal. Unfortunately, the external interrupt pins don’t have an internal pullup, so you must supply your own resistor. Something like 10 kΩ will work fine: one end to the power supply, the other to INT0 or INT1 as appropriate.

    With the knob connected, set up the pins & interrupt in your setup() function:

    attachInterrupt(IRQ_KNOB_A,KnobHandler,FALLING);
    pinMode(PIN_KNOB_B,INPUT);
    digitalWrite(PIN_KNOB_B,HIGH);
    

    The first statement says that the interrupt handler will be called when the A signal changes from HIGH to LOW.

    The Arduino idiom for enabling the chip’s internal pullup on a digital input pin is to define the pin as an input, then write a HIGH to it.

    Set up a variable to accumulate the number of clicks since the last time:

    volatile char KnobCounter = 0;

    The volatile tells the compiler that somebody else (the interrupt handler or the main routine) may change the variable’s value without warning, so the value must be read from the variable every time it’s used.

    The variable’s size depends on the number of counts per turn and the sluggishness of the routine consuming the counts; a char should suffice for all but the most pathological cases.

    Define the handler for the knob interrupt:

    void KnobHandler(void)
    {
        KnobCounter += (HIGH == digitalRead(PIN_KNOB_B)) ? 1 : -1;
    }
    

    KnobHandler executes on each falling edge of the A signal and either increments or decrements the counter depending on what it sees on the B signal. This is one of the few places where you can apply C’s ternary operator without feeling like a geek.

    Define a variable that will hold the current value of the counter when you read it:

    char KnobCountIs, Count;
    

    Now you can fetch the count somewhere in your loop() routine:

    noInterrupts();
    KnobCountIs = KnobCounter;	// fetch the knob value
    KnobCounter = 0;		//  and indicate that we have it
    interrupts();
    

    Turning interrupts off while fetching-and-clearing KnobCounter probably isn’t necessary for a knob that will accumulate at most one count, but it’s vital for programs that must not lose a step.

    Now you can use the value in KnobCountIs for whatever you like. The next time around the loop, you’ll fetch the count that’s accumulated since the previous sample.

    Even if you RTFM, apply painstaking logic, and wire very carefully, there’s a 50% chance that the knob will turn the wrong way. In that case, change one of these:

    • In the interrupt handler, change HIGH to LOW
    • In the attachInterrupt() statement, change FALLING to RISING

    There, now, wasn’t that easy? Three wires, a resistor, a dozen lines of code, and your project has a digital quadrature knob!

    If you have a painfully slow main loop, the accumulated counts in KnobCounter could get large. In that case, this code will give you a rubber-band effect: the accumulated count can be big enough that when the knob starts turning in the other direction it’s just decreasing the count, not actually moving count to the other side of zero. Maybe you need some code in the interrupt handler to zero the count when the direction reverses?

    But that’s in the nature of fine tuning… twiddle on!

  • Analon Slide Rule

    Whenever I do anything even slightly out of the ordinary with magnetics, I must drag out my trusty Analon slipstick to make sure I haven’t lost a dimension.

    Analon slide rule - front
    Analon slide rule – front

    Go ahead, you verify that the area inside a BH hysteresis curve is proportional to power loss in a given transformer core. I’ll wait…

    Analon slide rule - back
    Analon slide rule – back

    My recollection is that I bought it in the Lehigh University Bookstore in the early 70s, but that doesn’t square up with the Analon’s history: they should have been out of circulation by then. I’m pretty sure I didn’t get it in high school, extreme geek though I was, and it’s for damn sure I wouldn’t have bought one after graduation. Come to think of it, if the LU Bookstore wasn’t among the last bastion of Analon holdouts, where would you look?

    Over the decades I’ve penciled in a few handy dimensions they didn’t think of. Unlike most of the 600 597 (plus one in the Smithsonian) Analons in the wild, this one actually gets used, so it’s not New-In-Box (which means you collectors need not suffer from involuntary hip motions). It’s also not as grubby as it looks: I didn’t spend a lot of time futzing with the scans.

    Anyway, that’s called beausage and it enhances the value.

    Works that way with other antiques, right?

    Links:

    Yeah, OK, it’s a Slide Rule Gloat…