Chapter 5: Analog Output

Last month we continued with the Arduino 101 Classroom series and discussed digital input using a momentary pushbutton. We also learned some more software concepts and we ended with a lab that combines what we learned about LEDs and pushbuttons to create a reaction time tester that tests how quickly you can press a button after an LED turns off. This month we will first learn how to use the Arduino Serial library and the Serial Monitor to communicate between the Arduino and a PC - something we'll need for setting values for analog output. Next we will discuss the differences between analog and digital. And then we will learn to output analog signals to control the brightness of an LED and the angular position of a servomotor. All of this will add some very useful tools to your personal computing and electronics toolkit.

 

 Chapter 5: Analog Output

Last month we continued with the Arduino 101 Classroom series and discussed digital input using a momentary pushbutton. We also learned some more software concepts and we ended with a lab that combines what we learned about LEDs and pushbuttons to create a reaction time tester that tests how quickly you can press a button after an LED turns off. This month we will first learn how to use the Arduino Serial library and the Serial Monitor to communicate between the Arduino and a PC - something we'll need for setting values for analog output. Next we will discuss the differences between analog and digital. And then we will learn to output analog signals to control the brightness of an LED and the angular position of a servomotor. All of this will add some very useful tools to your personal computing and electronics toolkit.

 

Talking to the PC

In this chapter we are going to learn mainly about analog output. But first let's take a look at a very handy Arduino class of functions: the Serial class. We used a couple of functions from that class at the end of Chapter 4: the serial.print() and serial.println() functions. This month we'll discuss these in a bit more detail and add a few more useful Serial class functions to our toolkit.

 

Being able to communicate with an Arduino via a PC terminal program is very handy indeed. It allows us to transmit information from the Arduino to the PC by using the Arduino IDE's built-in Serial Monitor. And it allows us to receive commands and data from the PC to an Arduino program. Doing this allows us to open a window to see into the Arduino that can be vital for testing software concepts and for debugging programs - both you will get very acquainted with as we go along.

 

Sending text to the PC

When we program the Arduino we use the IDE discussed in Chapter 1. The IDE uses the USB connection to do the communication through a Serial Port with a COM# identifier for the PC input port that, as we saw, we can select from the tools menu. The IDE takes care of all the communication between the IDE and the Arduino to allow us to upload programs that we write on the PC to run on the Arduino. We can also use this communications channel to send and receive data to/from the PC by using the Serial Monitor. We open the Serial Monitor by going to the tools menu in the Arduino IDE and clicking on the Serial Monitor as shown in Figure 1. Make sure you have selected the correct COM port as shown in Figure 2 (this was discussed in Chapter 1). You'll see a new Serial Monitor window open as shown in Figure 3.

 

 

Figure 1: Open the Serial Monitor

 

 

 

Figure 2: Select the Serial Port

 

Figure 3: The Serial Monitor

 

Figure 4: Serial Monitor baud

 

Setting up our serial communication, baud rate.

We must set up the serial port in the setup() function in our Arduino program. To do this we use the Serial.begin(baud) function where the 'baud'  (sometimes referred to as baud rate) is a number that is proportional to the speed of the communication. The bootloader on the Arduino UNO is set to 57600 baud, and it makes sense to set all our communications to that rate. Use the following in the setup() function:

 

     Serial.begin(57600);

 

You will want to verify that you've set the Serial Monitor to the same baud. Do this by opening the baud drop-down selector in the Serial Monitor as shown in Figure 4.

 

Using the Serial class

Serial is an Arduino class that contains many functions such as print() and println(). The difference between these two functions is that Serial.println() adds a line feed to the end of the text it sends to the Serial Monitor. The line feed causes the Serial Monitor to print the next text on the next empty line of the display. Each of these functions takes a string of text delimited by quotes such as "This is a string of text" and sends that text to the Serial Monitor. [These functions also can take a second parameter that can be used to translate numbers into different bases, but this is beyond the scope of our discussion at this point.]

 

