Chapter 6: Analog Input



In Chapter 5: Analog Output, we were introduced the concepts of analog versus digital signals where we learned that digital signals are made from two discrete voltages (in our case +5V and 0V) and analog signals can take any voltage, in our case on a continuum from +5V to 0V. We learned how to generate analog signals using PWM. And we learned about the Arduino Serial Monitor and how to use that to communicate between a PC and the Arduino. In this chapter, we will learn about inputting analog signals using the ADC (Analog to Digital Converter) built into the Arduino. And we will get an introduction to some basic electrical concepts, which will help us to understand what it is we are inputting. But first let's learn some more serial communication techniques.

 

Chapter 6: Analog Input



In Chapter 5: Analog Output, we were introduced the concepts of analog versus digital signals where we learned that digital signals are made from two discrete voltages (in our case +5V and 0V) and analog signals can take any voltage, in our case on a continuum from +5V to 0V. We learned how to generate analog signals using PWM. And we learned about the Arduino Serial Monitor and how to use that to communicate between a PC and the Arduino. In this chapter, we will learn about inputting analog signals using the ADC (Analog to Digital Converter) built into the Arduino. And we will get an introduction to some basic electrical concepts, which will help us to understand what it is we are inputting. But first let's learn some more serial communication techniques.

Sending commands and data



The computer on the Arduino board is an Atmega328 microcontroller and as the name indicates it is intended to control things. Sometimes a microcontroller is entirely embedded into a system such as a car engine where it might do something like sensing oxygen and actuating an air intake valve. But other times it is used in a system where it requires human user input, like in a microwave oven where it senses button presses and uses the human data input to set the cooking time.

In our last lab, we saw how to use a PC to send data to the Arduino to set the angle on a servomotor, but there could be many different things we might want to make a servomotor do. For instance, if the servomotor is controlling a camera pointing system on a robot, we might want to have the camera sweep across an area beginning at a certain position and ending at another position and we might want the sweep to occur at a certain speed. Here we have three different actions we want to control on the servo and each action is associated with a specific number. We might want to have the sweep speed be something between the slowest speed at 0 and the fastest speed at 100. And we might want to make the servo start at 45°, move to 135 ° and do that at a medium speed of 50. If we want to control this action from a PC then we will need four commands, one to set the start position, one to set the end position, one to set the velocity, and finally one to tell it to do the sweep. We've learned how to send numbers, now let's learn how to send commands along with those numbers.

In the last chapter, we looked at how to send a number from the PC Serial Monitor to the Arduino so that it could use that number to set the angle of a servo. We saw that if we received a string of characters that represent a number such as "123" that we could use the following statement to convert the string to an integer:

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

The readString.toInt() function is very useful when we send it the characters for a number, but if we send it non-numeric characters like 'a' or '!' it doesn't know what to do with them and the function returns 0. [You should remember this if you want to receive a 0 as a valid number since you might actually be receiving a 0 as an error indication.]

Let's look at the situation where we would like to send a command to the Arduino that contains a number. When the only thing we were sending to the Arduino was a number representing the angle, which was no problem. But what if we also want to send a number representing the velocity we want the pointer to move or a number that represents the angle we want the motion to start from or another number for the angle where the motion ends? Here we have three separate numbers so we'll need someway to link them to a command for the action associated with the number. For velocity, let's use 'v' to precede the number: vxxx where xxx is 0 to 100 - where 0 is stopped and 100 is the maximum speed. For the start angle we will use 's' as sxxx where xxx is 0 to 180 for start angle. And for the end angle we will use 'e' as exxx where xxx is 0 to 180 for end angle. This means that the Arduino will receive the string v123 and must be able to separate the 'v' as the velocity command and the '123' as the speed for the pointer to move. To do this, we receive the string v123, then we get the first character in that string into a 'command' variable using the readString.charAt() function as follows:

command = readString.charAt(0); // get the first character

