EE109 – Spring 2017 Introduction to Embedded Systems

EE109 – Spring 2017: Introduction to Embedded Systems

Lab 10

Pulse Width Modulation


In this lab exercise you will use a rotary encoder to control the generation of a pulse width modulation (PWM) signal from the Arduino Uno. In the first part of this lab we will use an 8-bit Counter/Timer to generate a PWM signal to control the brightness of an LED. The second part of the lab will involve using the higher resolution 16-bit Counter/Timer to generate a more precise PWM signal to control a servo motor. By adjusting the encoder position you'll be able to control the position or speed of the servo.

PWM Control of an LED

The Atmel microcontroller used on the Arduino Uno can generate PWM signals through the use of the Counter/Timer modules. The counter is used to perform two tasks for generating the proper PWM signal. First it has to generate pulses with a constant period. The period of the pulses is independent of the pulse width and is the time from the $0\rightarrow1$ transition of one pulse until the next $0\rightarrow1$ transition. To generate pulses at a fixed period the counter has to count the clock signal until the pulse period has been reached and then reset back to zero and start over.

In the PWM mode we will be using, each period of the pulse is limited to the length of time it takes the counter to count from 0 to 255. The counter simply counts up to the maximum count value and then starts over. The relationship between count value, prescalar and time is given by

$ count = time \times \frac{16Mhz}{prescaler} $

We will use the prescaler to divide the 16Mhz clock by 1024, so the period of our pulses will be

$ 256 = time \times \frac{16Mhz}{1024}$


$ time = 256 \times \frac{1024}{16Mhz} = 16.4msec $

The second task for the counter is to control the width of the pulse. The pulse output goes to the one state at the beginning of the pulse period, then at some point during the pulse period the counter must terminate the pulse by setting the pulse output to zero. The time that the pulse spends in the one state is the pulse width, and varying this width is what controls the brightness of the LED.

The counter can be configured so that at the start of the pulse period (counter = 0) the OC0A output signal, which appears on Arduino port D6 (Port D, pin 6), will go to the high state to start the pulse and then will go back to zero at some point while the counter continues to count to 255. This is called "Fast PWM" mode and is illustrated below. In Counter/Timer0, register "OCR0A" is used to store a value that determines the pulse width by telling the counter when to terminate the pulse. The pulse output will go high at the start of the pulse period and when the counter reaches the value in OCR0A the output signal goes back to zero.

The Program, Part 1

For this lab you should be able to start with a copy of the lab 9 program that uses interrupts to handle the inputs from the rotary encoder. Do the following tasks.

PWM Control of a Servo Motor

The next thing we want to do is use the PWM signal to control a servo motor. Servos are a bit more picky than LEDs about the PWM signals. The LED worked fine with a PWM signal with a duty cycle that varied from 0% to 100%, and the pulse period of 16.4ms seemed to work fine also. A typical servo requires a PWM pulse period of 20ms and the pulse width should only vary between 0.75ms to 2.25ms. The eight-bit timer used above can't generate a pulse with a 20ms period since that would require a count value greater than 255. So for this part of the lab we will use the 16-bit Counter/Timer1.

Counter/Timer1 has two internal 16-bit registers that are used to implement the two tasks described above. In the counter mode we will be using, register "OCR1A" is used to determine the pulse period by storing the value the counter should count to before resetting and repeating. Register "OCR1B" is used to store the value that determines the pulse width by telling the counter when to terminate the pulse. The pulse output will go high at the start of the pulse period (counter = 0) and when the counter reaches the value in OCR1B it will set the pulse output back to zero. The counter then continues to count until it reaches the value in OCR1A. At that point it resets to zero and starts the process over. This is illustrated the figure below. Needless to say, the value in OCR1B should be less than the value in OCR1A. When Counter/Timer1 is used in this mode the pulse output will appear on Arduino port D10 (Port B, bit 2).

The Program, Part 2

Before modifying your program to control the servo motor, make a copy of your lab10.c just in case you have to go back to it for some reason. For the second part of the lab, the following tasks will need to be done.

To confirm that the pulses are being created as specified, use an oscilloscope to look at the pulses on the OC1B output (Arduino port D10). You should be able to see the pulse width change as you rotate the encoder. Check to make sure that

You must demonstrate your working PWM signals by showing them on an oscilloscope to an instructor. Only then will you be issued a servo motor. When connecting the motor to your Arduino, first disconnect the power to your Arduino before connecting the motor. The cable to the motor has a three conductor connector with three wires going into it, red for power, black for ground and white for the PWM signal. Using a piece of breadboard hookup wire, make a connection from the $+5V$ on the Arduino to the red wire by inserting the end of the wire into the connector socket for the red wire as shown in below. Do the same to connect the Arduino ground to the black wire, and from the D10 output pin to the white wire.

Once you reconnect the power to your Arduino the motor should move to the initial position as set by your PWM signal. Try rotating the encoder knob and see if the motor responds correctly. For a standard servo, check to see that you can move the motor through an arc of about 180 degrees. For a continuously rotating motor, check you can make it rotate at full speed in either direction, and also stop the rotation.


Once you have the assignments working demonstrate them to one of the instructors. Turn in a copy of the source code from the second part of the lab assignment through the link on the class web site.