If we write:

 

void setup() {

Serial.begin(57600);

}

 

void loop() {

Serial.println("Hello, world!");

Serial.println();

Serial.print("How ya doin?");

for(;;);

}

When we upload and run the sketch we will see the text on the Serial Monitor as shown in Figure 5.

 

Figure 5: Hello world

 

Receiving Text from the PC

Let's learn to receive numbers from the PC. These numbers will be of the int (integer) data type and on the Arduino they can be any value from 0 to 65535. We will use the parseInt() function from the Serial class as follows:

void setup() {

Serial.begin(57600);

Serial.println("How much would you pay?"); 

}

 

void loop() {

int pay;

if(Serial.available()) {

   pay =  Serial.parseInt();

  

   Serial.print("You'd pay: ");

   Serial.print(pay);

   Serial.println(" - is that all?");

   Serial.println();

   Serial.println("How much would you REALLY pay?");

   Serial.println(); 

}

}

 

When the program first runs we see the text "How much would you pay?" that was sent by the Serial.println in the setup() function as shown in Figure 6.

 

Figure 6: How much would you pay

 

First we enter an integer into the text box at the top of the Serial Monitor such as '123' then click Send as shown in Figure 7.

 

Figure 7: Serial Monitor send number

 

The loop() has an if statement that uses the Serial.available function to check to see if the PC is sending anything. If something has been sent then the Serial.parseInt function converts the data from the PC into an integer variable 'pay'. Then, several Serial.print and Serial.println functions are used to display the number that was sent and to challenge the users as to what they would really pay as shown in Figure 8.

 

Figure 8: How much would you REALLY pay

 

The message will repeat each time you input a new amount. We will use these concepts later in the chapter in labs that let use send numbers to set LED brightness and servo motor positions.

 

And as a little note of warning, if you open the Serial Monitor and instead of seeing the readable text you are expecting, you see a bunch of nonsense characters - check your baud. Both your Arduino program and the Serial Monitor must be using the same baud rate (57600 in our example) or the transmission and reception will be garbled. This is a very common error so be prepared.

 

Now let's learn about analog output.

Analog versus Digital

A signal is a quantity we detect that changes over time. We will look at signals for voltages that vary over time.

 

The term digital signal refers to two discrete voltage states changing over time. These states represent a higher and lower voltage. The higher voltage, in our system, is +5 volts while the lower voltage is 0 volts also known as ground (sometimes shown as GND). Digital signals are what computers use to operate. The term analog signal refers to continuously varying voltage over time. For our system, these signals will vary between +5 volts and 0 volts. Digital signals have only two states, on or off, while analog 'states' are continuous and in essence have infinite possible values, in our case between +5 and 0. Figure 9 shows examples of digital and analog signals.

 

Figure 9: Digital and analog signals

 

 

Analog Output using PWM (Pulse Width Modulation)

We've learned that the Arduino can output digital signals on some of its pins. What we will learn in this chapter is that several Arduino pins can output digital signals that can be used to create analog signals. These pins are marked with a '~' on the Arduino UNO board and are numbered: 3, 5, 6, 9, 10, and 11 as shown in Figure 10

 

Figure 10: Arduino UNO PWM pins

 

The Arduino does not actually produce a variable continuous voltage on its analog pins; it produces pulses of digital voltages that can be averaged out by external devices so that they produce results functionally similar to a variable voltage.

 

Figure 11: Pulse width and period

Figure 11 illustrates this concept with four pulse trains (pulses that repeat over a set interval know as the period) where the vertical represents voltage (0 to +5) and the horizontal represents time. In the first pulse train the pulse is turned on to +5 volts 10% of the time and off to 0 volts 90% of the time. In that case the average voltage over time is 10% of 5 volts or 0.5 volts. The second pulse train is for 30% on and 70% off giving an average of 1.5 volts. The third pulse is on 50% off 50% and averages to 50% of 5 volts or 2.5 volts. And the last one is on 90% off 10% for 4.5 volts average. [Please note that this is an over-simplification of what happens in real electronic systems but is okay to help understand what is going on at this point in the discussion.]

 

