Tuesday, August 19, 2014 5:00 pm

Sparkfun TMP102 Temperature Sensor: Network and I2C connectivity with a NetBurner Device

Written by 
Rate this item
(0 votes)

This article will demonstrate how to interface a NetBurner device to the Sparkfun TMP102 temperature sensor using the I2C communication bus. The temperature readings can be read through the serial port of the NetBurner device, and will also be visible on the device’s web page. The web page will use Ajax (a type of javascript) to continuously update the reading without reloading the web page.

The NetBurner module used in this example is the Nano54415-200IR. Both the module and the temperature sensor are quite small:

Hardware Configuration:

The RS-232 Serial connection is only necessary if you want to run a serial terminal to view the status messages.

I2C Wiring from Nano to TMP102:

The TMP102 only needs 4 signals: I2C Clock, I2C Data, Vcc and Gnd. The table below shows the connections for both the Nano module’s P1 edge connector and the P3 connector on the Nano development board.

Signal Dev Board Nano Module
I2C0_SCL P3.27 P1.27
I2C0_SDA P3.29 P1.29
VCC 3.3 P3.47 P1.47
GND P3.48 P1.48

Source Code Files

The program was written in C/C++ using the NetBurner Network Development Kit. You do not need to know C++ to use the driver. The project consists of the following files:

main.cpp	Initialize the system and print temperature readings to the serial port
TMP102.h	Header file for TMP102 driver
TMP102.cpp	Source file for TMP102 driver
index.htm	Index web page. Contains the script code to update readings
reading.htm	The script code will load this page to update the temperature reading

TMP102.h Header File

The header file defines a very simple TMP102 C++ object. The public keyword means those data/functions can be accessed anywhere the object is used. The private keyword means those data/functions can only be used from within the class. For example, getSensorAverage() can call write8(), but write8() cannot be called by functions outside the class.

The constructor and destructor get called when an object is created or released, but they do not do anything in this example. The init() function is called to initialize the I2C bus. getSensorAverage() will take as many readings as it can over the specified time period, then average the results and return the average. The _addr variable is the I2C address of the TMP102. The write8() and read8() write and read 8 bits on the I2C bus.

#ifndef TMP102_H_
#define TMP102_H_

