The speed of a DC motor is proportional to its average supply voltage, making it easy to vary its speed by varying its supply voltage (This, along with the high speed characteristic of DC motors, is why DC motors are often used in variable speed AC power tools such as corded drills. A DC motor optimized for an AC power supply is called a universal motor.)
Electronic speed controls for DC motors almost always use digital PWM (Pulse Width Modulation) instead of analog current or voltage regulation. PWM speed control works by chopping the supply voltage into a rectangular wave pulse train with a frequency ranging from 1000 to 100,000 pulses per second. By adjusting the duty cycle from 0% (always off) to 100% (always on) we can adjust the average power supply voltage. The inductance of the motor windings smooths the currents flowing through them so that the currents (and therefore the magnetic fields) are smooth and continuous even though the power supply voltage is chopped.
Every different combination of DC motor driver circuit and DC motor has tradeoffs with the PWM pulse rate: Some are more efficient with 1000 Hz pulse trains, other are more efficient with much higher pulse rates. Magnetostriction can cause vibration of the motor driver or motor or both that can produce annoying whine at 1000 Hz but completely silent at 30,000 Hz.
There are several DC motor control signaling patterns. For this class we will always use two digital pins: One digital output for direction and one PWM output pin for speed.
Setting the direction output high with digitalWrite() sets
nominal clockwise rotation (nominal, because it depends on the motor wiring;
swapping the motor power supply wires reverses the direction of rotation).
Setting the PWM output duty cycle sets the average voltage supplied to the
motor and hence its speed.
The Arduino platform provides the misnamed function
analogWrite() to set the PWM duty cycle. That function requires a
digital pin number and a duty cycle value ranging from 0 (0%) to 255
(100%).
Hardware limitations of the ATmega328 microcontroller timer/counter subsystems yield fairly crude PWM services: Only 8 bit resolution on certain digital pins at only a few rather odd frequencies. Other Arduino platforms such as the RP2040/RP2350 and STM32 32-bit microcontrollers have vastly superior hardware PWM support.
The DC motor driver boards that we will use in this class (Cytron MD13S and the
MUNTS-0021) will have Grove
System sockets with DIR on pin 1 (yellow) and PWM
on pin 2 (white). This scheme is compatible with sockets D2 and
D4 on both the Arduino Uno and Nano Grove shields.
Note: DC motors (and especially gearmotors) need a significant amount of power to overcome static friction to begin rotating, meaning that a motor under PWM control might not begin rotating until the PWM duty cycle reaches 30% or more. One trick is to set the duty cycle to 100% for 100 milliseconds to get the motor turning and then set the duty cycle to say 10% for slow rotation.
const int DIR = 4;
const int PWM = 5;
void setup()
{
pinMode(DIR, OUTPUT);
pinMode(PWM, OUTPUT);
digitalWrite(DIR, true); // Clockwise (nominal)
analogWrite(PWM, 255); // Full speed
delay(100);
analogWrite(PWM, 25); // Slow speed
}
void loop()
{
}