The parameter for .charAt tells the function which character to get, which in our case is the first character that is in the 0 position in the string. [Remember that computers starting counting at 0 not 1.] When we have the command set then we can look at the character in the command to see which command it is. We do this as follows:
  

    if(command == 'v')// set the velocity

    {

      // do what is needed to set the velocity

    }

    else if(command == 's')// set the start angle

    {

      // do what is needed to set the start angle

    }

    else if(command == 'e')// set the e angle

    {

      // do what is needed to set the end angle

    }


We will call this technique a command parser and as you can see we can parse as many separate commands as there are ASCII characters. [In a later chapter we will learn to accept commands that are greater than a single character since it is much easier to remember what the command 'set end angle' does than 'e'.] Once we have identified the command and the code moves into the block of code [delimited by { and }] that deal with the code, we will need to extract the number that was send following the command character. We do this by first reading the rest of the command string from the second position in that string - position 1 (remember we started counting at 0) using the readString.subString() function as follows:
  

	String temp;



      temp = readString.substring(1); // get the rest of the string

      velocity = temp.toInt(); // convert the string to an integer

 

In Lab 1 we will use this to control motion by setting a start and end angle and a velocity for the pointer to move. This sort of action is used in a variety of real-world situations like controlling where a camera is pointed or the position and speed of a machine tool.

Voltage, Current, and Resistance


The term 'analog input' refers to using a computer to sense analog (continuous) information from the environment. We often do this by sensing voltage where the voltage is an indicator of some continuous parameter in the environment that we want to measure. When we measure light or temperature or sound, for instance, we have an electrical device or circuit that converts the light, temperature, or sound to an equivalent voltage and then we measure that voltage with a peripheral in our microcontroller called an ADC (Analog to Digital Converter). We then use some sort of calibration value to map the voltage to the parameter being measured. We might have a temperature sensor that measures from ᆼ° to +150°C by outputting voltage from 0.1V to 2.0V. For this example we have about 0.17V per degree Celsius, so we could write a little algorithm that would read the voltage and report the temperature in Celsius, or with another line of code, Fahrenheit.

In Chapter 2, we learned that we could light an LED by connecting the long leg to +5 volts and the short leg to one side of a resistor and the other side of that resistor to ground. In that illustration, we used a 1000 W resistor. The resistor functions to limit the amount of electrical current that moves through the LED. If we connected the LED directly to +5 and 0, the current would be so great that the LED would overheat and burn out. For us to understand analog input, we will need to understand a bit more about electricity than we have seen so far.

Electric Measurements


When we want to bake a cake, we follow a recipe that will say something like: we need two cups of this, a teaspoon of that, a dash of something else, baked at some temperature for some time. If we want to have a cake that is edible, we need to know what the measurements mean. What are cups, teaspoons, dashes, degrees Fahrenheit, and minutes? Likewise to play with electricity we need to know some electrical measurements.

There are three things that we measure when we first learn about electricity: Voltage, Current, and Resistance with units in volts, amps, and ohms. Volts are a measure of electric potential (force - how hard the electricity is pushing), amps are a measure of electric current (how much of the electricity is moving through something), and Ohms are a measure of opposition to electric current flow.

Electric Potential Difference = Voltage




Figure 1: Bucket voltage metaphor



We intuitively understand that if someone dumps a bucket of water off a 20-story building and it hits the sidewalk next to us we are going to get splashed more than if someone standing next to us dumps that bucket of water from 3 feet up on the same spot. We use this fact every time we turn on a faucet. The water pipe is connected to a tank of water somewhere that is higher up than our faucet: the higher the tank the greater the water pressure. Voltage is like water pressure, but electric ‘pressure’ does not come from gravity. It comes from the simple fact that electrons do not like each other and the more crowded they get the madder they get and the more determined they become to bust out and go somewhere with fewer electrons (hey, that’s what quantum physicists say if you read between the lines). Areas with more electrons are said to have a higher electric potential relative to areas with fewer electrons. Figure 1 shows this with holes at different depths along the side of a bucket. This potential difference (more electrons in one area and less in another) can be thought of as a force that pushes electrons from one place to another.

