Source Code. Projects. Nerd Stuff. Art Stuff.

Analog Output

Just like with input, there might be times when you want a range of outputs other than 0 or 1. In instances like these, we need an analog output. In the event that we want to vary a light source, sound source or device controlled by mechanical transducers (these convert electrical energy into mechanical energy–motors are a good example), we’ll need a variable output. Usually, there is some other component in between the microcontroller and final output device, such as a lighting dimmer, MIDI controller, etc.

Digital microcontrollers such as an Arduino can’t produce a varying voltage, they can only produce a high voltage (in our case 5V) or low (in our case 0V). We need to “fake” an analog voltage by producing a series of voltage pulses at regular intervals, and varying the width of the pulses. This is called pulse width modulation (PWM).

In the graph below, we pulse our pin high (5V) for a set period of time, and pulse it low (0V) for a set period of time. This ratio of the length of time the pin is high (called the pulsewidth) to the time the pin is low is called the duty cycle.

When the duty cycle is 75%, the average voltage is a three-fourths the total voltage, at 50% the average voltage is about half the total voltage, and so on. If we make the duty cycle less than 50% by pulsing for a shorter amount of time than we pause, we get a lower effective voltage. The pulsewidth is usually a very small time, on the order of a few microseconds or milliseconds at most.

Notice in the diagram above, the term digitalWrite() appears, with a number inside the parentheses. This is one of the ways we can modulate pulsewidth on the Arduino.

Method 1

Using analogWrite(), the pins marked PWM (pins 9 – 11 on Arduino) can be pulsed using the analogOut() command, like so:

1
 
1
analogWrite(pin, pulsewidth);
1
 

Pin refers to the pin we’re going to pulse, while pulsewidth is a value from 0 – 255. 0 corresponds to 0 volts, and 255 corresponds to 5 volts (remember the diagrm above, with 0 in the parentheses yielding a 0% duty cycle and 255 yielding a 100% duty cycle. Every change of one point changes the pseudo-analog output voltage by 5/255, or  0.0196 volts.

Method 2

Another way to create a series of pulses is to write your own pulseOut using the pulseOut() function:

void setup() {
  // make pin 13 an output pin. 
  // You'll pulse the LED on this pin:
  pinMode(13, OUTPUT);
}

void loop() {
  // read an analog input, 0 - 1023:
  int pulse = analogRead(0);
  // use that value to pulse an LED on pin 13:
  pulseOut(13, pulse, HIGH);
}

void pulseOut(int pinNumber, int pulseWidth, int state) {
  // only pulse if the pulseWidth value 
  // is greater than 0:
  if (pulseWidth > 0) {
    // if the pulse should be high, go high then low:
    if (state == HIGH) {
      digitalWrite(pinNumber, HIGH);
      delayMicroseconds(pulseWidth);
      digitalWrite(pinNumber, LOW);
      delayMicroseconds(pulseWidth);
    } 
    // if the pulse should be low, go low then high:
    else {
      digitalWrite(pinNumber, LOW);
      delayMicroseconds(pulseWidth);
      digitalWrite(pinNumber, HIGH);
      delayMicroseconds(pulseWidth);
    }
  }
}

 

For most applications, it’s better to use the analogWrite() command, because the microcontroller maintains the PWM even after you give the command.

 

Applications of Analog Output

DC Motor Speed Control

Using a pulseout command, it is possible to vary the speed of a DC motor. You use the same transistor circuit that turns the motor on anf off, but instead of setting the pin output high or low, you pulse it instead. There is a Lab on Servo/Motor control, if you want more information on controlling DC motors. Experiment with the pulse frequencies, you’ll find that different ranges produce a variety of results, but a good range to start with is between 0.0002 to 0.02. At the base of the transistor, a varying voltage causes the current flow to vary through the motor, and it spins at a variable rate.

LED dimming

You can use pulseOut() to dim an LED. However, an LED responds to the changing voltage much faster than a motor does, and as the pulsewidth gets greater, you will notice the LED actually going on and off rather than dimming. A low-pass filter circuit will smooth this somewhat, by only allowing frequencies of a certain frequency to pass (in this instance, the low-pass filter only allows low frequencies to pass, and blocks those above a certain range). This means that if the voltage is changing more than a certain number of times per second, these changes would not make it past the filter, and only an average voltage would be seen.

Let’s take our pulseout as an example. With a pulsewidth of 1 millisecond, our voltage is going from high to low 1000 times a second. The frequency is 1000 changes a second, or 1000 Hertz (Hz). If we had a filter circuit that blocked frequencies above 1000 Hz, we would see only an average voltage on the other side of the filter, instead of the pulses.

A basic low-pass filter consists of a resistor and a capacitor, connected like so:

The image above represents a general case for low-pass filters, but the ratio of frequency blocked to capacitance is both complex and subtle. If you’re dimming an LED, start with a 10µf capacitor and a 220-ohm resistor, and experiment with different values from there to see what works best.

Tone generation

Arduino has a command called freqout() that allows you to generate a tone from any of the I/O pins. When a speaker or amplifier is connected properly to the pins, the tone can be heard. The syntax for this function is:

1
freqout(freq, duration)

For this function, freq is an integer variable defining the frequency you want to generate. Units are in Hz. Human hearing extends from 20 – 20,000 Hz, so with an integer (whose values can be as high as 32,767), you can generate tones higher than the human ear can hear. Two tones can be generated at the same time; to generate a single tone, use the same tone for both frequency parameters.

Duration is the number of milliseconds to play the sound for.

For more on using the freqout() function, visit the Arduino playground.

You’ll need a speaker to hear tones that are generated, and even still they might be difficult to hear. For better sound, wire your microcontroller to an audio jack so you can connect its output to the input of an amplifier. See the lab on Tone Output for more.

Servomotors

Perhaps the most exciting thing you can do as analog output is to control the movement of something. One simple way to do this is to use a servomotor. Servomotors are motors with a combination of gears and an embedded potentiometer (variable resistor) that allows you to set their position fairly precisely within a 180-degree range. They’re very common in toys and other small mechanical devices. They’re also very easy to control. They have three wires:

  • power (usually +5V)
  • ground
  • control

Connect the +5V directly to a 5V power source that can supply at least one amp of current (don’t try to power the motor from the microcontroller; it hasn’t got enough power). Ground it to the same ground as the microcontroller. And attach the control pin to a pin on the microcontroller. Then you need to send a series of pulses to the control pin to set the angle. The longer the pulse, the greater the angle.

To pulse the servo, you generally give it a 5-volt, positive pulse between 1 and 2 milliseconds (ms) long, repeated about 50 times per second. The width of the pulse determines the position of the servo. Since servos’ travel can vary, there isn’t a definite correspondence between a given pulse width and a particular servo angle, but most servos will move to the center of their travel when receiving 1.5-ms pulses.

See the servo example for more on this.