PWM on Arduino

I’ve spent a lot of time recently talking about different aspects of PWM and filtering. Today I’d like to take a step back from the theory and build what you might call the “Hello World” of digital synthesis, generating PWM signals with an Arduino. This should be a fairly straightforward project but will give me a vehicle to start experimenting with pulse width modulation in a more concrete setting.

Wiring It Up

Arduino PWM Circuit

The wiring for this one is pretty simple. On one side of the Arduino I’ve placed a 10K potentiometer between 5V and ground with the wiper connected to pin A0. This is the analog input that I will use to set the duty cycle of my pulse. The potentiometer will function as a basic voltage divider allowing us to control the voltage at the pin (between 0 and 5V).

On the other side of the Arduino we find the digital pins. These are where we can output our PWM signal. You’ll notice some of the pins (3, 5, 6, 10 and 11) have a tilde beside them. These are the pins capable of outputting PWM signals. An additional consideration is that Arduino UNO boards offer two different PWM frequencies. Pins 3, 10 and 11 output PWM at 490Hz while pins 5 and 6 output 980Hz. For this project I’ll be connecting my scope to pin 5 to read a signal output at that pin.

Writing The Code

The code for this project should be pretty straight forward as well. I’m writing it using the Arduino IDE which is available free from the Arduino website. I’m going to break it into a few sections and explain each one.

int duty_cycle_in = A0;
int PWM_out = 5;

int duty_cycle;

The first step is to declare a few variables. Here we define our duty cycle control to be at pin A0 and our PWM output to be at pin 5. This step can be skipped if you refer to the pins directly when you use them in your program however as your code grows this can make things really confusing. For the sake of keeping clear and concise code I always alias my pins in this way.

Additionally I create an integer variable to store the duty cycle. This variable will be updated with a value from duty_cycle_in and be used to write the PWM signal to PWM_out.

void setup() {
  pinMode(PWM_out, OUTPUT);
  pinMode(duty_cycle_in, INPUT);
}

Next up is our setup function. This function will run once when the Arduino powers on before moving into the main loop. Here we call the pinMode function twice. This function tells the Arduino what kind of information to expect from/send to each pin. We set PWM_out (pin 5) as an output and duty_cycle_in (pin A0) as an input.

void loop() {
  duty_cycle = analogRead(duty_cycle_in)/4;
  analogWrite(PWM_out, duty_cycle);
}

Finally we come to the main loop of the program. This is where the magic happens, the main loop is the code which runs on a repeating cycle as long as the Arduino is powered on.

The first step is to read from the duty_cycle_in pin (A0) and store that value into the duty_cycle variable. Notice that I divide the result by 4, this has to do with a difference in resolution between the analog input pins and PWM output pins. the analogRead function returns a value between 0 and 1023 depending on where the voltage falls between 0V and 5V. Meanwhile the analogWrite takes a value between 0 (always off) and 255 (always on). To deal with this discrepancy we simply divide the input by 4 to bring it from 0-1023 down to 0-255.

Next we take that duty_cycle value and write it to the PWM_out pin using analogWrite. together these two lines mean the Arduino will be constantly checking the value at the potentiometer and writing that value to the PWM pin as a duty cycle (with an average voltage equal to the value read from the potentiometer).