Figure 12: Pulses and average voltage

 

These digital signals are known as PWM (Pulse Width Modulation). To output PWM signals with an Arduino you use the analogWrite(write_value); function. This function takes the write_value variable, which can be from 0 to 255 and uses that number to set the width of the pulses as shown in Figure 12. There are three terms you need to describe what is happening: frequency, period and pulse width.

 

The frequency is the number of times a repeating event occurs per unit time. The period is the duration of one cycle of that repeating event. We use the term Hz (Hertz) to indicate how many times the repeating event occurs in one second. The Arduino analogWrite function outputs a pulse train with a frequency of about 490 Hz that equates to a period of about 2 ms.

 

We see in Figure 12 that each of these pulse trains creates a constant DC (Direct Current) voltage that does not change over time. And since we can set the pulse to any of 256 widths that means we can have 256 discrete DC voltages. If we use analogWrite(0); we get a voltage of 0, and if we use analogWrite(255) we get the maximum voltage that in our case is 5 volts. If we use analogWrite(127), half way between the two, then we wet half of 5 volts or 2.5 volts. You can calculate the write_value to use in analogWrite(write_value) to give a percent of time the pulse is high by multiplying the percent times 255. Thus for a 90% on time you multiply 0.9x255 = 229.5 and since we are using integers you round it up to 230. This is shown in Figure 12 as analogWrite(230).

 

 

Lab 1: Serial Print: Testing Your Reaction Time



Parts Required:

1 Arduino
1 Arduino Proto Shield

This lab uses the pushbutton and LED breadboard set up from Chapter 4 Lab 3


 Check off when complete:
Make sure the power is off before building the circuit.
Build the circuit shown in Figures 16 and 17.
Plug the USB cable into the Arduino.
Apply power to the circuit.
Open the Arduino IDE and load the 'C4_Time_Tester' program.

  
// C4_Reaction_Time_Tester
// Reports over the serial port how many milli seconds it 
// takes you to remove your finger from the pushbutton after
// the LED turns on.

// Constants used to set pin numbers 
const int buttonPin = 12; // the number of the pushbutton pin

// variables 
int buttonState = 0; // pushbutton status variable
const int ledPin = 11; // the number of the LED pin
int reactionTime = 0; // reaction time variable

unsigned long startTime = 0;
unsigned long endTime = 0; 

long randNumber;

void setup() { 
  // initialize Serial communications
  Serial.begin(57600);
  Serial.println("Test your reaction time.");
  Serial.println("Hold down button and release when LED comes on.");

  // set the buttonPin mode to INPUT
  pinMode(buttonPin, INPUT); 
  // set the ledPin mode to OUTPUT
  pinMode(ledPin, OUTPUT);  
}

void loop(){

  // get the state of the pushbutton
  buttonState = digitalRead(buttonPin);

  // is the button pressed?
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {  
    
    // select a random number of milliseconds from 1000 to 5000
    randNumber = random(1000,5000); 

    // turn LED on:   
    digitalWrite(ledPin, HIGH); 

    // leave the LED on for the randome milliseconds 
    delay(randNumber);

     // turn LED off:
    digitalWrite(ledPin, LOW); 

    // get the start time as soon as the LED goes off
    startTime = millis();

    // wait until the subjects gets his finger off the button
    // read the button state until it is equal to HIGH
    do{
       // get the state of the pushbutton
       buttonState = digitalRead(buttonPin);
    }while(buttonState == HIGH); 

    // get the end time as soon as the finger is off the switch
    endTime = millis();   

    // Tell the world your reaction time
    Serial.print("You took: "); 
    Serial.print(endTime-startTime,DEC);
    Serial.println(" milliseconds."); 
  } 
}