class TMP102 {
	TMP102();					// constructor
	virtual ~TMP102();				// destructor
	void init();					// initialize the sensor
	int getSensorAverage(uint seconds);	// Take readings and average
	int8_t _addr;						// I2C address of sensor
	uint8_t write8(uint8_t reg, uint8_t value);	// Write 8 bits over I2C
	uint8_t read8(uint8_t reg);			// Read 8 bits over I2C

#endif /* TMP102_H_ */

TMP102.cpp Source Code File

The implementation of the functions are shown below. The notation “TMP102::” means that the functions are part of the TMP102 class. The functions I2CInit() and I2CSendBuf() are part of the NetBurner I2C master library.

/* Initialize the I2C bus. There are multiple I2C ports, we are using 0 */ 
void TMP102::init() {
    I2CInit();		// Init the Nano I2C0 bus signals
    _addr = 0x48;		// I2C address of sensor

/* Take readings for the specified number of seconds and average the 
 * results. Readings are taken at approx. 50ms intervals.
int TMP102::getSensorAverage(uint seconds) {
	int samples = 0;
	int avg = 0;
	uint timeNow = Secs;
	while ((Secs-timeNow) < seconds) {
		avg += read8(0x00);	// read sensor register 0
	int c = (avg / samples);
	int f = 1.8 * c + 32;
	return f;

/* Use I2C to read a byte from the specified register */
uint8_t TMP102::read8(uint8_t reg) {
    uint8_t rx = 0;
    int status = I2CSendBuf(_addr, &reg, 1);
    if ( status != I2C_OK )
    	iprintf("Error calling I2CSendBuf()\r\n");

    status = I2CReadBuf(_addr, &rx, 1);
    if ( (status != I2C_OK) && (status != I2C_NEXT_READ_OK) )
    	iprintf("Error %d calling I2CReadBuf()\r\n", status );
    return rx;

/* Use I2C to write a byte to the specified register */
uint8_t TMP102::write8(uint8_t reg, uint8_t value) {

    int status = I2CSendBuf(_addr, &reg, 1);
    if ( status != I2C_OK )
    	iprintf("Error calling I2CSendBuf()\r\n");

    status = I2CSendBuf(_addr, &value, 1);
    if ( status != I2C_OK )
    	iprintf("Error calling I2CSendBuf()\r\n");

    return status;

Main.cpp Source File

The main.cpp file contains two functions. Since the real-time operating system is always running, think of UserMain() as you would a C main() function. The difference is that in an RTOS, it is a task. UserMain() has a fairly simple purpose: it initializes the network stack, starts the web server, creates a TMP102 object named “sensor”, then calls the it’s initialization function. An infinite while loop is then entered in which temperature readings are averaged over 2 seconds, the gTemp variable is updated (for use by the web interface), and the average is printed to the RS-232 serial port.

The function webDisplayTemp() is automatically called any time someone accesses the web server of the Nano. The HTML pages do the formatting and display all of the static information. The sole purpose of this function is to convert the integer temperature value to a string and send it to the web browser client. This is done with the FUNCTIONCALL tag which you will see when we describe the web page source code. One way to visualize the interaction is to think of the web server response to the web browser as a real-time stream of data. When a FUNCTIONCALL tag is encountered the web server transfers control to the webDsiplayTemp() function, which sends the temperature average as an ASCII string, then returns control back to the web server.

const char * AppName="I2C Temp Sensor Example";

int gTemp; 	// global temperature variable

 * Function to display temp on web page
 *  sock = Active tcp socket handle passed by the web server
 *  url  = The URL sent by the web browser
void webDisplayTemp( int sock, PCSTR url )
	char strTemp[16];

	if ( (gTemp < -100) || (gTemp > 200) )
		strcpy( strTemp, "NaN" );
		siprintf(strTemp, "%d", gTemp );

	writestring( sock, strTemp );

 * UserMain
void UserMain(void * pd)
	init();	// Initialize network stack
	StartHTTP();	// Start web server

	iprintf("Application started\n");
	TMP102 sensor;	// Create temp sensor object
	sensor.init();	// Initialize sensor and I2C interface

    while (1) {
    	// Write readings to serial port. Take average over 2 seconds
    	gTemp = sensor.getSensorAverage(2);
    	iprintf("Sensor Reading: %d\r\n", gTemp);


The index file contains both HTML code and Ajax (asynchronous JavaScript and XML). Ajax is what makes the web page updates smooth and flicker-free. A web application can send data to, and retrieve data from, a server in the background without interfering with the display and behavior of the existing page. The script will continually run and update the temperature value, without the user having to reload the web page. The initialize() function specifies the function to call (processAjax), the URL to send (reading.htm), the variable to update (TEMP), and the time interval (200ms).

The processAjax() function causes the client browser to send a HTML GET request to the server for reading.htm, which returns just the average temperature value. The getData() function take the GET result and stores in in the temp (short for temperature) variable. The HTML code outside the “script” tags displays the images and static text.


<script type="text/javascript">
    temp=0;		// temperature variable
    function initialize() { //dummy stamp tricks IE into loading a page it wants to cache
    	setInterval("processAjax('reading.htm?dummy=' + new Date().getTime(),'TEMP')", 200);
    function processAjax(url,txt) {
	dataLd = txt; 
	if (window.XMLHttpRequest) { // Non-IE browsers
		req = new XMLHttpRequest();
		req.onreadystatechange = getData;
		try {
			req.open("GET", url, true);
		} catch (e) {
		// alert(e);
	} else if (window.ActiveXObject) { // IE
		req = new ActiveXObject("Microsoft.XMLHTTP");
		if (req) {
			req.onreadystatechange = getData;
			req.open("GET", url, true);

	function getData(){
     		if (req.readyState == 4) { // Complete
			if (req.status == 200) { // OK response
				temp = req.responseText;
				document.getElementById(dataLd).innerHTML = temp;
			} else {
				// alert("Problem: " + req.statusText);

<title>NetBurner I2C Demo With Sparkfun TMP102</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<body bgcolor="#FFFFFF" text="#000000" onload="initialize()">
<table width="655" border="0" cellspacing="0" cellpadding="0" height="121">
    <td width="200"><a href="http://www.netburner.com"><img src="/images/logo.jpg" width="200" height="104" border="0"></a></td>
    <td width="53"> 
      <div align="center"><b></b></div>
    <td width="402" align="right"><b><font face="Arial, Helvetica, sans-serif" size="6" color="#0000FF">
    NetBurner I2C Demo With Sparkfun TMP102</font></b></td>
<img src="/images/TMP102.jpg" width="120" border="0">
<p><font face="Arial, Helvetica, sans-serif" size="10">Temperature: <span id="TEMP"></span></font></p>

Web Page Display

The resultant web page is shown below:

Read 3783 times Last modified on Monday, November 17, 2014 3:17 pm

NetBurner Learn

The NetBurner Learn website is a place to learn faster ways to design, code, and build your NetBurner based product.

Latest Articles