17. Building an I2C-based Digital Thermometer

The Theory

How I2C is different from SPI

By giving each device an address, we can drop the SS line. By forcing all communication to occur on one wire, we drop MISO/MOSI. This means communication is half-duplex and bidirectional.

Voila! Just like that we’ve arrived at 2 wires – SDA/SCK. Contrast this with 4 wires for SPI.

How I2C Works

SDA can only toggle when SCK is low EXCEPT for START/STOP conditions.

Data is only read when SCK is high.

Every I2C transaction begins with a 7-bit address.

Since SDA is bidirectional, we attach an 8th bit, the R/W bit. This conveys the direction of communication flow. If its set, the Master is receiving (or READING) data. If pulled low, Master is WRITING data.

If the Master or Slave receives data, they must either ACK or NACK. This is a 9th-bit sent after every byte. SPI doesn’t have this error detection. Therefore, an I2C data transaction is always 9 bits long.

START/STOP conditions are generated exclusively by the master. Thus, the slave is unable to initiate or terminate conversation. It’s response is received via ACK/NACK.

I2C Data Logger

Let’s combine 2 communication protocols, I2C and UART to design a temperature data logger.

NOTE: This project can be reconfigured to serve as a data logger for any sensor.

UART will be used to extract the data and to present a UI/Menu.

Data is stored in EEPROM.

Project 1 – I2C Thermometer

Initially, we’ll do the thermometer, then we’ll integrate the 25CL256 to create a temperature logger.

Hardware Connections

The schematic is located in my GitHub repository.

The Software

This project consists of an I2C driver and main.c. Full source code available in my GitHub repository. Thanks to the hardware I2C/TWI, the software is quite sparse. The hardware is doing the majority of the heavy lifting.

NOTE: Pay attention to the MakeFile. Some files are imported from folders with specific file locations.

main.c uses the i2c driver to communicate with the LM75. It uses I2C to read the temperature from the LM75 and transmits it via UART.

The information below contains the address of the LM75

The first 4 digits 1001 is hard-wired to the LM75. The other 3 is determined by the connections to A0, A1, A2. Since their all grounded, the address this is 000. That is 4 + 3 = 7 bits. This is a standard I2C 7-bit address.

#define LM75_ADDRESS_W          0b10010000  
#define LM75_ADDRESS_R          0b10010001 

The last bit, LSB is R/W bit. A Read = 1, Write = 0. Recall that an I2C address is 7-bits. Last bit is R/W bit. When we want to send data we send 1001000. When we want to read data we send 10010001.

The Showcase

You can see when I bring fire close to the sensor, it’s readings increase (as it should).

Project 2 – Logging Thermometer

Now that I’ve validated the LM75 temperature sensor works, let’s add a 25LC256 EEPROM IC to develop a temperature logger.

Upon power-up, a menu appears where the user can interact with the logger. If no selection is made, the menu times out and resumes logging.

Hardware Connections

2 devices are connected to the I2C bus.

The schematic is available in my GitHub repository.

The Software

NOTE: The I2C and 25LC256 driver from previous projects are re-used. Hooray for code re-usability. Full source code available at the GitHub repository.

The Showcase

Project 3 – Logging Thermometer with time-stamped readings

I left the temperature logger logging overnight. It accrued 248 readings. However, without a timestamp, the readings are meaningless. I can’t interpret this.

Let’s add a DS3231 RTC IC and time-stamp each sensor reading.

Here are the new additions:

  1. The readings are dumped into a .csv file
  2. A Python script automatically plots it

Hardware Connections

We have 3 devices connected on the I2C bus.

The schematic is available in my GitHub repository.

Circuit prototyped on a breadboard

The Software

The source code is expanded with the addition of the DS3231 driver and two scripts. Full source code available at the GitHub repository.

The Showcase

After I run make plot, it executes the Python script, generating a beautiful time-stamped log.

NOTE: The dip at the bottom at 11:45 – 12:00 is deliberate as I transported the circuit into the garage. Afterwards, I transported it into the room and cranked up the heater. This explains the subsequent rise in readings.

A plot of time-stamped sensor readings