Verify and upload the program to your Arduino.
Open the Arduino Serial Monitor.
Press and hold the pushbutton.
When the LED goes off release the button.
Verify that your reaction time is being shown in the Serial Monitor as shown in Figure TODO;
Do this 10 or more times and then average your reaction time.
Challenge someone to a contest and see who has the fastest reaction time.

Figure 19: Reaction Time

Lab 2: Controlling an LED brightness

 

Parts Required:

1 Arduino

1 USB cable

1 Arduino Proto Shield

1 LED

1 1000 O resistor

 

Estimated time for this lab: 15 minutes

 

 Check off when complete:

Connect the LED to pin 11 as shown in Figure 13 and 14.

 

 

Figure 13: LED to pin 11 drawing

 

Figure 14: LED to pin 11 schematic

 

Open the Set_LED_brightness sketch or copy and paste the following code: 

// Set_LED_brightness 3/11/14

int ledPin = 11; // LED connected to PWM pin 11

 

void setup()  {

  Serial.begin(57600);

  Serial.println("Enter 0 to 255 to set LED brighness");

}

 

void loop()  {

  int brightness;

 

  if(Serial.available()) {  

    brightness =  Serial.parseInt(); // convert input to int

   

    analogWrite(ledPin, brightness); // set PWM

   

    Serial.print("Brightness: "); // print the brightness

    Serial.println(brightness);                        

  }

}

 

Open the Serial Monitor and set several values between 0 and 255 as shown in Figure 15.

Observe the LED brightness change.

 

Figure 15: Set brightness with Serial Monitor

 

Lab 3: Analog Output to pulse an LED - Heartbeat LED


In Chapter 3, Lab 2: Timing, Part 2 - Dimming the LED we looked at using the delay timer to dim the LED. That technique is fairly low resolution compared to using the analogWrite() function. In this lab we will use the LED set up from Lab 1 and run the Arduino example program

 

However, if we use the analogWrite() command, the dimming is done by the timer/counter peripheral that controls the PWM on off timing of the pin that drives the LED. It does this in the background so that it has no effect on the main program.

 

Parts Required:

1 Arduino

1 USB cable

1 Arduino Proto Shield

1 LED

1 1000 O resistor

 

Estimated time for this lab: 10 minutes

 

 Check off when complete:

Open the Arduino File menu and select File/Examples/Analog/Fading as shown in Figure 16.

Change the int ledPin = 9; to int ledPin = 11;

Upload the code and observe the LED pulsing.

Change the delay from 30 ms to 10 ms in both the fade in and fade out sections and observe the faster pulse.

 

Figure 16: Select the Arduino Fading example

 

Servo Motors

When we learn about the Arduino as a controller, we learn that it controls things by looking at the environment with sensors and then, using what it senses it can make things move in the environment with actuators. An example of an actuator is the Servomotor. These are used in many applications in machine automation, robotics, and RC (Radio Control) models.

 

The word servo is a shortened version of servomechanism: a device that has built-in sensing to help control some aspect of the mechanisms function. A servomotor senses the motor actuator arm position and can vary that position over approximately half of a full turn - from 0° to 180° (angle degrees). Note that since the servo has internal sensing, the Arduino doesn't need to sense the angle position of the servo, but needs only send it the correct PWM value to set an angle.

 

Our servomotor does this internal angle sensing with a built-in variable resistor known as a potentiometer (we will learn lots more on these things in the next chapter). The potentiometer produces a variable voltage that depends on the angle of the servomotor's rotor position. A dedicated controller in the servomotor uses that voltage to set and hold the required angular position of the actuator arm.

 

We discussed the Arduino PWM, and saw that the library sends out pulses at a frequency of 490 Hz, which is about 2 ms per pulse. Servomotors, however, use a 10 to 20 ms period and within that pulse they require a on time between 1ms and 2 ms to control the angular position as shown in Figure 17.  Fortunately, the Arduino has a servo library that sets the correct pulse width and period so that we can use an angle as a parameter to set the angle of the servo rotor. We will learn to do this in the following labs.

 

