Tag Archives: arduino

Communication Between Arduinos Using I²C

There are many great resources for describing what I²C is, and how to read data from an I²C device with the Arduino. However, I couldn’t find any suitable page for how to use I²C for communication between two Arduinos. This is for version 1.0.3.

Hardware

The hardware setup is the same as any other I²C setup. Connect each Arduino’s A4 inputs to each other, and connect the A5 inputs together. They will need a pull-up resistor, however the Wire library enables the internal pull-up resistors when begin() is called.

This may be adequate for your uses, but as is discussed in Effects of Varying I²C Pull-Up Resistors, it’s a case of YMMV. If internal pull-up resistors do cause a problem, then you’ll have to comment out the following lines from the Wire/utility/twi.c soruce file.

[cpp firstline=”75″]// activate internal pullups for twi.
digitalWrite(SDA, 1);
digitalWrite(SCL, 1);[/cpp]

Software Overview

The structure of the master code and the slave code are very different, but neither is complicated. Because I²C does not define a data protocol, you’ll have to roll your own. It’s common to use a model where devices are manipulated through writing to registers, and reading values back.

The Master

The master’s code is synchronous, and wraps its communication between beginTransmission() and endTransmission() calls. It sends with the write() methods, and receives with the requestFrom() method.

Setup

Setup requires only one command, begin().

[cpp]
void setup()
{
// Start I²C bus as master
Wire.begin();
}
[/cpp]

Sending Data to a Slave

Sending data to a slave is done either by individual bytes, or in bulk. Here is a somewhat contrived example that sends the value of an analogue input pin to a slave every second. It writes bytes one at a time rather than using a buffer.

[cpp]void loop()
{
int input = analogRead(AnalogueInputPin);

// Send two bytes to slave.
Wire.beginTransmission(SlaveDeviceId);
Wire.write(input >> 8);
Wire.write(input & 255);
Wire.endTransmission();

delay(1000);
}
[/cpp]

Receiving Data from a Slave

Receiving data from a slave is done either by individual bytes, or in bulk. Here is another contrived example that receives the value in the prior section.

[cpp]void loop()
{
// Request data from slave.
Wire.beginTransmission(SlaveDeviceId);
int available = Wire.requestFrom(SlaveDeviceId, (uint8_t)2);

if(available == 2)
{
int receivedValue = Wire.read() << 8 | Wire.read();
Serial.println(receivedValue);
}
else
{
Serial.print("Unexpected number of bytes received: ");
Serial.println(available);
}

Wire.endTransmission();

delay(1000);
}[/cpp]

The Slave

The slave controller uses asynchronous callback functions for its communication. Slave mode is strictly reactionary — it receives or sends data only at the best of the master. The callbacks are set in the setup() function, the loop() function is empty, and everything happens in the callbacks.

Setup

Setup requires two commands. The first is to call begin() with the slave’s ID number.

[cpp]
const byte SlaveDeviceId = 1;

