PWM and Servo motor
the tutorial with the most math
Last updated
the tutorial with the most math
Last updated
For controlling the DC motor and servo motor. DC motor: power (speed) Servo motor: angle
If you use GPIO, you can only control the DC motor to be max speed or no speed, or control the Servo motor to be in the leftmost or the rightmost angle. However, sometimes we want the DC motor to be in 50% or 30% speed or move the Servo motor to somewhere in the middle. So, we can use PWM to achieve this.
Pulse Width Modulation(PWM)
Let's say we want to output a 30% power. However, our board is weak and can only output HIGH(100%) and LOW(0%) voltages only. So, instead of trying to output a 30% Voltage, we will output HIGH for 30% of the time and LOW for the remaining 70% of the time.
Then, the average output would be:
100% Voltage *30% time + 0% Voltage *70% time = 30% power.
If the board changes between HIGH and LOW very quickly (i.e. 50 times per second or above), you and the motor cannot see the difference between a 30% output voltage and 30% PWM signal.
REF: ELEC1100 lecture 10 (2022, Deparment of Electronic and Computer Engineering, HKUST)
The output frequency (1/T)
how fast it changes between HIGH and LOW
The on-time (The time of "HIGH voltage")
(Duty Cycle) which is on-time to period ratio
determines the percentage of time it outputs HIGH
in Second
The data-sheet will usually provide the frequency and on-time (pulse) to use. The SG90 servo uses 50 Hz and 1-2ms on-time.
We will also use PWM signal to control a DC motor, which duty cycle implies the output power of the DC motor. For example letting the motor to spin at a lower speed.
Using Timers. (MCU_Clock)
MCU_Clock is the clock that determines the speed of the MCU(or CPU in layman's terms). Our motors don't need to be as fast as the MCU so we have to slow it down.
Frequency of clock (MCU_Clock):
The timer of clock (in our board we are using 84MHz)
Prescaler value(PSC):
to scale down the frequency of the clock
a 16-bit unsigned integer
Auto-reloaded counter(ARR):
to control the output signal
a 16-bit unsigned integer
Frequency of PWM:
The output (or desired frequency) for the motors We are using 50Hz for this servo motor.
Items in red are what we are concerned about
As you can see, when there are 2 peaks in the MCU_Clock, 1 peak in Clock after Prescaler is generated. So the prescaler value must be 2 right? No! As we are programmers, we always count from 0. So, the Prescaler value = 1.
The auto-reload counter in the above example is 36
As you can see, when there are 37 peaks in clock after prescaler, the auto-reload counter increases by 1, when the value is > 36, 1 peak in Counter overflow is generated and the counter is reset to 0. Again, we are programmers, so the auto-reload counter = 36.
On the above picture you can see that the prescaler value and auto-reload counter help reduce the frequency of the MCU_Clock and generate a lower frequency.
The purpose of having both of them is that our MCU runs at a high frequency. If we were to work with servos (assume they require 50Hz) and use only the Prescaler or only the Auto-Reload, we won't be able to reduce to the targeted frequency. That's why we need both.
The difference between the two is that Prescaler value is just aiming to reduce the frequency, while auto-reload counter also aims as a counter.
The prescaler value and Auto-reload counter are limited to a 16-bit unsigned integer only. Thus, the maximum value of both values is 2^16 - 1 = 65535.
After all, how do we get the output frequency???
Frequency of PWM again (demonstrates using code):
I know that no one wants to read the large paragraph above to understand what is happening. It may be easier for us - programmers to understand through actual code.
MCU_Clock frequency = 84MHz (depends on Hardware setup)
Clock_after_prescalar frequency
= Number of times Clock_after_prescalar becomes 1 in a second
Output_Clock frequency
= Number of times Output_Clock becomes 1 in a second
Duty cycle:
According to the figure below, the number on the left-hand side is the duty cycle, it means the percentage of time that a signal is given as "high"(or 5V). i.e.,
By only looking at the picture, you may not understand what is happening. It maybe easier for us - programmers to understand through actual code.
CCRx
means Compare Register. x means the number of channels that we are using.
When the auto-reload counter is smaller than CCRx
, the output PWM will give a HIGH value.
The ARR (auto-reload counter) from the previous paragraph is used as a downscaler of clock frequency. But in here, it acts as a denominator and CCRx
acts as an numerator.
There are many combinations of prescaler value and auto-reload counter that can generate the same frequency output. How can we choose a better value?
As you may notice, the ARR acts as a denominator in the Duty Cycle formula, therefore if we want to output a short on-time, we need to have a larger denominator. Notice that both the CCR and ARR have to be a 16-bit unsigned integer.
As a result, Larger Auto-reload Value and Smaller Prescaler Value would be better when outputting a short on-time.
Each pin can use specific timers and timer channels. You can check the configuration of the board from CubeMX to find out which timer and channel to use.
Each timer will only have one prescaler value and one auto-reload counter.
Each timer will have several channels that can output different on-time(compare value). (CCR1, CCR2 ...)
Which means those different channels will share the same prescaler value and auto-reload counter, but have different on-time. So when using motors with different frequencies, you may need a different timer.
There are 4 steps in setting up the PWM output channel and the pin to use.
In catergories, click Timers then choose the timer you want to use.
Setup the Mode same as the figure shown. It's fine if you only get 1 channel.
Set the Parameter Settings same as the figure shown
Supposedly, You don't have to change anything
3. IMPORTANT: Enable the global interrupt of the timer.
Assign the GPIO pin to be the specific timer and channel. e.g Assign the PC7 pin to output the pwm signal of TIM3_CH2.
There are 4 steps in coding:
Initialize the Timers for PWM
This should be implemented in the beginning of
main.c
Set the Prescaler value, Auto-reload counter
Hint: The clock of the board is running at around 84MHz.
Start the Timer (in tutorial3_pwm.c
in pwm_init()
)
Change the CCR as required for the classwork/homework
tutorial3_pwm.c
located in thesrc
file!!Try to control servo motor to turn to -90 degrees-> 0 degrees -> 90 degrees (with a short pause at 0 degrees
Note: for the servo motor we are using, the on-time at -90 degrees should be 0.5ms, and the on-time at 90 degrees should be 2.5ms. Calculate the on-time for 0 degrees on your own.
We are using TIM5 and channel 1
Bonus: control the angle of the motor with a button
If we need a frequency output of 50Hz, what are the 3 possible combinations of prescaler value and auto-reload value? (Given that the clock frequency is 84MHz)
If we need a frequency output of 50Hz and on-time of 0.5ms, what are the possible combinations of prescaler value, auto-reload value, and compare value? (Given that the clock frequency is 84MHz)