Figure 17: Servo pulse and angle

 

What is inside our servomotor?

The following materials will save you from tearing apart your servomotor to see how it works. Not that you shouldn't do that, but I'd suggest you wait until you've done all the labs in this chapter and in Chapter 6. You know… just in case you break something.

 

Figure 18: Servo horns and screws

 

Figure 18 shows the servomotor in the Arduino 101 Projects Kit that you can get from Nuts&Volts magazine and web store. The three white pieces are called horns and are attached to the servomotor shaft with the small screw. The large screws are used to attach the servomotor to a frame or base. The horns are used to provide attachment points for rods that are used in RC models to control the position of things such as rudders and elevators on model aircraft.

 

Figure 19: Servo side top and bottom

 

In Figure 19 you see the internals of the servomotor through the transparent plastic with the label removed. We remove the bottom screws as shown in Figure 20, which allows us to remove both the top and the bottom of the servomotor case as shown in Figure 21.

 

Figure 20: Servo remove screws

 

Figure 21: Servo removing top and bottom

 

 

Figures 22 and 23 shows details of the gear system.

 

Figure 22: Servo top off

 

Figure 23: Servo side with top and bottom off

:

 

Figure 24: Servo bottom removed

 

In Figures 24 and 25 we see the motor and controller board removed from the bottom of the servomotor.

 

Figure 25: Servo PCB and motor removed

 

Figure 26 shows the bottom and top of printed circuit board that contains components used to control the position of the servomotor shaft.

 

Figure 26: Servo PCB top and bottom

Figure 27: Servo potentiometer

Figure 27 shows the variable resistor (potentiometer) that is connected by the gears to the motor and the external shaft used by the horns. The potentiometer turns when the shaft turns and the resistance varies with the degree of the turn. This resistance is measured by the controller on the printed circuit board and used to control the angular position of the shaft.

 [NOTE: PhilKe on the forum pointed out that the servomotor will not run if you use an unpowered USB hub and that it will not run two servomotors even if you use the fully powered USB direct connection to the PC.]

Lab 4: Connecting and Testing the Servo Motor

Parts Required:

1 Arduino

1 USB cable

1 Arduino Proto Shield

1 3-pin header

1 Mini-servo motor

 

Estimated time for this lab: 15 minutes

 

 Check off when complete:

Place the long legs of the 3-pin header into the mini-servo connector as shown in Figure 28.

[Please note that this connection is not very secure and pulls out easily, however it should do just fine for learning to use the servo. If, however, you want to make a more robust connection that will let you work with more advanced projects then you will want to look at the tutorial kindly provided by oldiron on the forum: Oldirons servo header tutorial ]

Plug the 3-pin header into the breadboard as shown in Figures 29. These pins are short so you'll need to exercise care to keep the header plugged into the breadboard.

Connect a jumper wire from the position of the mini-servo yellow wire to pin 9 on the Arduino header as shown in Figures 30, 31, and 32.

Connect a jumper wire from the position of the mini-servo orange wire to the 5V pin on the Arduino header as shown in Figures 30, 31, and 32.

Connect a jumper wire from the position of the mini-servo black wire to the GND pin on the Arduino header as shown in Figures 30, 31, and 32.

 

 

Figure 28: Servo connector header

 

Figure 29: Servo plugged into breadboard

 

 

Figure 30: Servo wired to Arduino

 

Figure 31: Servo drawing

 

 

Figure 32: Servo shield schematic

 

Open the Arduino IDE and select the File/Examples/Servo/Sweep example sketch.

Upload the sketch.

The Servo should begin to sweep back and forth 180°.

 

Lab 5: Setting an angle on a servo motor

 The source code and the image for the dial and pointer are located at:

http://arduinoclassroom.com/downloads/Arduino_101_Chapter_5_May_2014_supplemental.zip