void setup()
{
// Start I²C bus as a slave
Wire.begin(SlaveDeviceId);

[/cpp]

The second is to set up the callbacks. Details are below.

Receiving Data from the Master

Data coming in to the slave from the master is handled in a single callback of the form

[cpp]void callbackName(int numberOfBytesBeingTransmitted)[/cpp]

This is registered in the setup() function by calling the onReceive() method.

[cpp]#include

const byte SlaveDeviceId = 1;

void setup()
{
// Start I²C bus as a slave
Wire.begin(SlaveDeviceId);
// Set the callback to call when data is received.
Wire.onReceive(receiveCallback);

// For demonstration purposes.
Serial.begin(9600);
}

void loop()
{
}

// aCount is the number of bytes received.
void receiveCallback(int aCount)
{
if(aCount == 2)
{
int receivedValue = Wire.read() << 8;
receivedValue |= Wire.read();
Serial.println(receivedValue);
}
else
{
Serial.print("Unexpected number of bytes received: ");
Serial.println(aCount);
}
}[/cpp]

Sending Data to the Master

Sending data to the master is also done asynchronously using a callback. When a request for data is received from a master, a callback is invoked. The callback must compose its reply in a buffer, then send the buffer all at once with a single call to write(). Note that the Write class performs no buffering for outgoing transmissions; any call to write() transmits the entire reply immediately.

Data coming in to the slave from the master is handled in a single callback of the form

[cpp]void callbackName()[/cpp]

This is registered in the setup() function by calling the onRequest() method.

[cpp]
#include

const byte AnalogueInputPin = 0;
const byte SlaveDeviceId = 1;

void setup()
{
// Start I²C bus as a slave
Wire.begin(SlaveDeviceId);
// Set the callback to call when data is requested.
Wire.onRequest(requestCallback);
}

void loop()
{
}

void requestCallback()
{
// Contrived example – transmit a value from an analogue pin.
int input = analogRead(AnalogueInputPin);

// To send multiple bytes from the slave,
// you have to fill your own buffer and send it all at once.
uint8_t buffer[2];
buffer[0] = input >> 8;
buffer[1] = input & 0xff;
Wire.write(buffer, 2);
}
[/cpp]

Sending and Receiving on the Same Slave

A single slave can both send and receive data by registering two callbacks. The appropriate callback is invoked automatically.

[cpp]
void setup()
{
Wire.begin(SlaveDeviceId);
Wire.onReceive(receiveCallback);
Wire.onRequest(requestCallback);
}
[/cpp]

“Gotchas”

The Wire library provides a convenient high-level wrapper for I²C. It has some oddities that will cause trouble if you’re not aware of them. Here are some gotchas.

Small Buffer

The Wire object‘s internal buffer is fixed at 32 bytes. You cannot send larger packets without modifying the library.

Asymmetric Behaviour

The write() method’s behaviour is different depending on whether the class is a master or a slave. See the sections on master and slave for details.

Type Coercion

The requestFrom() method’s overloads may confuse the compiler. If you get compiler errors, try coercing the parameters, for example:

[cpp]
const byte SlaveDeviceId = 1;

// Request data from slave.
Wire.beginTransmission(SlaveDeviceId);
int bytesReceived = Wire.requestFrom(SlaveDeviceId, (uint8_t)2);
[/cpp]

No Clock Stretching

The current version of the library does not support clock stretching.

Collisions Between Multiple Masters

I’m still looking into this more, but it appears that there is no mechanism for a master to wait for for a busy bus to clear. The transmission simply fails.

Code

I put some some demonstration code on GitHub.

Updates

16 Feb 2013
Update pull-up resistor information. Update “gotchas” section.

Adafruit Motor Shield

For some proof of concepts we bought Adafruit‘s motor shield kit.

 Assembly

The kit was easy to assembly following the instructions on the ladyada.net site. I recommend heeding the advice to use the 16-pin IC sockets and not soldering the L293D motor drivers to the board unless you’re experienced driving motors.

Use

Some of the information is scattered. For driving motors, Adafruit has a library available on github. Instructions can be found here.

Servos

Instructions for servos is sketchy. There are two servo connectors SER1 and SERVO2. According to the schematic, SER1 is connected to Arduino pin D10, and SERVO2 is connected to Arduino pin D9.

Headers

As the kit is, there is no way to stack a shield on top of the motor shield, or make easy connections for proofing. For my purposes, I added female headers to the shield using the holes parallel to the male headers. An alternative would be to use stacking headers instead of the provided male headers.

Headers added to the motor shield.

 

 

Hallowe’en Eyes

This is a small Arduino project our family did for Hallowe’en.

In the old cartoons, dark forests were shown as black backgrounds with mysterious eyes that would glow in the dark, often blinking or opening and closing.

httpv://www.youtube.com/watch?v=y77RqZNGPzQ

Hardware

The electronic hardware is very simple: multiple Arduino digital outputs sporting 330Ω resistors and an LED.

Schematic Overview

Mounting the Eyes

Each LED is mounted in a cardboard toilet paper tube with eyes cut out.

  1. Hold the tube horizontally in front of you.
  2. Cut large eyes in the middle of the tube. Use your imagination to get different expressions.
  3. Cover the eye openings with wax paper or cooking papyrus to act as a diffuser.
  4. Secure with tape.
  5. Cover the ends of the tube with aluminum foil and secure with tape.
  6. Make a hole directly opposite the eyes, and mount the LED, ensuring it’s pointing between the eyes.
  7. Secure the LED with tape.

Run pairs of copper wire from where the eyes will hide in the bushes to the Arduino. (Ensure the Arduino is protected from the weather. I put mine in a small cooler.) Check all connections and connect the battery to the Arduino.

Be sure to use a battery that has enough capacity to run all the lights and the Arduino for several hours. I used a small hobby 6V lead-acid battery.

Software

This is a glorified “blink” program; nothing amazing going on here.

The software consists of a simple coöperative multitasking core that runs simple processes in a round-robin fashion.

Each process has a references to a master array oftapes, or eye programs.

  1. If the processes is sleeping and has not reached its wake time, return.
  2. If the process has no active tape, or reached the end of the tape, choose a new tape at random from the master array of tapes.
  3. Play the instructions at the current tape position.
    1. Turn the LED on or off, as instructed.
    2. Choose a future wake-up time as instructed.
  4. Increment the current tape index.
  5. Return.

As you can see, there’s nothing terribly complicated about any of this. The software may be found on GitHub here.

Including Libraries in the Arduino IDE

There’s an annoying subtlety in the Arduino IDE when using tabs (multiple files in the sketch), that was kindly explained by PaulS on the Arduino forums.

Any Arduino libraries that are needed by the files outside of the sketch (.ino) file must also be listed in the sketch file itself.

Example

You cannot simply do this:

[cpp light=”true”]example.h:

#include <Servo.h>[/cpp]

When you attempt to compile, you’ll get an error like,

In file included from test_junk_02.cpp:1:
test.h:7: error: 'Servo' does not name a type

You must also include the library in the sketch:

[cpp light=”true”]test.ino:

#include <Servo.h>
#incude "example.h"[/cpp]

Explanation

The explanation that PaulS gave was the following:

The sketch is parsed for include files. The sketch, all included header files, and the corresponding source files, are copied to another directory for compiling. From that directory, library-based include files are NOT available unless they are included in the sketch and copied to the build directory.

Multiple Source Files with the Arduino IDE

Granted, the Arduino IDE isn’t conducive to heavy-duty projects, but it’s useful for quick and dirty programs.

Once you outgrow a single file and wish to break the project up into multiple files, you can do so in the Arduino IDE with multiple tabs. Each tab represents a single file stored in the same directory as the sketch file (.ino).

You create new tabs using the drop-down menu that appears by clicking on the inverted triangle above the upper right-hand corner of the editor.

Showing the Tab Menu in the Arduino 1.0.1 IDE

Note that unlike the sketch’s main .ino file, you will not have automatic access to the Arduino basic definitions. That is easily remedied by including

#include "Arduino.h"

Happy Hacking.

Library Warning

Please note that there is a quirk in the Arduino IDE that can prevent libraries from being included in the compile. The IDE requires all libraries to be #include’d in the main (.ino) file. If you do not do this, the library will not be included, and you’ll get errors during compile.

How It Works

When compiling, the IDE copies all the files to a temporary directory. It scans the .ino file for libraries, and copies the library files to the temporary directory. Finally, it does the actual compile. If you #include a library in any of the tabbed files, but not in the .ino file, the library will not be available to the parser. The IDE only scans the .ino file for libraries.

 

A Practical Adruino Prototyping Platform

I’ve been asked by several people to post some basic information about what I’m doing.

Once you start working with the Arduino, you find immediately that you need a breadboard to punch out some simple circuitry. Then you find that having the breadboard and Arduino side by side is a little inconvenient.

I’ve made a few small platforms that have the Arduino, breadboard, and extra space as a single unit. These have been very convenient as the entire assembly can be moved around as desired without upsetting any of the wiring. They are not elegant, but functional.

I go down to a hardware store that sells flooring, such as Lowe’s. I buy two of the larger Pergo flooring samples, then glue them together (1 and 2 in  the image below) with carpenter’s glue. I then attach the Adruino (A) and the breadboard (B) as pictured, leaving a little extra room (C) for attaching other hardware as needed.

Click to Enlarge

I’ve been wary about permanently attaching the expensive Arduino to a piece of cheap wood, so I drilled eight holes through which I ran tiny zip ties. This holds the Arduino securely, does not harm the Arduino, and if the need arises in the future, it can be detached easily.

Click to Englarge

Update 20 July 2012:

Why use wood? Isn’t that kind of, well, hick? Well… it may be. It certainly has a backwoods flavour to  it. However, wood has the virtue of being easily hackable. Most especially items can be secured to the board with screws, zip ties, gaffer’s tape, etc.  Some examples:

On one board I drilled holes to secure a multi-wise sensor cable with a zip tie (one hole on each side of the cable). No matter where I carried the board to do sensor calibration, there was no risk of the wires being ripped off the breadboard.

Here is a bracket for a 9V battery used to power an Arduino.

9V Battery in Bracket Powering an Arduino

Gaffer’s tape is expensive, but it doesn’t produce the messy residue that duct tape is prone to leave behind. (This breadboard is rather crudely attached with screws.)

6V AGM Battery on the Pergo Board

I hope that this gives a few ideas that might prove useful.