I2C to EMC1001 Temp Sensor using MCC


The Microchip Xpress board has an EMC1001 temperature sensor module on-board. This application will show how to access that device and communicate with it to display the temperature in a terminal window on a PC.

The project uses:

To follow along with these steps, MPLAB® Xpress should be open and the user should be logged in so that the MPLAB Code Configurator plug-in can be used. If you need help with the set-up, it is explained in a previous module. You should see a screen similar to the one below to move on to step 1:


If you have not completed the set-up yet, this will walk you through the process. Begin by opening a new project under File > New Project.


Choose Microchip Embedded and Standalone Project then choose Next


The Xpress Development Board uses the PIC16F18855 device. Next

Lastly, name your project. For this project, use the name TemperatureSensor.


Hardware Tools (Optional)

Tool About Purchase
MPLAB® Xpress
Development Board

Software Tools

Tool About Installers
Windows Linux Mac OSX
MPLAB® Xpress
Cloud Integrated Development Environment

Additional Files




Open the MPLAB® Code Configurator under the Tools>Embedded menu of MPLAB Xpress.


If you do not see this option, make sure you are logged in to your mymicrochip account.

Follow the steps to open MPLAB Code Configurator (MCC) in MPLAB Xpress.



The Master Synchronous Serial Port (MSSP) enables us to use Serial Peripheral Interface (SPI) and Inter-Integrated Circuit (I2C) serial communication. Serial communication is used for communication to other microcontrollers, as well as between microcontrollers and external peripherals. The temperature sensor is incorporated into the Xpress board and requires I2C serial communication to interface to it from the PIC16F18855 microcontroller on the board. Therefore, the MSSP block must be set-up accordingly. Select MSSP2 from Device Resources.

Although this is automatic, note the Mode is set to I2C Master due to the fact that it is in control over the peripheral.

Change Slew Rate Control to Standard Speed and the Baud Rate Generator Value to 0x4. It should look like the window below:



The second block we need is the EUSART block. This will handle the communication between the microcontroller and Tera Term to display the ambient temperature on your computer screen.

Choose EUSART under Device Resources. Select the Enable Transmit and Redirect STDIO to USART. Your block should look like the one below:


Redirect of STDIO to USART enables use of the STDIO.h library in your software, allowing easier programming of USART commands.


Next, connect the necessary pins. According to the schematic, pin RC4 is the SCL line connected to SCL on the EMC1001 and RC3 is the SDA line connected to SDA on the EMC1001. Therefore, lock RC4 to MSSP2 SCL1 input and output, as well as locking RC3 to MSSP2 SDA1 input and output.

We also need to connect the transmitting line, TX, of the EUSART to pin RC0. This is seen below:



Under Interrupt Mode make sure to enable MSSP2 BCLI and MSSP2 SSPI :



Lastly, make sure the Pin Module under Project Resources -> System is configured correctly:



This project makes heavy use of the i2c1.h library and this step will teach you the functions necessary to complete this project. In this section, we will cover the additional lines of code necessary to write in manually.

First, select main.c under the TemperatureSensor Project:


Now we will break down the code for this tutorial.

The code begins:

#include "mcc_generated_files/mcc.h"
#define EMC1001_ADDRESS     0x38   // slave device address

This section selects the hex value for the slave, in this case the EMC1001, address as well as including the general header file.

uint8_t EMC1001_Read(uint8_t reg, uint8_t *pData)
    I2C2_MasterWriteTRBBuild(&trb[0], &reg, 1, EMC1001_ADDRESS);
    I2C2_MasterReadTRBBuild(&trb[1], pData, 1, EMC1001_ADDRESS);                
    I2C2_MasterTRBInsert(2, &trb[0], &status);
    while(status == I2C2_MESSAGE_PENDING);      // blocking
    return (status == I2C2_MESSAGE_COMPLETE); 

Because there is no function currently included to read specifically from the sensor, one must be written into the code. This code contains a couple of important functions to enable the I2C communication process.

The Transaction Request Block (TRB) refers to the data type that needs to be built to handle any I2C communication and is used to inform the driver how to handle the process.

The WriteTRBBuild and ReadTRBBuild are called to correctly form the TRB block, changing the register if it is a read or write command. However, these only format the TRB. In order to send the transaction, TRBInsert must be called.

The while loop waits until the process is completed, or the status stops pending, and then updates the status to deliver a message_complete.

// EMC1001 registers
#define TEMP_HI     0       // temperature value high byte 
#define TEMP_LO     2       // low byte containing 1/4 deg fraction

This section defines the addresses called from the EMC1001 to report the high and low-value bytes for the current temperature.

void main(void)
    uint8_t data;
    int8_t  temp;
    uint8_t templo;

This section defines variables and initializes the code.

while (1)
        printf("\x0C");   // comment out if terminal does not support Form Feed
        puts("Temperature Sensor Demo\n");
        if (EMC1001_Read(0xfd, &data)) printf("Product ID: EMC1001%s\n", data ? "-1" : "");
        if (EMC1001_Read(0xfe, &data)) printf("Manufacturer ID: 0x%X\n", data);
        if (EMC1001_Read(0xff, &data)) printf("Revision : %d\n", data);

The continuous part of the code begins by sending information to the USART, which can be read via Tera Term. After a general header, the previously written EMC1001_Read() function is called to read the Product ID, Manufacturer ID, and Revision number from the sensor.

   if (EMC1001_Read(TEMP_HI, (uint8_t*)&temp)) {
            EMC1001_Read(TEMP_LO, &templo);     // get lsb 
            templo = templo >> 6;                   
            if (temp < 0) templo = 3-templo;    // complement to 1 if T negative
            printf("\nThe temperature is: %d.%d C\n", temp, templo*25);

If you notice the printf function, temp is the integer value of the Celsius while templo is a remainder value. If you want to show the values in Fahrenheit, you can use the temp variable and a simple conversion equation online. Then, add your new value into the printf statement as well.

The code now begins to read the actual temperature data to two decimal places, and then prints that to the USART.

if (EMC1001_Read(4, &data)) printf("\nThe Conversion rate is: %x\n", data);
        if (EMC1001_Read(5, &data)) printf("The high limit is: %d C\n", data);
        if (EMC1001_Read(7, &data)) printf("The low limit is: %d C\n", data);         

Lastly, the program reads the conversion rate, i.e., the number of times per second the sensor delivers data, as well as the High and Low temperature limits set.

Now its time to program!


Generate a .hex file by clicking Make and Program Device:


Program the MPLAB Xpress board by dragging the generated project .hex file from the downloads section of the browser and dropping the file on to the XPRESS drive.


The Programmer LED on the Xpress board should quickly flash from green to red and then back to green indicating that the .hex file was successfully programmed to the PIC16F18855.



In order to test successful completion, open the Tera Term window. Change the Baud Rate from 9600 to 19200 and you will see something similar to this:



After completing this tutorial, you should have a basic understanding of the EUSART module as well as the EMC1001 temperature sensor on the Xpress board. This can be used to monitor CPU heat during processing high loads, or other applications as they arise. If the characters appearing on the screen seem to be gibberish or different than what you were expecting, make sure the baud rate of the microcontroller and computer terminal agree.

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.