Sunday, March 1, 2015

Arduino blocks lesson 3 - Analog inputs and serial debugging

In this lesson I'm covering two things - inputs that are analog, that is, not just zero and one but a whole range of values, and also serial debugging, which is a simple technique that is very helpful in getting small programs and circuits working before going on to bigger things, and also in figuring out "what the heck is going on" inside the Arduino sketch.

Here's the video version of today's lesson:




Today's device
For this demonstration of analog inputs I'll be using a photo resistor.  Electrically this component acts exactly like the resistors we've used previously, but its value changes depending on how much light it sees.

Photo Resistor
I used my multimeter to measure the resistance of this device in bright and dim light and found that in the dark, it's about 50,000 ohms, and in bright light it's about 200 ohms.

Today's first new Arduino feature: analogRead()

The Arduino's analogRead() function documentation is very useful, you can read it here.  It says that the values go from 0 to 1023 when you read.  If the pin you are reading from is 0 volts, you get 0, if it's 5 volts (in the case of a classic 5 volt Arduino, or something else if your Arduino has some other reference voltage) then you get 1023.

We need a circuit that delivers various voltages to the Arduino pin based on the resistance of the photo resistor.  The immediate thought is to hook one side of the photo resistor to 5 volts and the other to the sense pin.  However, this won't work since there's nothing that would make the sense pin not just go straight to 5 volts regardless of the value.  So we need to build what is called a voltage divider.  We put in TWO resistors between ground and 5 volts, and the voltage in the middle is simply the ratio of those two resistors - if we had a 1000 ohm resistor going to 5 volts and a 4000 ohm resistor going to ground, the voltage between them would be 4 volts, since the total of 5 volts is being divided equally among 5000 ohms, and we're getting 4000 of those divided bits.

So we build a circuit like this:
Now, this isn't completely ideal because the analog pin never gets to 5 volts and it never gets to ground.  However, this doesn't really matter in most cases because we usually do not need that much precision in how bright it is.  In theory this circuit should result in output values from (10000/10200) * 1023 = 1002 down to 10000/(60000) * 1023 = 170.

Here's the circuit as built:





Now, I stole this code from the analogRead() documentation linked above:

int analogPin = 3;
int val = 0;
void setup()
{
  Serial.begin(9600);          //  setup serial
}

void loop()
{
  val = analogRead(analogPin);    // read the input pin
  Serial.println(val);             // debug value
}


Today's second new Arduino feature: Serial debugging

You'll see the new word "Serial" in there.  This is where we'll talk about serial debugging.  Since the Arduino doesn't have a screen, this is a way for it to send information back to your computer so that you can see what it's doing in simple text form.  In setup() it says Serial.begin(9600).  The 9600 is a "baud rate" which people old enough to know what a phone modem sounds like will know, but you don't really have to worry about it, just use that value.

In the loop, you'll see that it simply reads the value out and sends it to the serial monitor, which is on your PC in the Arduino code, under "Tools".  Compile and upload the software to the Arduino and once it's running, click "Tools/Serial monitor and you'll see this window:
The numbers you see there are what the Arduino is sending back to you.  

This facility is EXTREMELY useful. You may have some code that is doing something unexpected, but your circuit only has a few switches and lights,so it's hard to tell what's going on in there.  Using this facility you can have it tell you "I'm going to turn on this light now....I'm going to read the value of the switch...The switch is on so I'm going to start this motor now..." and so on.  It's very useful when "debugging" your code to get a glimpse of what's happening inside.

Cleaning up your data in software:
When I tested mine, I got values from about 1000 (with a bright light shining on the sensor) to about 400 (with the sensor in the dark under my desk).  Now, since we don't really need any better precision than that but let's say for the purposes of some thing I'm making, I need values to go from 0 to 99, we can simply correct these values in software to go from 0 ("pretty dark") to 99 ("pretty bright") like so:


void loop()
{
  val = analogRead(analogPin);    // read the input pin

  // translate our 400 to 1000 values into 0 to 99 values
  val = val - 400; // translate into 0 to 500

  if (val < 0)
    val = 0;    // do not allow to go negative
   
  val = val / 6; // translate 500 down to 100
 
  if (val > 99)
    val = 99; 
  Serial.println(val);             // debug value
}
You can grab the complete code sketch at this link.

What we're doing here is to first subtract 400 (since that's the about the lowest value we normally see) and then divide by 6 (we see a RANGE of about 600) to give us an approximately 0 to 100 range, then we have the two "if" statements to limit the range from 0 to 99.  It's a good idea to put "safety" code like this in as you write code, to make sure that your assumptions about the values are correct.  You wouldn't want to write code to do something like water the plants when it gets bright out, then find out that if the sun hits your sensor it goes to 101, causes your code to crash and it dumps water into your plant for the next 8 hours.

Summary
So to recap, we have built a simple circuit to turn light levels into voltages.  We have used the analogRead() function on the Arduino to get that value, we've written some code to change those values into clean 0 to 99 values for how bright it is right now, and we've learned how to use serial debugging to see values the Arduino is calculating on our screen.

No comments: