Build a Custom 8-Bit Absolute Linear Encoder with SPI
2026-09-02
Linear encoders are invaluable for detecting position or motion along a straight path and are powerful in robotics, automation, or even experimental CNC applications. An absolute encoder in combination with a code strip provides physical position data. There is no need for homing or bogging down a controller with extra tasks like counting tick marks or indexing pulses because each position has a unique location value.
This tutorial steps through building a custom, 8-bit, absolute linear encoder using an array of infrared reflective sensors, comparators, a shift register for data collection, and delivery over SPI protocol.
Working principle
- Sensing Reflected Light
A linear code strip with 9 rows of black and white segments is scanned by a moving column of reflective sensors. Each sensor’s output varies depending on how much reflected light it receives from the code strip segments. - Signal Conditioning using Comparators
Since the sensors produce analog signals, comparators with input level thresholds and hysteresis process the analog signals to produce a clean, digital HIGH or LOW compatible with 3.3 V or 5 V logic. - Serializing with a Shift Register
The digital outputs from eight of the comparators are fed directly into the parallel inputs of a common shift register. When the sensors properly align over the segments on the code strip, a ninth sensor pulses the clock input that pushes the parallel bits into the shift register’s data register. - SPI Communication
A microcontroller (MCU) pulls the data from the shift register using the SPI protocol when it receives an interrupt triggered by the falling edge of the ninth sensor. Upon receiving clock pulses from the MCU, the register pushes 8 data bits, one by one, into a serial line back to the MCU.
Building the circuit and designing the schematic in KiCad
The components described in this tutorial have small surface mount footprints. Break-out boards were used to adapt them to DIP headers that are compatible with breadboarding. Substitution with through-hole components is also an option. The full schematic, as shown in Figure 1, was designed in KiCad followed by PCB (printed circuit board) layout and production through DigiKey’s DK Red PCB service.
Figure 1: Full schematic in KiCad. (Source for all images: Don Johanneck)
Sensing Reflected Light with the VCNT2020
The first step is to configure the IR emitter part of the VCNT2020 reflective sensor. Like most LEDs, it needs a current limiting resistor. The operating brightness of the emitter is critical. Current set too low may not provide enough reflected light from a white code strip segment to turn on the transistor. Too much current floods the area with light and may cause the sensor to turn on even when it sees a black segment.
The datasheet for the VCNT2020 suggests 82 ohms as the lowest recommended resistor value which results in maximum brightness. After some experimentation and adjustment of the emitter brightness, a 1.5 kohm current limiting resistor enabled consistent, close-range detection of the smallest white segment on the code strip (Figure 2).
Figure 2: VCNT2020 with dropping resistor.
Next, it’s time to tackle the open collector phototransistor side of the sensor. When reflected light is sufficient to turn on the transistor, current increases as the connection between the collector and ground gets stronger resulting in a proportional decrease in voltage supplied across the pullup resistor. The ground strength through the transistor increases until it is fully on and the output drops to near zero volts. It can take a lot of light to overcome a strong pullup (low resistance or high supply voltage) which reduces overall sensitivity.
Increasing the value of the pullup resistor and adding resistance between the emitter (pin 1) and ground, narrows the output voltage range and positions it near the optimum ON/OFF threshold of the phototransistor which makes it very sensitive to changes in reflected light. Figure 3 shows the emitter to ground resistance is composed of two resistors, R3 and R4, to form a voltage divider with the output between them. R3 also limits output current and R4 pulls the output down.
Figure 3: VCNT2020 with voltage divider output.
For the encoder used in this circuit, experimentation is used to find how much voltage is dropped between the output and ground for the white and black segments. A black segment positioned above the sensor is slowly lowered while observing a voltmeter connected across R4. This process is repeated with a white segment.
Output voltages:
- Black – 1.7 mV to 403 mV
- White – 1.7 mV to 610 mV
Note: Output voltage tests were completed with a 5 V supply, 1 mm sensor to strip gap, and indoor lighting.
Choosing a rough midpoint value of 500 mV, the logic output is now defined. Voltages less than 500 mV are a LOW (black) and anything equal to or greater than 500 mV is a HIGH (white) output. Adjusting R2, R3, and R4 provides any range of output values and sensitivity level desired though calculation or experimentation.
Be aware that making a super sensitive output invites unwanted results when excessive ambient light noise is present. Adding light pollution to the experiment using a smart phone flashlight proved that R2, R3, and R4 increased sensitivity without opening the door to false triggering. Note that the values in the full schematic may be different than the example due to additional tuning.
Signal conditioning
So far, it has been established that any output above 500 mV is considered HIGH. In the realm of 5 V logic enjoyed by shift registers and microcontrollers, 500 mV is logically LOW. One solution to this problem would be to add a bipolar junction transistor (BJT) to amplify the output to 2.7 V or higher (Figure 4). This approach works well in many cases but may result in “jitter” or output voltage jumping above and below the threshold until the phototransistor of the sensor is sufficiently turned on.
Figure 4: VCNT2020 with BJT conditioning.
While a transistor stage can amplify the signal, it does not provide the well-defined switching thresholds and hysteresis available from a comparator like the TLV7031. Comparators accomplish stable output by monitoring a set voltage reference input and using hysteresis to remove jitter. It compares the voltage from the phototransistor to the reference and sets its output HIGH when the input voltage is equal to or greater than the reference voltage (Figure 5).
Figure 5: VCNT2020 with comparator.
The TLV7031 comparator has 25 mV of built-in hysteresis which prevents the output from transitioning back and forth between logic states when there are small fluctuations of the input voltage. When the input reaches 500 mV and the output transitions from LOW to HIGH, the input could dip down to 488 mV (500 mV - 12.5 mV) before the output transitions back to LOW.
Logic HIGH hysteresis can be increased using a feedback loop from the comparator’s output back to the input through a high value resistor. To understand more how hysteresis effects output, experiment by changing the feedback resistor value. Example: Reducing the resistance too much may add enough hysteresis to latch the output HIGH following a LOW to HIGH transition and cannot be turned off unless the feedback is removed.
Adding an LED and current limiting resistor to the output helps to visualize the transition from HIGH to LOW (Figure 6). Using an oscilloscope or multimeter at the output during experimentation will also help to visualize the interactions between the sensor and the comparator. Because the output of a TLV7031 comparator is push-pull, the only values at the output must be near the supply voltage or ground levels. Any other voltage, like 2.5 V, means the output is rapidly turning on and off which requires more tuning of the comparator input or the output data will be unreliable.
Figure 6: VCNT2020 with comparator and LED.
Data collection and SPI
With accurate HIGHs and LOWs defined, each comparator output is then connected to one input pin of a 74HC597D shift register that can store eight parallel input values as shown in Figure 7. When directed by a transfer clock pulse, the register delivers the data over a single wire to a microcontroller. Because the 74HC597 has pins for serial data and a transfer clock input, SPI communication is easily implemented. Prior to the transfer of data, the normally HIGH PL pin is pulled LOW to temporarily block new data while the old data is in transfer. The 8 bits of transferred data is read by the microcontroller as a number that represents the actual position of the sensors (absolute).
Note: The eight bit on D7 is labeled “QUAD” rather than “OS7” in this example which refers to quadrature detection in a dual encoder XY gantry system.
Figure 7: Detector circuits and parallel to serial shift register with SPI outputs for MCU.
A ninth sensor and comparator detect an additional row of evenly-spaced narrow segments that pulse the register’s shift input (pin 12) automatically on a rising edge when the other eight data sensors are directly over their relative segments. This is the event that captures the current sensor states into the register. This ninth sensor’s output can also trigger an optional interrupt at the microcontroller on its falling edge telling the MCU that a new position value is available. Using an interrupt allows the microcontroller to ignore the sensor when there is no change in position.
Note: While many commercial absolute encoders use Gray code to minimize transition errors, this project uses a binary-coded strip because the sensor positions are synchronized by the ninth "bit loader" channel.
Designing the linear code strip
An 8-bit code provides 256 unique positions. The physical resolution depends on the printed strip length divided by the number of encoded positions. A normal code strip is shown in Figure 8. For the DigiKey Spork-A-Veyor project, for example, the strip starts at 0 on the left end and increments to 100 on the right with a slight twist. The final encoder PCB design staggers the sensors to provide extra room for assembly so the code strip has the same offset of the tick marks (Figure 9).
Figure 8: Normal code strip layout with binary numbers represented in vertical columns.
Figure 9: Code strip layout with binary numbers represented in staggered columns.
For another project, the encoder needed to detect location on a Cartesian coordinate system. The center of the strip is at zero with increasing numbers to the left and right representing the x-axis. To determine above or below zero, the eight bit is used as a quadrant value (Figure 10). Above zero is quadrant 1 or 4 (positive values) and below is quadrant 2 or 3 (negative values). Adding another sensor and code strip for the Y-axis provides a fully navigable Cartesian mapping system.
Figure 10: Code strip layout for cartesian navigation with zero at the center.
The completed coder assembly, shown in Figure 11, is attached to a motion system that passes over the code strip. The LEDs and PCB labels indicate what the sensors see on the back side of the PCB and what information is passed to the MCU through the SPI interface. In operation, every time the “Bit Loader” LED turns on, the data indicated by the above LEDs is stored in the shift registers output memory. When the “Bit Loader” LED turns OFF, a signal is sent to the MCU to pass the data in the shift registers output register into a designated MCU register.
Figure 11: Absolute Linear Encoder in operation.
Conclusion
Absolute encoders provide accurate position values with high repeatability and accuracy. They are useful for position detection and detecting stalls in the motion system. They require no calibration and survive total loss of power. Once power is restored, they report their current position accurately without homing or recalibration.
Components required:
- 9× Phototransistors (e.g., VCNT2020)
- 9× Comparators (e.g., TVL7041 & tvl7031)
- 1× 8-bit Shift Register (e.g., 74HC597D)
- Microcontroller with SPI capability
- Voltage reference or resistive divider for comparator thresholds
- Encoding strip (e.g., Printed or engraved black/white pattern)
- PCB
Descargo de responsabilidad: Las opiniones, creencias y puntos de vista expresados por los autores o participantes del foro de este sitio web no reflejan necesariamente las opiniones, las creencias y los puntos de vista de DigiKey o de las políticas oficiales de DigiKey.


