Using AREF

So I want to use a reference voltage of 3.3 volts for my project. It looks pretty simple, connect the 3.3 volt source on my Arduino to pin AREF, issue the command analogRefernce(EXTERNAL) and I am in business.

But wait…

The analogReference() documentation has the following ominous and cryptic statement:

Don’t use anything less than 0V or more than 5V for external reference voltage on the AREF pin! If you’re using an external reference on the AREF pin, you must set the analog reference to EXTERNAL before calling analogRead(). Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board.

Alternatively, you can connect the external reference voltage to the AREF pin through a 5K resistor, allowing you to switch between external and internal reference voltages. Note that the resistor will alter the voltage that gets used as the reference because there is an internal 32K resistor on the AREF pin. The two act as a voltage divider, so, for example, 2.5V applied through the resistor will yield 2.5 * 32 / (32 + 5) = ~2.2V at the AREF pin.

This sounds dangerous.

I understand very little about circuit design so I cannot make sense of the statement, “short together the active reference voltate (internally generated) and the AREF pin”.  But fortunately they provide a safe alternative, add a 5k ohm resistor.

Many questions come to mind.

  • What is special about a 5k ohm resistor?
  • If I put a 5k ohm resistor between the 3.3 volt pin and AREF my reference voltage is 2.85 volts.  What happens if I try to measure 3.3 volts?
  • Where does the 32k ohm number come in?

I think I have figured it out.

If I attach an ohmmeter to AREF and ground I get the following readings:

  • At power up: 32.83k ohm
  • After analogReference(DEFAULT) and analogRead() commands: 0 ohms
  • After analogReference(EXTERNAL) and analogRead() commands: 32.83k ohm.

So I have concluded the following:

  • When analogReference() function is called nothing happens until the next analogRead() command.
  • If the external reference voltage is not used the AREF pin is connected to ground.  If a voltage source is connected to AREF then you have a ‘blue smoke’ situation.
  • There is an internal resistance of ~32k ohm between AREF and ground.
  • There is nothing special about 5k ohm.  This was a resistance deemed sufficient to eliminate a short circuit situation.
  • The documentation is confusing.

For me this means that to get a safe 3.3 volt reference I need to use the 5 volt source and employ a voltage divider.  A 16.5k ohm resistor between the 5 volt source and AREF will provide me with a 3.3 volt reference.  I have checked this with my meter to make sure it is correct.

Of course there are a few caveats to add:

  • If the Arduino source voltage is less than 5 volts then you will see less than 5 volts on the 5 volt pin.  When connected to the USB port you can expect a bit less than 5 volts.  On my computer I measure 4.95 volts.
  • If you switch reference voltages from internal to external it will take a few analogRead() commands before the voltage settles down.  I guess there is a capacitor involved somewhere to filter out noise and it will take a bit of time for it to discharge.

Robot v1

I was looking for a project to use as a means of learning more about what I could do with the Arduino.  I figured it would not be to hard to build a two-wheeled self balancing robot, basically a miniature Segway.

Well my first version did not work, but I figure someone might learn from my failure so I will post some pictures and some notes.

Design

The design was centered around my desire to reuse some hard drive discs that I salvaged from some drives I dismantled out of curiosity.  My reasoning was that I had plenty of them, they were very uniform in size and the machined pretty well.

I looked into many different motor/encoder combinations before deciding that if I wanted to build my own it would take a huge investment in time.  I decided to bypass this work by purchasing a combination motor/encoder from Pololu.

I looked into several options for batteries and decided the cheapest route would be to use AA cells.  I read where it was a good idea to separate motor noise from the sensor/cpu so I figured I would use two battery packs, one for the motor and the other for the Arduino.  Because the Arduino wanted >5 volts and the motors were ~6volt I decided to use 6 batteries for each pack.

I purchased a cheap Accelerometer from Pololu (ADXL335) in hopes that I could avoid spending too much money.  I could not get it to work so I decided to get a more accurate unit (Mx2125), but it appears that I also need a Gyroscope.

Total weight is about 635 grams.

Shopping List