Voltage is a measure of electric potential difference between two areas that have different amounts of electrons. Water will run downhill if it can run down hill and electrons will spread out from higher electron density regions to lower electron density regions if they can spread out.
 

Electric Current = amps




Figure 2: Bucket current metaphor



We think of current as the amount of water moving past in a stream. The Gulf Stream is a current that has a lot more water moving along than the stream coming out of your bathroom faucet. A bolt of lightning has a lot more electrons moving past than that spark of static electricity your older brother applies to your ear after sliding his bunny slippers across the wool carpet in the hall on a dry day.

The amount of electric current is referred to as amperes or amps. Figure 2 uses the water bucket metaphor with larger holes allowing greater current. The pressure is the same, but as the holes get bigger you get a greater current.
 

Electric Resistance = ohm (&Omega)


For the water analogy, we can think of resistance as being caused by the diameter of the hole. Note that in Figure 2 more current is due to different size holes – bigger hole, less resistance, more water.

For the resistors in the projects kit, the higher the number the more the resistance so you can think about the 10k &Omega resistors as having a smaller electric hole and thus passing less current than the 1k &Omega resistors which has a bigger electric hole and passes more current. (The symbol &Omega is means Ohm in this context)

Materials with low resistance are known as conductors, while materials with high resistance are known as insulators. Electrons move easily in some things such as copper wire (a good conductor) but are stopped cold by some things such as glass (a good insulator). Copper has very low resistance – the jumper wires in the projects kit have near 0 ohms resistance (about 1 ohm per 62 feet), while glass can have millions of ohms resistance.

Ohm’s Law


Georg Simon Ohm wrote a rule to account for observations of voltage (volts), current (amps), and resistance (ohms). We typically see this rule, as voltage is equal to current times resistance:

volts = amps * ohms Voltage equals current times resistance.

A little algebra shows us that the equivalents are:

amps = volts/ohms Current equals voltage divided by resistance.
ohms = volts/amps Resistance equals voltage divided by current.

Now let's confuse things a little bit and use the standard (SI) symbols for this:

V = IR Voltage equals current times resistance

And the confusion is the 'I' is the symbol for amps. But this is what is used so let's just go with it.

I = V/R Current equals voltage divided by resistance.
R = V/I Resistance equals voltage divided by current.

With this law, if you know any two of the variables, you can solve for the third unknown variable. This comes in handy when for instance you want to specify the resistor for an LED. Let's say that you will be powering at 3.3V and the datasheet says the LED is most efficient when passing 15mA of current. You solve the resistance formula:

R = V/I
R = 3.3/.015
R = 220 &Omega

And since 220 &Omega is a standard resistor size we can easily get the exact resistor needed. In the Arduino Projects Kit we use 1k &Omega resistors and have 5V power so the current can be found with:

I = V/R
I = 5/1000
I = 0.005 amps

And while 5 mA (0.005 amps) is under-powering the LED, it are plenty bright and since we may be using batteries, the lower current saves power and extends the battery life.

Circuits




Figure 3: Electric current from battery through resistor and LED



We get electricity to do useful work by channeling it from devices that produce electric force (like generators and batteries) through devices that do electric work (like lights and motors) and back to the device that created the force. That last part is critical. Circuit is just a fancy way of saying ‘circle’: electricity must run around a circle to do useful work.
 

Figure 3 shows arrows marking the direction of conventional current from the higher voltage side of a 9-volt battery (the positive terminal) through a resistor and an LED back around to the lower voltage terminal of the battery.



You have probably seen really complex circuits on printed circuit board or as schematics, but no matter how complex it looks, it can be simplified to one part producing the force as a current, one part using that force to do work, and the circular electrical connection between them.
 