Parts Required:

1 Arduino

1 USB cable

1 Arduino Proto Shield

1 3-pin header

1 Mini-servo motor

1 Print out of the servo angle and pointer image shown in Figure 33:

1 Piece of cardboard (cereal box) to accommodate the compass and dial.

1 Double-sided sticky tape.

1 Pair Scissors

 

Estimated time for this lab: 30 minutes

 

Figure 33: Angles dial

 

 Check off when complete:

Print the angles dial and pointer shown in Figure 33.

[Note this image can be found in Servo_angle_and_pointer.pdf located in Arduino_101_Chapter_5_May_2014_supplemental.zip that you can find on the Nuts&Volts web site page for this article and on the www.arduinoclassroom.com Chapter 5 web page.]

Place strips of double-sided sticky tape on the back of the angles dial and pointer printout.

Place it on the cardboard (like from a cereal box) and carefully smooth it down.

Cut out the angles dial and pointer.

Look at Figures 34, 35, 36, and 37 to get a feel for how to cut out the holes to mount the compass and the dial.

Use the scissors to drill a tiny hole in the center of the compass then clip out a shape like the top of the mini-servo - a larger circle at the center and a smaller circle to the side. This should match the top of the min-servo in shape but be about 1/8" smaller.

Clip 1/8 notches around the shape so that you can force the mini-servo into the hole and have the clipped edges squeeze tight to the mini-servo

Use the scissors to drill a small hole in the base of the dial and then use the smaller of the screws shown in Figure 34 to attach the dial to the mini-servo.

 

Figure 34: Servo dial top

 

Figure 35: Servo dial

Figure 36: Servo dial side

 

Figure 37: Servo dial bottom

 

Either cut, paste, or type in the following program. [Or open the A101_5_Servo_Angle.ino program - note this file is located in Arduino_101_Chapter_5_May_2014_supplemental.zip that you can find on the Nuts&Volts web site page for this article and on the www.arduinoclassroom.com Chapter 5 web page.]

Notice that the servo angle and the compass angles are in opposite directions so that the code is modified to show the angle entered into the Serial Monitor as the angle the servo points to.

 

// Servo Angle

// 3/7/14 Joe Pardue

 

#include <Servo.h>

 

Servo myservo;  // create servo object to control a servo

 

int pos = 0;    // variable to store the servo position

String readString;

 

void setup()

{

  myservo.attach(9); // attaches the servo on pin 9 to the servo object

 

  // initialize the serial communication:

  Serial.begin(57600);

  Serial.flush();

  Serial.println("Servo Angle 1.0");

}

 

void loop()

{

  byte angle;

 

  while (Serial.available()) {

    char c = Serial.read();  //gets one byte from serial buffer

    readString += c; //makes the string readString

    delay(2); //slow to allow buffer to fill with next character

  }

 

  if (readString.length() >0) {

    Serial.println(readString);  //so you can see the captured string

    int n = readString.toInt();  //convert readString into a number

 

    // The compass has the angles reversed from the servo angles

    //     so we convert the input angle to fit the compass angle

    n = 180-n;

 

    Serial.print("writing Angle: ");

    Serial.println(180-n); // show angle sent

    myservo.write(n); // use converted angle

 

    readString=""; //empty for next input

  }  

}

 

Upload the program.

Open the Serial Terminal and send it a value of 180 as shown in Figures 38 and 39.

After the servo has set the angle loosen the pointer screw and move the point of the tip to point at 180 on the angle dial.

Now send various angles such as 45, 90, 135 etc. to test that the mini-servo angle is being set correctly.

 

Figure 38: Input 180 to Serial Monitor

 

 

 

Figure 39: Serial Monitor shows angle

 

Remember that all the components used in the Arduino 101 series are available from the Nuts&Volts magazine web site. And if you have any questions about this series, please don’t hesitate to visit the forum on www.arduinoclassroom.com and ask.