Part No Name Description
Pololu 1218 Pololu 42x19mm Wheel & Encoder Set These includes the wheels, motor mounts and encoder which fits neatly under the mount.
Pololu 998 50:1 Micro Metal Gearmotor HP 6v, 625RPM, 1.6 Amp Stall, 15 oz-in. I was afraid if I got something slower I would run out of speed.
Pololu 142 3-AA Battery Holder Used 4 of these
Pololu 713 TB6612FNG Dual Motor Driver Carrier Motor driver. Capable of driving the two motors.
Adafruit 51 Adafruit Proto Shield This is needed to hold the breadboard to the top of the Arduino
Adafruit 65 Tiny breadboard Fits nicely in the shield
Pololu 1801 Pre-crimped 6″ Wire Purchased these wires and they were almost long enough. Hoped I could postpone the purchase of a crimping tool.
RadioShack 275-614 DPDT Submini Switch This one switch can switch both battery packs at the same time.
Pololu Connector Housing Purchased a variety of connector housings so I could make up some cables.
Adafruit 163 ADXL335 3-axis accelerometer +/-3g analog
Radio Shack 2909788 Memsic 2125 Dual Axis Accelerometer +/-3g. Thought this would work better, I was wrong.

Problems

I had problems with the sensor.  I could not make sense of the data coming out of the sensor.  There seemed to be too much noise.  I thought it was not accurate enough, so I picked up a digital accelerometer.  Data was just as noisy but it took longer read.  Turns out the problem is that I need to filter the readings and most likely need a I think the motors were also geared too high and might not be able to make the small adjustments in position I need.

I thought digital meant zeros and ones and was better than analog.  I replaced the analog accelerometer with a digital one thinking it would be more accurate, after all it was more expensive.  Instead the data seemed just as random.  But instead of a quick analogRead() call, I had to measure the time that an input was high before it went low.  This meant that I could only get data when the sensor was ready to hand it out.  Turns out it was much slower and a bigger hassle to use.

I was able to get it to skip back and forth, but when it fell over the edges of the disks were pretty hard on the desktop.  So the next robot will be designed to fall over gracefully.

More on that in a future post…

Multiple File Sketches

So I decide to split my sketch into multiple files.  The manual says there are four kinds files and they are all concatenated together when you compile into a single sketch.

Well, immediately I started getting errors and I learned a few things…

Extensions Matter

The Arduino documentation states that there are four different exensions; none, h, c and cpp.

Well first off; none means .pde.

It does not say much about what the difference is but through trial and error I have figured out the following:

The .h files are not included in the sketch unless there is a #include statement in one of the .pde files.  Even then, the .h files are processed by the compiler and will probably generate some errors.  For example a #include statement in a .h file will fail.  So don’t use .h files unless you are creating a library and know what you are doing.  Using .h files will produce errors claiming that a data type is not valid, or an include file cannot be found.

The .c and .cpp files are included in the compilation process but are compiled individually.  I think if they compile successfully everything comes together at the link step.  The process will fail if one file references a global variable or function declared in another file.  Using these extensions will produce errors complaining that something is not declared in this scope.

Based on some comments I saw on the forums I believe that .c files are complied a C code and .cpp files are complied as C++ code.  If you don’t know the difference then you have another reason not use use these extensions.

The .pde files are concatenated into a single file and then compiled as though it were one file.  It is pretty straight forward but will probably fail if you are not careful because…

Order Matters

I noticed that if I tried to use a function before it was defined that I got an error.   This issue is made worse when using multiple files until you understand the order in which they are concatenated.

Basically the .pde files are concatenated to the central .pde file in alphabetical order.

If your sketch is named foo.pde and you create files zabar.pde and bar.pde, then the order in which they will be concatenated is foo.pde + bar.pde + zabar.pde.  If foo.pde references a function declared in bar.pde you will get an error complaining that the function has not been defined.

So if you want the setup() and loop() functions to reference functions or global variables called out in other files they will need to be concatenated last.  I ended up putting them into a files z_setup.pde and z_loop.pde.  This way they are concatenated last and things work.

Conclusion

So, if you want to break your sketch into multiple files I have a few suggestions:

1. Put nothing in the central sketch file.  Maybe some comments, but really  not code.

2. Create a series of .pde files to hold the functions and global declarations you want to create.

3. Put the setup and loop functions into a file that will concatentate last.  I used z_setup.pde and z_loop.pde.

Debugging

The preferences file option “build.verbose=true ” is helpful when debugging.  During the build process it will dump out the commands it issues and you can figure out what temporary files are being created.  These files are cleaned up when you exit the IDE.  So you can view them and figure out what your code looks like after the concatenation process.