Short Circuits


If we connect a copper wire between the + and – terminals of a battery, ‘short circuiting’ them, as shown in Figure 4, the current will rush through doing a lot of work making the wire heat up and quickly deplete the chemicals in the battery that are creating the electric potential difference in the first place. Don’t try this experiment because not only will it deplete your battery, many batteries will heat up and possibly even explode when treated this way.


Figure 4: Short circuit



If you are doing Arduino experiments plugged into the USB port of your computer you are using +5V supplied from the PC over the USB cable. If you short circuit the + to the -, and if you are lucky, the USB protection circuits on the PC will detect the current rush and shut down your USB connection before something blows up in your PC. And if you aren’t lucky? Well, say bye-bye to something expensive. The morale? Be careful not to short circuit anything expensive, flammable, or with tendencies to explode, that being most things that can be short-circuited – including you.
 

Voltage across resistance


Let’s build a circuit that let’s us play with Ohm’s Law. We put 8 of the 1k &Omega resistors from the Arduino 101 Projects Kit on the breadboard so that they are each connected in series - this yields 8k &Omega in 1k &Omega increments. These are connect one end of that series to +5V and the other end to the GND as shown in Figures 5, 6, and 7 that show the current and the voltage drop across this circuit. This arrangement of resistors is called a voltage divider and allows us to access each cumulative resistance value from 0 to 1k, 2k,3k,4k,5k,6,7,and 8k. [The illustrations also show the Arduino Analog Input pin 0 attached between the fifth and sixth resistors counting up from the +0V and we will look at that in a minute].

Figure 5: Resistor series current drawing




 

Figure 6: Resistor series voltage drawing


 

Figure 7: Resistor series schematic



Let’s play with Ohm’s Law for a moment. We know that we have 5 volts and a total of 8k &Omega resistance in our circuit, so we can calculate the unknown variable, current (I):

I = V/R
I = 5/8000 = 0.000625 Amps

0.000625 Amps is the same as 0.625 milliamps which we will usually show as 0.625mA. So we have 0.625mA current passing through each of the 8 resistors and since each resistor is 1k &Omega and we can solve Ohm’s Law for the voltage across each resistor:

V = IR
V = 0.000625 * 1000 = 0.625 Volts

So, theoretically, we should be able to measure the voltage between fifth and sixth resistor above 0V (as shown in Figure 6) and it should conform to Ohm’s Law where the total resistance of the 5 resistors is 5k &Omega:

V = IR
V = 0.000625 * 5000 = 3.125 Volts

Theoretically? We will take a look at this law with some real-world measurements in the labs, but first let's take a look at an Arduino function we will find very useful in those labs.
 

The Arduino map() function


We notice in nature that sometimes two separate variables may be proportional to each other, (meaning that the two numbers correspond in size). For instance we know that that with a constant resistance the higher voltages correspond to higher currents. In Lab 2, we will use different voltages to specify different servomotor angles. We will use ADC readings which range between 0 and 1023 can be made and we will use these readings to set a proportional servo angle that range between 0 and 180. Thus if we have half the ADC reading, 512 we can have half the servo angle 90. If we want to use the ADC reading of the voltage to specify the servo angle then we would need to use the following formula:
Servo_angle/180 = ADC reading / 1023

So if we read ADC = 512 we can solve for the servo angle:

Servo_angle/180 = 512/1023
Servo_angle/180 = 0.5
180 * Servo_Angle/180 = 0.5 * 180
Servo_Angle = 90

We could easily write an algorithm to do this in the Arduino IDE, but we can also - even easier - use the map() function which takes the parameters:
  

map(value, fromLow, fromHigh, toLow, toHigh)


So given the information above we write:
  

	int value = 512;



	map(value, 0, 1023, 0, 180);

	if( value == 90)

	{

		// do this

	}

	else

{

		// do that

}


