Skip to main content
emobility.academy
B.Tech / BEMotor controlBeginner About 4 weeksKit + add-ons

PWM Speed and Direction Control of a DC Motor with Throttle Input

Build an EV-style throttle controller that reads the potentiometer as a throttle pedal and drives a small DC motor with PWM, with forward and reverse selection. The LCD shows throttle and duty cycle, and safety rules stop direction changes while the motor is driven.

Uses: PWM · ADC · GPIO

The problem

Every EV motor controller turns a driver's throttle position into a power command. Doing it safely means filtering noisy sensor input, mapping it sensibly, never reversing a moving motor abruptly and refusing to start if the throttle is already pressed.

Objectives

  • Generate a 20 kHz PWM signal with a hardware timer and vary its duty cycle
  • Read the potentiometer through the ADC with filtering and dead-band
  • Control direction through the motor driver with a zero-duty interlock
  • Show throttle, duty and direction on the 16×2 LCD

What you need

From the EV Embedded Development Kit

  • STM32F103C8T6 microcontroller unit (Arm Cortex-M3)
  • Motor driver for PWM motor-control experiments
  • Analog potentiometer input
  • 4×3 matrix keypad
  • 16×2 LCD
  • RGB LEDs and a buzzer

Software

  • STM32CubeIDE with HAL TIM, ADC and GPIO
  • Embedded C
  • Proteus (optional) to simulate the PWM and H-bridge before hardware

Extra parts

  • A small brushed DC motor within the motor driver's rating — The kit has a motor driver but no motor.

Key concepts

PWM duty cycle
Switching the motor voltage on and off quickly and varying the on-time fraction sets the average voltage, and so the motor speed.
PWM frequency
At 72 MHz with prescaler 0 and auto-reload 3599, the timer gives 20 kHz, which is above hearing and smooth for a small motor.
Throttle dead-band
A small zone at the bottom of the pot travel is treated as zero so noise does not creep the motor when the pedal is released.
Direction interlock
Reversing a spinning motor causes current spikes; the controller only changes direction when the duty is zero and the motor has been stopped for a short time.