HP IR Remote Codes

I found a small remote that has the right buttons for my robot project. I found that it works when I put a good battery in it.

For future reference here are the codes it generates:

Button Code
Off/Off 8011040C
DVD 80118424
Music 80110447
Stop 80110419
Rewind 80118415
Play/Pause 80110416
Fast Forward 80110414
Louder 80118410
Previous Track 8011041B
Up 8011841E
Next Track 8011841A
Mute 8011040E
Left 80110420
OK 80110422
Right 80118421
Quieter 80118411
Up Level 80110423
Down 8011041F
Information 8011040F
Print 80110449
Camera 8011044E
Movie 8011044A
Monitor 8011044F

IRremote Library Notes

IRremote Library Page

The data transfer rate from remote to Arduino is not blistering.  It takes about 44ms per character.  Find for adjusting volume, not so great at swinging a servo 180 degrees one degree at a time.

The code checks the IR Receiver pin every 50 microseconds to see if there is a change in signal.  At 44ms per character and 50 microseconds per check, it takes about 880 checks to identify one character (this is with a Sony remote, perhaps others are faster).

I was a little concerned with the background cpu load.  I created an loop with some cpu intensive commands and tested it with and without the code running in the background.  Without the code running the loop ran in 3,226ms.  With the code running in the background it took 4,184ms.  My rough estimate is that it consumes ((4,184-3,226)/4,184) 23% of the CPU.  This was tested on an Arduino UNO with an ATmega328 running at 16MHz.

I used the following sketch to use the IR Receiver to operate two servos.

#include <Servo.h>
#include 

Servo servoElev;
Servo servoPan;

const int pinIR = 9;
IRrecv irrecv(pinIR);
decode_results results;

const int pinServoElev = 5;
const int pinServoPan  = 6;

const long codeLt = 0xDCB47;
const long codeUp = 0x9CB47;
const long codeDn = 0x5CB47;
const long codeRt = 0x3CB47;
const long codeHm = 0x42B47;

const int  stepSize = 1;
const int  delayMs  = 5;

unsigned long time    = 0;
unsigned long elapsed = 0;

unsigned long timeMs = 0;
unsigned long elapsedMs = 0;

int elevDegree  = 90;
int panDegree   = 90;

int loopcount = 0;
int charcount = 0;

void setup() {
  // initialize servos
  servoElev.attach(pinServoElev);
  servoPan.attach(pinServoPan);

  // enable IR Reciever
  irrecv.enableIRIn();

  Serial.begin(9600);
}

void loop() {

  loopcount++;

  // act if IR codes are pending
  if (irrecv.decode(&results)) {

    charcount++;

      // resume scanning for IR Codes
    irrecv.resume();

    switch (results.value) {
       case codeLt:
         panDegree = constrain(panDegree - stepSize, 0, 180);
         break;

       case codeRt:
         panDegree = constrain(panDegree + stepSize, 0, 180);
         break;

       case codeUp:
         elevDegree = constrain(elevDegree + stepSize, 0, 180);
         break;

       case codeDn:
         elevDegree = constrain(elevDegree - stepSize, 0, 180);
         break;

       case codeHm:
         elevDegree = 90;
         panDegree  = 90;
         break;

      } // switch statement

   // set position
   if (servoElev.read() != elevDegree) {
     servoElev.write(elevDegree);
   }

   if (servoPan.read()  != panDegree ) {
     servoPan.write(panDegree);
   }

   if (charcount >= 30) {
     elapsed   = (micros() - time)/30;
     elapsedMs = (millis() - timeMs)/30;
     Serial.print("Loop: ");
     Serial.print(loopcount);
     Serial.print(", Char: ");
     Serial.print(charcount);
     Serial.print(", microSec/char: ");
     Serial.print(elapsed);
     Serial.print(", millisec/char: ");
     Serial.print(elapsedMs);
     Serial.println();

     time = micros();
     timeMs = millis();
     loopcount = 0;
     charcount = 0;
   }

  } // if statement

  // pause
  delay(delayMs);

}

I used the following sketch to test the IR code CPU consumption:

#include 

// declare a constant to hold the pin to which the
// IR receiver is attached.
const int pinIR = 9;

// Instantiate and IR Reciever object passing the pin number
// as part of the setup.
IRrecv irrecv(pinIR);

