If you are building a tmp sensor arduino project for environmental monitoring, incubator control, or thermal profiling, the analog TMP36 is no longer sufficient. The modern benchmark for high-precision digital temperature sensing is the TMP117. It communicates over I2C and delivers ±0.1°C accuracy from -20°C to 50°C without requiring user calibration. This guide provides the exact hardware specifications, raw I2C code with robust error handling, and a debugging framework to resolve the most common Wire.h timeout failures.

TMP117 vs TMP102 vs TMP36: Which Sensor Do You Actually Need?

Before wiring the breadboard, verify that you actually need the TMP117. Over-specifying a sensor wastes budget and I2C bus capacitance, while under-specifying leads to noisy data. Here is how the common Texas Instruments TMP series sensors compare for embedded builds.

Feature TMP117 (Digital I2C) TMP102 (Digital I2C) TMP36 (Analog)
Accuracy (at 25°C) ±0.1°C ±0.5°C ±2.0°C
Interface I2C (up to 1MHz) I2C (up to 400kHz) Analog Voltage (ADC)
Resolution 0.0078125°C (16-bit) 0.0625°C (12-bit) 10mV/°C (ADC dependent)
Operating Voltage 1.8V to 5.5V 1.4V to 3.6V 2.7V to 5.5V
Typical Breakout Cost ~$4.50 - $6.00 ~$1.50 - $2.50 ~$1.00 (bare chip)
Best Use Case Medical, lab, precision thermal General room weather stations Basic hobbyist, high-noise tolerance

Source: Texas Instruments TMP117 Datasheet

Bench Note: The TMP117's 16-bit resolution means the raw ADC noise floor of an Arduino Uno will completely ruin the data if you try to use an analog sensor. Stick to I2C digital sensors like the TMP117 for anything requiring sub-degree precision.

Hardware Spec Sheet & Pin Mapping

This build targets the Arduino Uno R3 (ATmega328P) or Arduino Nano v3. We are using the Adafruit TMP117 Breakout Board (Product ID: 5092) because it includes the necessary 3.3V LDO, logic level shifting, and 10kΩ I2C pull-up resistors. If you are using a bare TMP117 chip, you must provide external 4.7kΩ pull-ups on SDA and SCL.

Required Parts List

  • Microcontroller: Arduino Uno R3 or Nano v3 (5V logic)
  • Sensor: Adafruit TMP117 Breakout (ID: 5092) or SparkFun TMP117 (SEN-15805)
  • Wiring: 4x silicone stranded jumper wires (26 AWG)
  • Power: USB 5V or external 7-12V DC barrel jack

Pin Mapping Table

TMP117 Breakout Pin Arduino Uno R3 Pin Function & Notes
VIN 5V Powers the onboard LDO. (Use 3.3V pin if bypassing LDO).
GND GND Common ground reference.
SCL A5 I2C Clock. (On Nano, this is also A5).
SDA A4 I2C Data.
ADDR Leave Unconnected Ties to GND internally. Default I2C address: 0x48.

Step-by-Step Wiring & I2C Pull-up Considerations

  1. De-energize the board: Unplug the Arduino USB cable before making I2C connections to prevent accidental shorting of the SDA/SCL lines to VCC.
  2. Connect Power: Route the Arduino 5V pin to the breakout VIN. Connect GND to GND. The Adafruit board regulates this down to 3.3V for the TMP117 chip safely.
  3. Connect I2C Data Lines: Connect Uno A4 to breakout SDA, and Uno A5 to breakout SCL.
  4. Verify Pull-up Resistors: The ATmega328P has internal pull-ups of roughly 30kΩ. These are too weak for reliable 400kHz I2C communication. The Adafruit breakout includes 10kΩ pull-ups. If you are wiring multiple I2C devices on the same bus, the parallel resistance will drop. Keep the total bus pull-up resistance between 2.2kΩ and 10kΩ.
  5. Set the Address: Leave the ADDR pin floating. The breakout has an internal pulldown, setting the 7-bit I2C address to 0x48. Soldering the ADDR jumper to VCC changes the address to 0x49.

Complete Arduino Code with Error Handling

Many tutorials rely on heavy third-party libraries that mask I2C bus failures. The code below uses the native Wire.h library to read the 16-bit two's complement temperature register (0x00) directly. It includes strict error handling for NACK (Not Acknowledged) responses and bus timeouts, preventing the Arduino from hanging indefinitely if the sensor disconnects.

#include <Wire.h>

// --- PIN & ADDRESS DEFINITIONS ---
// Arduino Uno/Nano I2C pins are hardcoded in Wire.h (A4=SDA, A5=SCL)
#define TMP117_I2C_ADDR 0x48 
#define TMP117_TEMP_REG 0x00
#define TMP117_RESOLUTION 0.0078125 // °C per LSB

// --- ERROR STATE FLAGS ---
bool sensorFault = false;

void setup() {
  Serial.begin(115200);
  while (!Serial) { delay(10); } // Wait for serial port (Leonardo/Micro)
  
  Serial.println("TMP117 Raw I2C Initialization...");
  Wire.begin();
  Wire.setClock(400000); // Set I2C to 400kHz Fast Mode
  
  // Initial bus scan to verify connection
  Wire.beginTransmission(TMP117_I2C_ADDR);
  byte error = Wire.endTransmission();
  if (error != 0) {
    Serial.print("FATAL: Sensor not found. endTransmission() error: ");
    Serial.println(error);
    sensorFault = true;
  } else {
    Serial.println("TMP117 found at 0x48.");
  }
}