In the above code snippet, the value would be mapped from 512 to 90 and the "//do this" block would run. We will use this in Lab 2 to map ADC readings to servo angles.

Lab 1: Sending a command plus data


This lab will use the Arduino 101 Projects Kit setup from the last lab in the last chapter. The servo drawing in Figure 8 taken from that chapter is included here as a reminder of how to wire it up.

Parts Required:
1 Arduino
1 USB cable
1 Arduino Proto Shield
1 3-pin header
1 Mini-servo motor

Estimated time for this lab: 30 minutes

 Check off when complete:
Wire the servomotor to the Arduino Proto Shield as shown in Figure 8.



Figure 8: Servo drawing



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

  

// Arduino_101_ch6_servo_velocity

// 3/26/14 Joe Pardue


#include <Servo.h>


// create servo object to control a servo 

Servo myServo;   

 

// Declare global variables

int startAngle,endAngle, velocity;

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 Velocity 1.0");

  Serial.println("Use:");

  Serial.println("Send vxxx where xxx is 0 to 100 to set velocity.");

  Serial.println("Send sxxx where xxx is 0 to 180 for start angle");

  Serial.println("Send exxx where xxx is 0 to 180 for end angle");

  Serial.println("Send g to move from start to end at velocity");

} 

 

void loop() 

{ 

  char command;

  String temp; 



  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) 

  {

    command = readString.charAt(0);

    

    if(command == 'v')// set the velocity

    {

      Serial.print("Set velocity to: ");

      temp = readString.substring(1);

      velocity = temp.toInt();

      Serial.println(velocity);

    }

    else if(command == 's')// set the start angle

    {

      Serial.print("Set start angle: ");

      temp = readString.substring(1);

      startAngle = temp.toInt();

      if(startAngle < 0) startAngle = 0;

      if(startAngle > 180) startAngle = 180;

      Serial.println(startAngle);      

    }

    else if(command == 'e')// set the end angle

    {

      Serial.print("Set end angle: ");

      temp = readString.substring(1);

      endAngle = temp.toInt();

      if(endAngle < 0) endAngle = 0;

      if(endAngle > 180) endAngle = 180;

      Serial.println(endAngle);      

    }

    else if(command == 'g')// move the pointer

    {   

      if(startAngle < endAngle)

      {

        for(int i = startAngle ; i < endAngle; i++)

        {

          // 180 - i because the compass is reversed
          myServo.write(180-i); 
          delay(velocity);

        } 

      }

      else

      {

         for(int i = startAngle ; i > endAngle; i--)
        {

          // 180 - i because the compass is reversed
          myServo.write(180-i);
          delay(velocity);

        }   

      }     

    }

    else

    {

      Serial.println("Incorrect command character");

    } 

   readString = ""; // clear out the string

  }

}


Enter 'v25', then 's135', then 'e45', then 'g' and verify that you get the output shown in Figure 9:


Figure 9: Servo velocity


 

Lab 2: Voltage Divider


In Figures 5, 6, and 7 we saw the drawing and schematic for a circuit with 8 of the 1k &Omega resistors linked in series from +5V to GND and we learned that the voltage across those resistors is equally divided among them since they are the same size. For this lab, let's verify what we learned by building the circuit (see those figures and the photo in Figure 10.) Note that the values derived from the Arduino ADC and subsequent calculations will not be precisely what we expect due to inaccuracies inherent in this setup, but they should be close.

Parts Required:
1 Arduino
1 USB cable
1 Arduino Proto Shield
8 1k &Omega resistors

Estimated time for this lab: 30 minutes

 Check off when complete:
Build the circuit shown in Figures 5, 6, 7,and 10.
Attach one end of a jumper to the Arduino analog input pin 0 as shown in the figures.
You will move the other end of the jumper to breadboard holes corresponding to the connection between each resistor. To begin, plug the jumper into the hole where resistors 5 and 6 are connected as shown in the figures 5, 6, and 10.