// create a object to store the results
decode_results results;

unsigned long time;
unsigned long elapsed;
float foo;

void setup() {
  Serial.begin(9600);
}

void loop() {

  time = millis();

  for (int i = 0 ; i < 10000 ; i++) {
    foo = sqrt(i*3.14159);
    foo = sin(foo);
    foo = foo * sqrt(foo * 3.14159);
    foo = tan(foo);
  }

  elapsed = millis() - time;

  Serial.print("Elapsed time, without IR: ");
  Serial.print(elapsed);
  Serial.println();

  // enable the IR Reciever.  This starts a background process which
  // looks at the IR Reciever every 50 microseconds.
  irrecv.enableIRIn();

  time = millis();

  for (int i = 0 ; i < 10000 ; i++) {
    foo = sqrt(i*3.14159);
    foo = sin(foo);
    foo = foo * sqrt(foo * 3.14159);
    foo = tan(foo);
  }

  elapsed = millis() - time;

  Serial.print("Elapsed time, with IR: ");
  Serial.print(elapsed);
  Serial.println();

  delay(2000);

}

Digital Input vs Output

As a programmer I understand binary logic. Either it is a zero or a one. But the more I look into hardware I realize that the digital stuff looks very analog to me.

The ports on the Arduino seem to be Digital or Analog and Input or Output.

This will be my attempt to figure out what that means.

So I set up a couple of LEDs controlled by two different switches; a push button and a potentiometer.

Here is the sketch:

int pinRedLED    = 12;
int pinGreenLED  = 6;

int pinButton = 5;
int pinDial   = 11;

void setup() {
pinMode(pinGreenLED, OUTPUT);
pinMode(pinRedLED,   OUTPUT);

pinMode(pinButton, INPUT);
pinMode(pinDial,   INPUT);

}

void loop() {

digitalWrite(pinGreenLED, digitalRead(pinButton));

digitalWrite(pinRedLED, digitalRead(pinDial));

delay(100);
}

Now, I am breaking the rules here a bit by putting a potentiometer as a digital input rather than an analog input.  But I want to know more about what is going on.

Using a voltage meter I can see that when the pushbutton is not pressed the Arduino sees 5 volts on port 5 and the green LED is illuminated.  When the button is depressed it sees zero volts and the green LED goes off.

When the Potentiometer is all the way counter-clockwise the Arduino sees 5 volts on pin 11 and the red LED is illuminated.  When turned all the way clockwise pin 11 sees zero volts and the LED goes off.

But in between?

When the LED is illuminated it does off when the pin sees 2.3 volts.  When the LED is off, it is illuminated when the pin sees 2.5 volts.

So what is the difference between Input and Output?

It seems that on when configured for Input, the digital pin becomes a voltmeter and shows a state of HIGH when the voltage is more than 2.5 volts and a state of LOW when the voltage drops below 2.5 volts.

When configured for output when in the state of HIGH is produces 5 volts output (and about 5 mA when connected to an LED and 560 ohm resistor).  The manual says that the digital pins should be limited to 40 mA of load.

When configured for input it becomes a voltmeter (with I assume, high impedence).  Attaching the voltmeter to the pin and ground it appears to be an open circuit.

IR Remote

The goal of this experiment is to figure out if I can use a standard remote to communicate with the Arduino.

Here are some links:

Ken Shirriff has a nice page on IR remotes and a library you can use in your Aduino sketch.

Ken references another page with slightly more information.

The setup is pretty easy.  I used a Radio Shack 38khz IR Receiver Module (catalog number 276-640).

So I downloaded Ken’s library and setup a simple circuit connecting the IR Receiver to pin 9. 

And used the following sketch:

#include <IRremote.h>

int pinIR = 9;
IRrecv irrecv(pinIR);
decode_results results;

void setup() {
Serial.begin(9600);
irrecv.enableIRIn();
}

void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
irrecv.resume();
}
delay(20);
}

Opening the Serial Monitor window I could see the following:

3CB47
5CB47
5CB47
5CB47
5CB47

My Sony DVD player remote has the following button/code combinations:

button code
on/off A8B47
cursor left DCB47
cursor right 3CB47
cursor up 9CB47
cursor down 5CB47
cursor center BCB47
HOME 42B47

The next step will be to use the remote to control a pair of servos.