Problem
Build a closed-loop speed controller for a 12 V brushed DC motor using only an 8051-family MCU, a DIP switch for setpoint, a quadrature encoder for feedback, and a 7-segment readout. The teaching goal was understanding PWM, interrupt timing, and the bare-metal limits of an 8-bit MCU.
Approach
A proportional controller (P-only by design — the lab exercise was to discover the steady-state offset and reason about adding I and D). PWM at 1 kHz generated by Timer 0 in a 256-step duty cycle. Encoder ticks counted on the external interrupt and decimated into a speed sample every 50 ms.
Implementation
Programmed in a mix of C and 8051 assembly: C for the control loop, assembly for the time-critical PWM duty update so I could guarantee single-cycle accuracy. The L293D drives the motor; the 8-position DIP sets a 0–255 speed setpoint that maps to 0–100 percent. The full firmware was simulated in Proteus before bring-up; oscilloscope confirmed the PWM duty matched the calculation within one timer tick.
Speed step response (setpoint = 60 percent)
Results
Step response from 0 to 60 % settled in roughly 0.8 s with a steady-state error of ~0 % under no load. Under load, P-only left a visible 3–4 % droop, which made the case for a follow-up PI implementation in the next lab.
Lessons
The exercise made a lasting point about real-time determinism: a P controller on a 12 MHz 8051 felt instantaneous because the loop time was tiny relative to the motor mechanical time constant. The same algorithm on a slow loop would have oscillated.
Gallery

