2026-06-20
Rotary encoders convert shaft rotation into electrical pulses, giving you incremental position and direction information. Unlike potentiometers, they rotate continuously with no end stops and don't wear out a resistive element. They're everywhere: motor shafts, CNC handwheels, volume knobs, printer carriages, and robot joints.
The quadrature trick. An incremental encoder has two output channels, A and B, that produce square waves 90° out of phase. The phase relationship encodes direction: if A leads B, the shaft turns clockwise; if B leads A, counterclockwise. The pulse count encodes distance. A third channel, Z (index), pulses once per revolution for absolute reference.
Two physical flavors. Optical encoders use an LED and photodetectors reading through a slotted disk — high resolution (thousands of counts/rev), but sensitive to dust. Magnetic encoders use Hall sensors reading a multi-pole magnet — rugged, cheap, and immune to contamination, but lower resolution.
Decoding with hardware. Reading quadrature in software with polling is fragile: miss an edge and your count drifts forever. Use either a dedicated quadrature decoder peripheral (most ARM Cortex-M MCUs have one in their timer block — STM32's TIM1/2/3/4 all support "encoder mode") or pin-change interrupts on both A and B. The classic state machine looks at the previous and current (A,B) state — only 4 valid transitions exist per direction, anything else is noise or a missed edge.
4x decoding. If your encoder is rated at 1024 PPR (pulses per revolution), you actually get 4096 counts/rev by counting every edge on both A and B. That's free resolution — always enable 4x mode in your decoder peripheral.
Debouncing the cheap ones. The $1 mechanical detent encoders found in volume knobs bounce horribly — 1-5 ms of contact chatter per detent. Add a 10 nF cap from each output to ground and a 10 kΩ pull-up. The RC time constant (100 µs) filters bounces while passing legitimate edges. For high-speed optical encoders, skip the RC filter — it'll eat your pulses.
Real-world example. A NEMA 17 stepper motor with a 1000 PPR optical encoder on its shaft, driving a 5 mm pitch leadscrew. After 4x decoding: 4000 counts/rev × 1 rev/5 mm = 800 counts/mm, or 1.25 µm per count. That's machinist-grade positioning feedback with an STM32 timer doing all the decoding work in hardware — your firmware just reads TIM2->CNT whenever it wants the current position.
Maximum frequency rule of thumb. Your decoder must sample faster than 4× the highest expected edge rate. At 3000 RPM with a 1000 PPR encoder: 50 rev/s × 4000 edges/rev = 200 kHz edge rate. Hardware peripherals handle this easily; pin-change ISRs on an 8-bit AVR will choke.