Step-by-step guide

  1. 1

    List requirements

    Write down the behaviour before coding. Throttle 0–100% maps to duty 0% up to a set maximum; anything below 5% counts as zero. Keypad 1 selects forward, 3 reverse and # stops. Direction may change only at zero duty after a 500 ms wait, and the motor must not start if the throttle is above 5% at power-up. Note the motor's rated voltage and the kit motor driver's rating from its documentation, and make sure the motor you buy fits inside it.

    Checkpoint: A written requirement list and a state diagram (Off, Ready, Drive Forward, Drive Reverse, Fault).

  2. 2

    Set up the board

    Set the DIP switches to connect the motor driver, potentiometer, keypad and LCD. In CubeMX set a 72 MHz clock, configure one timer channel in PWM mode on the pin wired to the driver's PWM input, two GPIO outputs for the driver's direction inputs (check the schematic for how the driver is controlled), ADC1 on the pot pin and GPIOs for keypad rows and columns.

    Checkpoint: The project builds and an LED blinks, confirming clock and pin setup.

  3. 3

    Generate the PWM

    Set the timer prescaler to 0 and the auto-reload register to 3599, which gives 72 MHz divided by 3600, or 20 kHz. Start the channel with HAL_TIM_PWM_Start and change the duty at run time with __HAL_TIM_SET_COMPARE, where a compare value of 1800 is 50%. Before connecting the motor, check the output on an LED or an oscilloscope at 0%, 25%, 50% and 100% duty, and confirm the pin really is the one wired to the motor driver's PWM input.

    Checkpoint: The measured frequency is 20 kHz and duty steps match the compare values.

  4. 4

    Read the throttle

    Configure ADC1 for continuous conversion on the potentiometer channel with DMA, started with HAL_ADC_Start_DMA, and choose a long sample time because the pot has a high source impedance. Average the last 16 samples, apply the 5% dead-band and scale the 12-bit result to 0–1000 per mille so later maths stays in integers. Print raw and filtered values on the UART console and check both ends of the pot travel, since many pots do not reach exactly 0 or 4095.

    Checkpoint: Turning the pot from end to end gives a smooth 0–1000 output and the released position reads exactly zero.

  5. 5

    Scan the keypad

    Drive one keypad row low at a time with the others high, and read the columns with pull-up inputs; a low column means that key is pressed. Scan every 10 ms from the control timer and accept a key only after it reads the same on two consecutive scans, which gives about 20 ms of debounce. Map keys to forward, reverse and stop commands, and beep the buzzer briefly for each accepted key so the user knows it registered.

    Checkpoint: Each key press gives exactly one command on the console, with no double triggers.

  6. 6

    Implement the state machine

    Code the states from your requirement list: Off, Ready, Drive Forward, Drive Reverse and Fault. In Ready the duty is always zero; a direction key moves to Drive only if the throttle is at zero. Changing direction while driving forces duty to zero, waits 500 ms, then switches the direction pins. Any unexpected input or out-of-range reading moves to Fault, which needs the stop key and zero throttle to clear. Write the transition table in your report alongside the code.

    Checkpoint: Trying to reverse while the throttle is pressed is refused and the LCD says why.

  7. 7

    Connect the motor and integrate

    Connect the motor to the driver output and power it as the kit's motor-driver block specifies, not from an arbitrary supply. Run the control loop at 100 Hz from a timer interrupt: read the filtered throttle, update the state machine, then set the duty. Update the LCD at 5 Hz with throttle %, duty % and direction, because writing to the LCD every loop wastes time. Set the RGB LED green for forward, blue for reverse and red for fault.

    Checkpoint: The motor speed follows the throttle smoothly in both directions and the LCD values update without flicker.

  8. 8

    Test the safety rules

    Write a test list and run it methodically: power up with the throttle already pressed, try to reverse while driving, press keys rapidly, hold the pot at both extremes, and press stop at full throttle. For each test record the expected behaviour, what actually happened, and pass or fail. Fix any failure, then rerun the whole list rather than just the failed test, because a fix in a state machine can break another transition.

    Checkpoint: Every test passes, or the failure is fixed and retested.

  9. 9

    Document

    Write a short report covering the PWM frequency calculation, the ADC scaling and filtering, the state machine with its transition table, and the safety test results. Include photos of the setup and a short video showing normal driving and each interlock being triggered. Close with a paragraph explaining how this maps to a real EV controller's throttle handling, and what a production controller adds, such as current limiting, a second throttle track and speed feedback.

    Checkpoint: A short report and a demonstration video of normal driving and the interlocks.

Testing & validation

  • PWM frequency and duty measured on an oscilloscope or by timer capture
  • Throttle linearity: pot position versus filtered value
  • Safety test table: start-up interlock, direction interlock, fault handling

Expected results

A DC motor controlled by a throttle pot with smooth PWM, forward and reverse, a start-up throttle check and a direction interlock, with live readings on the LCD.

Take it further

  • Add a soft-start ramp so steps in throttle do not jerk the motor
  • Add an encoder motor and close the speed loop with PID
  • Add drive modes with different throttle maps

Viva and review questions

How did you get 20 kHz PWM?

Timer clock 72 MHz divided by (prescaler 0 + 1) and (auto-reload 3599 + 1) gives 20 kHz.

Why a dead-band on the throttle?

ADC noise near zero would otherwise give a small duty and creep the motor when the pedal is released.

Why stop before reversing?

Reversing a spinning motor applies its back-EMF plus the supply across the winding, causing a large current spike that stresses the driver.

What does the start-up throttle check prevent?

The vehicle lurching forward if the controller powers up while the pedal is already pressed.

Related EV projects

All 100 EV projects