Figure 10: Voltage divider lab



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

  

// voltage_divider 3/31/14 Joe Pardue



int sensorPin = A0;  // analog input pin

int sensorValue = 0;  // store the analog input value



void setup() {

  Serial.begin(57600);

  Serial.println("Measure voltage rev 1.0");

}



void loop() {

  

  if(Serial.available())

  {

    char c = Serial.read();

    if(c == 'r')

    { 

      // read the value from the sensor:

      sensorValue = analogRead(sensorPin);

      

      Serial.print("AnalogRead: ");

      Serial.print(sensorValue);      

      Serial.print("  Voltage: ");

      Serial.println(((5.0*(float)sensorValue)/1024.0), 3); 

    } 

  }                

}


Run the program and open the Serial Monitor and enter 'r' to read the voltage. Note that it probably won't be exactly 3.125, but it should be close.
Move the jumper between resistor 1 and 2, read the voltage, then move the jumper sequentially between each resistor and read the voltage. You should have output similar to that shown in Figure 11.


Figure 11: Measure voltage



 

Lab 3: Voltage control servo angle


Last month we saw how to control servo motion by sending a number over the serial port. Well, what if we want to use a servo and no PC is available, how do we set the angle then? There are, of course, many ways to do this but since we just saw how to measure 9 discrete voltages using analog input, let's look at how to use those voltages to set 9 discrete servo angles without having a PC to send the angles. We note that the servo can vary between 0° and 180° and that we can read 9 separate voltages from 0V to 5V from our resistor ladder so let's map the angles to the voltages and then move the analog input jumper to different voltages to set the servo angle. And also notice that this is a tricky circuit to visualize even with the drawing and schematic shown in Figures 12, 13, and 14. The servomotor connector is placed on three jumper lines that are between two resistor connectors. The resistor stretches across these three lines much like a flyover highway crosses a lower road - in this case the three empty breadboard lines under the resistor.

Parts Required:
1 Arduino
1 USB cable
1 Arduino Proto Shield
8 1k &Omega resistors
1 Servomotor and connector

Estimated time for this lab: 30 minutes

 Check off when complete:
Assemble the circuit shown in Figures 12, 13, and 14

Figure 12: Voltage control servo drawing



 

Figure 13: Voltage control servo schematic


 

Figure 14: Voltage control servo photo



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

  

// Voltage Control Servo Angle 

// 3/31/14 Joe Pardue

#include <Servo.h>

int sensorPin = A0;  // analog input pin

int sensorValue = 0;  // store the analog input value 

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


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

String readString;



void setup() 

{ 

  // attaches the servo on pin 9 to the servo

  myservo.attach(9); 

  

  // initialize the serial communication:

  Serial.begin(57600);

  Serial.flush();

  Serial.println("Voltage control servo Angle 1.0");

} 

 

void loop() 

{ 

  if(Serial.available())

  {

    char c = Serial.read();

    if(c == 'r')

    { 

      // read the value from the sensor:

      sensorValue = analogRead(sensorPin);

      

      Serial.print("AnalogRead: ");

      Serial.print(sensorValue);      

      Serial.print("  Voltage: ");

      Serial.print(  ((5.0*(float)sensorValue)/1024.0), 3); 

	

      //float val = (float)sensorValue;

      //val = (float)map(val,0.0,1023.0,0.0,180.0);

      int val = (float)sensorValue;

      val = (float)map(val,0,1023,0.0,180);

       

      Serial.print("  Angle = ");

      Serial.println(val);

       

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

      

    } 

  }  

}


Compile and run the program.
Open the Serial Monitor and sequentially move the jumper between each resistor and send an 'r' to the Arduino between each move.
Verify that you receive the text shown in Figure 15.



Figure 15: Voltage control servo output


Remember that all the components used in the Arduino 101 series are available in the Arduino 101 Projects Kit 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.