void loop() {
  if (sensorFault) {
    Serial.println("[HALT] I2C Bus Fault. Check wiring and reset.");
    delay(5000);
    return;
  }

  // 1. Point to the Temperature Register
  Wire.beginTransmission(TMP117_I2C_ADDR);
  Wire.write(TMP117_TEMP_REG);
  uint8_t status = Wire.endTransmission();

  // 2. Handle I2C Write Errors
  if (status != 0) {
    Serial.print("I2C Write Error: ");
    Serial.println(status); // 2 = NACK on address, 3 = NACK on data
    delay(1000);
    return;
  }

  // 3. Request 2 bytes of data
  uint8_t bytesReceived = Wire.requestFrom(TMP117_I2C_ADDR, 2);
  
  if (bytesReceived == 2) {
    // Read MSB then LSB
    int16_t rawTemp = (Wire.read() << 8) | Wire.read();
    
    // Convert to Celsius
    float tempC = rawTemp * TMP117_RESOLUTION;
    float tempF = (tempC * 9.0 / 5.0) + 32.0;
    
    Serial.print("Temp: ");
    Serial.print(tempC, 4); // Print to 4 decimal places to see noise floor
    Serial.print(" °C  |  ");
    Serial.print(tempF, 2);
    Serial.println(" °F");
  } else {
    Serial.println("I2C Read Error: Bus timeout or incomplete packet.");
  }

  delay(1000); // 1Hz sampling rate
}

Debugging: "Wire.h Timeout" and "NaN" Readings

When working with I2C sensors on the bench, you will inevitably encounter bus lockups or garbage data. If your serial monitor outputs I2C Write Error: 2 or NaN, do not immediately assume the sensor is dead. Follow this diagnostic sequence.

The First Three Things to Check

  1. Verify VCC vs. Logic Levels: The raw TMP117 chip has an absolute maximum VCC of 5.5V, but it is optimized for 3.3V. If you are using a bare chip (no breakout) and wired it to the Arduino's 5V pin, you may have damaged the silicon. Always use a breakout with an LDO or power the bare chip from the 3.3V pin.
  2. Check for Swapped SDA/SCL: The Uno R3 silkscreen for A4 and A5 is small and easily misread. endTransmission() error: 2 (NACK on address) almost always means the I2C address is wrong, the chip is unpowered, or SDA/SCL are crossed.
  3. Inspect the ADDR Pin State: If the ADDR pin is accidentally shorted to VCC (or if your breakout board has the jumper bridged to VCC), the sensor will respond to 0x49, not 0x48. Run an I2C scanner sketch to verify the active address on the bus.

Common Error Strings and Ranked Causes

Exact Serial Output Meaning Most Likely Causes (Ranked)
I2C Write Error: 2 NACK on Address transmit 1. SDA/SCL swapped.
2. Sensor unpowered.
3. ADDR pin pulled high (Address is 0x49).
I2C Read Error: Bus timeout Wire.requestFrom() failed to clock in 2 bytes 1. Missing I2C pull-up resistors.
2. SCL line shorted to GND.
3. I2C bus capacitance too high (wires > 30cm).
Temp: NaN °C Math operation failed (usually division by zero or uninitialized float) 1. Code logic error (reading empty Wire buffer).
2. Using a 3rd-party library that returns NaN on I2C timeout instead of throwing an error state.

Reference: Arduino Wire.endTransmission() Documentation

Extending the Build: Data Logging and Thermal Mass

Once you have stable ±0.1°C readings, the next step is usually data logging or remote transmission. Here is how to scale the project without compromising the sensor's accuracy.

How to Extend: SPI SD Card Logging

Because the TMP117 uses I2C, you can safely add an SPI-based MicroSD card module (like the Adafruit MicroSD Breakout, ID: 254) without bus conflicts. Wire the SD module to the Uno's hardware SPI pins (11, 12, 13) and use a dedicated digital pin for Chip Select (CS). Log the timestamped temperature data to a CSV file at 1Hz. Ensure you use a 3.3V SD module or a level shifter, as SD cards will not tolerate 5V logic on the MOSI/CLK lines.

How to Simplify: Switching to TMP102

If you realize your application only requires ±0.5°C accuracy (e.g., a basic room thermostat or weather station), you can simplify the BOM and reduce costs by swapping the TMP117 for a TMP102. The I2C register map is slightly different (the TMP102 uses a 12-bit format), but the physical wiring and pull-up requirements remain identical. This drops the sensor cost from ~$5.00 to ~$1.50 per unit in bulk.

Thermal Mass Warning: The TMP117 is incredibly sensitive. If you mount it inside an enclosure, the heat generated by the Arduino Uno's onboard 5V linear regulator will create a localized thermal gradient, skewing your readings by 1.5°C to 3.0°C. Always mount the TMP117 on a short breakout cable outside the main microcontroller enclosure, or use a remote sensor topology.