Introduction
(skip this if you just want to know about TC74’s and Arduinos)
The first post of the season will be about my new love. I’ve been hacking software for a looong time now, but the last time I did any serious hardware stuff was back in high school.
And I’m glad to say that I forgot almost everything about it. I seem to remember some guy named Ohm being important, but that’s about it. But, lack of knowledge aside, writing code that, at best, changes a few pixels on a screen is a somewhat limited domain. I wanted to make something cool, something that moves, something interesting.
Arduino to the rescue! are awesome little things that let you play with electronics in a fun and easy way. At it’s heart lies a programmable chip (an ATmega168 to be precise), which you can attach stuff to. All kinds of stuff! There are dozens of examples of stuff being attached to arduinos in order to make them flash, vibrate, move, dance and sing to be found on the web.
And I’m not going to write about flashing leds or controlling servos. I’m going to do something a little bit more complex. I’ve been playing with my arduino for a couple of weeks now (mostly during weekends) and I’ve built a little robot around it (which I’m sure I’ll write about another time). One of the problems you start facing when building large, complicated things, is that you are going to run out of ports to connect stuff to. The currently “standard” Arduino Duemilanove has 13 digital I/O ports, and 5 Analog IN ports. This is plenty for basic sensor input, driving a dc motor through a controller and a few servos on the side (in short, plenty for a robot). But if you want to control a few dozen leds independently you’ll be out of luck.
That’s where buses come in. They allow communication in a standardized form over a smaller number of wires than you would need to attach the components on the bus to your controller separately. I had of course read about them, in some computer science class a couple of years ago, but never used a bus directly. Abstraction layers make your life easier, and I am lazy. I work at least levels above bus level usually.
I2C
The TC74 temperature sensor I hooked up today uses an I2C bus. This bus has been designed here, in the Netherlands, by Philips. It requires only two wires, and has a 7 bit addressing space (if that doesn’t mean much to you, think: “you can hook up a lot of things to just 2 ports on your Arduino”).
Starting out with low-level bus communication for a person like me is… Difficult at best. I spent 2 hours just hooking up a single digital sensor, which would have taken me 5 minutes were it a “normal” analog sensor. You’ll need skills like Binary-To-Hexadecimal conversion and a hacker attitude. You will have to pay closer attention to datasheets than usual, because it’s harder to troubleshoot things when they go wrong. But don’t let that scare you away, there are a lot of benefits to using serial communication with your components, most of all that you need two wires to hook up a whole bunch of stuff.
Arduino has a library for I2C communication, which you can include in your sketch like:
1 2
| #include "Wire.h"
//wire library |
There is a reference page for the Wire library, but don’t expect too much from it. Wire (why didn’t they just call it I2C?) takes care of some of the communication details, but you will still need to know intimate details of the communication protocol, as it differs from part to part.

Connecting the sensor to the relevant ports is easy enough. There are only 4 wires that matter, there is the standard +5V and GND connectors, which go to the +5V and GND connectors on your arduino (durrr), and then there’s two wires for I2C. One is a clock line (SCL, sometimes written as SCLK), which is controlled by the master (your Arduino), and can be thought of as the rhythm section of an orchestra. Communication is a series (hence “serial communication”) of 1s and 0s, and they are “measured” on each “beat” of the clock line. When using the Wire library, your Analog Input 5 is automagically set up as the SCL line. On a TC74, the second wire from the left is SCL. The other wire in the I2C setup is the data wire (SDA), which is the wire that is either high for 1, or low for 0, synced with the clock.
The difficult part about bus communication is that you need to specify specific addresses for each component added to the bus. These addresses can sometimes be set with control pins, but for the TC74 they are set in the factory. An address is 7 bits long, and for the TC74 the first 4 bits are always 1001. The most common TC74 sensor, the TC74A5 has the address of 1001101 (101 is binary for 5). There’s a whole series of TC74’s, from TC74A0 (address 1001000) to tc74A7 (1001111). Do you see the connection? Well I didn’t, at first. I didn’t realize that my sensor was an A7 model, which led to extreme frustration as I tried to communicate with a non-existent component on the bus.
So how does this communication actually work? Well to start you’ll have to tell the Wire library to set your Arduino up as a bus master:
1 2 3 4 5 6
| void setup()
{
Wire.begin();
//the begin() method accepts an address parameter
//but that would make your arduino into a slave
} |
Communication is set up into blocks. A master initializes it by writing the address (that’s 7 bits, remember?) of the component it wants to talk to on the SDA line, with the last bit being either 0 for read, or 1 for write. Making it into a block of one byte long. Don’t worry about the read/write stuff, we’ll get to that. In Wire code, beginning a conversation with your TC74 sensor would look like:
1 2 3 4 5 6 7 8 9 10 11
| #define address 0x4F
//the address of the sensor, in hex, it's the equivalent of 1001111
//which is the address found in the datasheet of my sensor
//this may seem complicated if you've never seen hex before
//for a TC74A5 it would be 0x4D
void setup()
{
Wire.beginTransmission(address);
//start the transmission
} |
Now, in the datasheet for your component you’ll find a timing diagram. It specifies what the component expects at certain points during communication. There will be references to “registers” and “commands”. Usually you’ll issue a command to either read or write something from a register. What the component does with the value of a register is of course dependent on what kind of component it is. For our TC74 temperature sensor, you can read a register that contains… The current temperature.
The command to “read” the register is 0×00 (that’s hex), which is found in the datasheet. After that, the datasheet says, you have to repeat the address of the slave in read mode. This means that you put the 7 bits of the address on the SDA line, but with a 1 following it, and not a 0 (which was how beginTransmission() put it on the line). After that we can read the value, which is a single byte with the temperature in Celsius:
1 2 3 4 5 6 7 8 9 10 11 12
| Wire.beginTransmission(address);
//start the transmission by writing the slave address
Wire.send(0x00);
//send the command to read the temperature
Wire.requestFrom(address, 1);
//read 1 byte from address
//this re-broadcasts the address in read-mode
int temperature;
if (Wire.available()) {
//check if we can read
temperature = Wire.receive();
} |
Now our integer “temperature” holds the current temperature. In theory. If something went wrong it’ll hold 0, which is a valid temperature (a little too cold to be working with small electronic components though
). It would be best to add an else-clause to the if-clause and do something meaningful.
A full sketch that reads the temperature and puts it on the serial line looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include "Wire.h"
//wire library
#define address 0x4F
//address of the temperature sensor
#define delayC 1000
//delay count in ms
#define baudrate 9600
//baudrate for communication
void setup()
{
Wire.begin();
Serial.begin(baudrate);
}
void loop()
{
Serial.print("temperature in Celsius: ");
//let's signal we're about to do something
int temperature;
//temperature in a byte
Wire.beginTransmission(address);
//start the transmission
Wire.send(0x00);
Wire.requestFrom(address, 1);
if (Wire.available()) {
temperature = Wire.receive();
Serial.println(temperature);
} else {
Serial.println("---");
}
Wire.endTransmission();
//end the transmission
delay(delayC);
} |
I hope this was a little helpful to you. I found it a bit hard to start with I2C because of a lack of documents on the web written for noobs like me. If you want to read more, I would suggest the following resources that detail specifically with Arduino’s I2C support: