Swordfish Module: Microchip MCP9800 I2C High-Accuracy Temperature Sensor

Swordfish Module: Microchip MCP9800 I2C High-Accuracy Temperature Sensor | Swordfish Modules

TAP-28_and_I2C_Demo_Board_-_teaserThe Microchip MCP9800 High-Accuracy Temperature Sensor features ±1°C accuracy from -10°C to +85°C, and 9 - 12 bit conversions using an I2C interface.  The MCP9800 also features high and low trip points so that it can be used as a thermostatic controller.  The MCP9800 is about US$1.20 in small quantity.  Up to 8 MCP9800s may be used on a single I2C interface if parts with different addresses are used.  See below.

The Swordfish module allows easy use of the MCP9800 with simple commands and full access to all of its registers.  The module uses hardware I2C.  A sample program is shown below.

The module was developed using a TAP-28 board and Microchip's PICkit Serial I2C Demo Board (shown on the right).


Module Commands

  • Function GetTemperature returns the temperature to the nearest degree in integer format.
  • Function GetTemperature100 returns the temperature x 100 in integer format.  This allows using  2 decimal places.
  • Function GetTset returns the set point temperature to the nearest degree in integer format.
  • Sub SetTset (Temperature As Integer) sets the Tset temperature.  May be positive or negative.
  • Function GetTset100 returns the set point temperature x 100 in integer format.  This allows using 2 decimal places.
  • Sub SetTset100 (Temperature As Integer) sets the Tset temperature x 100.  Rounded to nearest 0.5 degree.  May be positive or negative.
  • Function GetThyst returns the hysteresis temperature to the nearest degree in integer format.
  • Sub SetThyst (Temperature As Integer) sets the Thyst temperature.  May be positive or negative.
  • Function GetThyst100 returns the hysteresis temperature x 100 in integer format.  This allows using 2 decimal places.
  • Sub SetThyst100 (Temperature As Integer) sets the Thyst temperature x 100.  Rounded to nearest 0.5 degree.  May be positive or negative.
  • Function GetMode(mode) returns the value of the configuration property as a byte.  Modes are:
  • Sub SetMode(mode As Byte, value As Byte)
Mode
Value
Config_ONESHOT 
0* = continuous, 1 = oneshot (single reading)
Config_ADC_RES ADC resolution (9*, 10, 11 or 12 bit)
Config_FAULT_QUEUE Number of times a reading must be out of range to assert output (1*,2 ,4 or 6)
Config_ALERT_POL 0* = Active Low, 1 = Active High
Config_COMP_INT
0* = Comparator mode, 1 = Interrupt mode
Config_SHUTDOWN 0* = Enable, 1 = Disable

* Default Value.  See data sheet for more information.

 

Reading and Writing Registers

The MCP9800 provides a total of 4 registers.  The register names are based on the data sheet names.  Three of the registers may be read or written; the Ta register may only be read.

Register
Function
R/W?
Bytes
REG_TA Ambient temperature
read
2
REG_CONFIG Configuration parameters
r/w
2*
REG_THYST Hysteresis temperature
r/w
2
REG_TSET Set temperature
r/w
2

*Only the first byte is used.  Second byte is a dummy and not read or written to MCP9800.

See data sheet for details about the registers and data format.

Sub Read_REG(Register, Byte1, Byte2)
Sub Write_REG(Register, Byte1, Byte2)

 

MCP9800 Address

The MCP9800 is available with 8 different addresses.  Each MCP9800 used on an I2C interface must have a different address.  The MCP9801 has a larger package with pins for selecting the address.  The default address in the Swordfish module is $90.  A different address may be set:

MCP9800.I2CDevice = $Address

Part
A7
A6
A5
A4
A3
A2
A1
R/W
Hex
MCP9800/02A0 1
0
0
1
0
0
0
0
$90
MCP9800/02A1 1
0
0
1
0
0
1
0
$91
MCP9800/02A2 1
0
0
1
0
1
0
0
$92
MCP9800/02A3 1
0
0
1
0
1
1
0
$93
MCP9800/02A4 1
0
0
1
1
0
0
0
$94
MCP9800/02A5 1
0
0
1
1
0
1
0
$95
MCP9800/02A6 1
0
0
1
1
1
0
0
$96
MCP9800/02A7 1
0
0
1
1
1
1
0
$97
MCP9801/03 1
0
0
1
x
x
x
0

x = User selectable.

 

Sample Program

The sample program below shows how simply the MCP9800 may be used with the Swordfish Module.  This program sets the temperature resolution and Tset temperature and reads out the temperature.  I've made use of the software UART and the PICkit UART tool to allow rapid switching between programming and monitoring output.

MCP9800 Demo Program
{
*****************************************************************************
*  Name    : MCP9800 I2C Temperature Sensor Demo                            *
*  Author  : Jon Chandler                                                   *
*  Notice  : Copyright (c) 2010 Creative Commons 3.0 sa-by                  *
*          : All Rights Reserved                                            *
*  Date    : 11/16/2010                                                     *
*  Version : 1.0                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
}
Device = 18f2520        'set for the device used
 
Clock = 12              'set for the clock speed used
 
Include("suart.bas")
Include("convert.bas")
Include("mcp9800.bas")
 
Dim Temperature As Integer
Dim Value1 As Byte
Dim Value2 As Byte
 
 
MCP9800.I2CDevice = $92     'change the default address to match the board
 
UART.SetTX (PORTB.7)        'set the software UART pin to use the ICSP connector            
UART.SetMode (umTrue)       'set the software UART pin to non-inverted mode            
UART.SetBaudrate(sbr9600)
 
 
MCP9800.SetMode(Config_ADC_RES, 12)     'set 12 bit resolution 
 
MCP9800.SetTset(23)                      'set Tset to 23 degrees C
 
While 1 = 1
 
Temperature = MCP9800.GetTemperature    'get integer temperature value 
UART.Write ("The Temperature is ", DecToStr(Temperature)," degrees C", 13,10)
Temperature = (Temperature *9)/5 +32
UART.Write ("The Temperature is ", DecToStr(Temperature)," degrees F", 13,10)
 
 
 
Temperature = MCP9800.GetTSet
UART.Write ("TSet: ", DecToStr(Temperature), 13,10)
UART.Write (13,10)
 
DelayMS(1000)
 
Wend

 

MCP9800 Swordfish Module

The module is listed below.  It should be saved as MCP9800.bas.

MCP9800 Swordfish Module
{
*****************************************************************************
*  Name    : MCP9800 Module                                                 *
*  Author  : Jon Chandler                                                   *
*  Notice  : Licensed Under Creative Commons 3.0 SA-BY                      *
*          : All Rights Reserved                                            *
*  Date    : 11/15/2010                                                     *
*  Version : 1.0                                                            *
*  Notes   : Microchip MCP9800 - 2-Wire High-Accuracy Temperature Sensor    *
*          :                                                                *
*****************************************************************************
}
Module MCP9800
 
Include ("i2c.bas")
 
'Register Names
Public Const REG_TA = 0
Public Const REG_CONFIG = 1
Public Const REG_THYST = 2
Public Const REG_TSET = 3
 
'Configuration Bits
Public Const Config_ONESHOT = 6
Public Const Config_ADC_RES = 5
Public Const Config_FAULT_QUEUE = 4
Public Const Config_ALERT_POL = 3
Public Const Config_COMP_INT = 2
Public Const Config_SHUTDOWN =1
 
 
Public Dim I2CDevice As Byte     'I2C address
 
Dim I2CPointer As Byte           'register address
Dim value1 As Byte
Dim value2 As Byte
Dim value3 As Byte
Dim value4 As Byte
Dim Temperature As Integer   
Dim value5 As Word
 
Public Sub Read_REG(Pointer As Byte, ByRef Val1 As Byte,ByRef Val2 As Byte)
    Select Pointer 
    Case = 0,2,3      'registers with 2 bytes
        I2C.Start
        I2C.WriteByte(I2CDevice)
        I2C.WriteByte(Pointer)
        I2C.Stop
 
        I2C.Restart
        I2C.WriteByte(I2CDevice+1)
        Val1 = I2C.ReadByte
        I2C.Acknowledge(I2C_ACKNOWLEDGE)
        Val2 = I2C.ReadByte
        I2C.Acknowledge(I2C_NOT_ACKNOWLEDGE)
        I2C.Stop
 
   Case = 1            'register with 1 byte
        I2C.Start
        I2C.WriteByte(I2CDevice)
        I2C.WriteByte(Pointer)
        I2C.Stop
 
        I2C.Restart
        I2C.WriteByte(I2CDevice+1)
        Val1 = I2C.ReadByte
 
        I2C.Acknowledge(I2C_NOT_ACKNOWLEDGE)
        I2C.Stop
        val2 = 0
    End Select
 
End Sub
 
Public Sub Write_REG(Pointer As Byte, ByRef Val1 As Byte,ByRef Val2 As Byte)
    Select Pointer 
    Case = 0,2,3      'registers with 2 bytes
        I2C.Start
        I2C.WriteByte(I2CDevice)
        I2C.WriteByte(Pointer)
        I2C.WriteByte(val1)
        I2C.WriteByte(val2)
        I2C.Stop
 
 
    Case = 1            'register with 1 byte
        I2C.Start
        I2C.WriteByte(I2CDevice)
        I2C.WriteByte(Pointer)
        I2C.WriteByte(val1)
        I2C.Stop
 
 
    End Select
 
 
 
End Sub
 
 
Public Function GetTemperature() As Integer
    Read_REG(REG_TA, value1, value2)
    If value1.7 = 1 Then 'negative temperature
        value1=Not(value1)+1
        result = -(value1 *10 +value2*10/256  +5)/10 ' round up if 0.5 degree or greater
    Else
        result = (value1 *10 +value2*10/256  +5)/10 ' round up if 0.5 degree or greater
    End If    
End Function
 
Public Function GetTemperature100() As Integer
    Read_REG(REG_TA, value1, value2)
    If value1.7 = 1 Then 'negative temperature
        value1=Not(value1)+1
        result = (-value1 *100 +value2*100/256)
    Else
        result = value1 *100 +value2*100/256
    EndIf        
End Function
 
Public Function GetTHyst() As Integer
    Read_REG(REG_THYST, value1, value2)
    If value1.7 = 1 Then 'negative temperature
        value1=Not(value1)+1
        result = -(value1 *10 +value2*10/256  +5)/10 ' round up if 0.5 degree or greater
    Else
        result = (value1 *10 +value2*10/256  +5)/10 ' round up if 0.5 degree or greater
    End If        
End Function
 
Public Function GetTHyst100() As Integer
    Read_REG(REG_THYST, value1, value2)
    If value1.7 = 1 Then 'negative temperature
        value1=Not(value1)+1
        result = -(value1 *100 +value2*100/256)
    Else
        result = (value1 *100 +value2*100/256)
    End If    
End Function
 
 
Public Function GetTSet() As Integer
    Read_REG(REG_TSET, value1, value2)
    If value1.7 = 1 Then 'negative temperature
        value1=Not(value1)+1
        result = -(value1 *10 +value2*10/256  +5)/10 ' round up if 0.5 degree or greater
    Else        
        result = (value1 *10 +value2*10/256  +5)/10 ' round up if 0.5 degree or greater
    End If 
End Function
 
Public Function GetTset100() As Integer
    Read_REG(REG_TSET, value1, value2)
    If value1.7 = 1 Then 'negative temperature
        value1=Not(value1)+1
        result = -(value1 *100 +value2*100/256)
    Else
        result = value1 *100 +value2*100/256
    EndIf    
End Function
 
Public Function GetMode(mode As Byte) As Byte   'Register is only 1 byte.  This is covered in the Read_REG command. Still must pass 2 bytes
    Read_REG(REG_CONFIG, value1, value2)
     Select mode
        Case = 1
            result=value1.0
        Case = 2
            result=value1.1
        Case = 3
            result=value1.2
        Case = 4
            value1 = value1 And %00011000
            Select value1
                Case = 0
                    result = 1
                Case = 8
                    result = 2
                Case = 16
                    result = 4
                Case = 24
                    result = 6
            End Select
        Case = 5
            value1 = value1 And %01100000
            Select value1
                Case = 0
                    result = 9
                Case = 32
                    result = 10
                Case = 64
                    result = 11
                Case = 96
                    result = 12
            End Select 
        Case = 6
            result=value1.7
    End Select
End Function
 
Public Sub SetThyst (Temperature As Integer)
    Select Temperature
       Case <  -55
            'out of range low
            value1 = 75 'default value
        Case < 0
           'negative number
           value1 = -1*Temperature  'convert to positive
           value1 = Not (value1) +1
        Case <126
            'positive number
            value1 = Temperature
        Case >125
            'out of range high
            value1 = 75 'default value
    End Select                       
 
    value2 = 0
    Write_REG(REG_THYST, value1,value2)
End Sub
 
Public Sub SetThyst100 (Temperature As Integer)
    Select Temperature
        Case < 0 'negative temperature
            value1 = -Temperature/100
            Select value1
                Case > 55
                    'out of range low
                    value1 = 75 'default value
                Else 
                    'negative number
                    value1 = Not (value1) +1
               End Select
        Case > 12500
            'out of range high
            value1 = 75 'default value
       Else
           'positive number
            value1 = Temperature/100
            value1 = value1
    End Select 
    If Temperature < 0 Then
        Temperature = - Temperature
    End If                      
    value5 = Temperature/100    'isolate fractional part
    value5 = value5*100
    value5 = Temperature-value5 'isolate fractional part
    If value5 >= 50 Then         'if fractional part equal or greater than 0.5, set value2 bit 7 
        value2.7 = 1
    EndIf
 
    Write_REG(REG_THYST, value1,value2)
End Sub
 
Public Sub SetTset (Temperature As Integer)
    Select Temperature
        Case <  -55
            'out of range low
            value1 = 75 'default value
        Case < 0
           'negative number
           value1 = -1*Temperature  'convert to positive
           value1 = Not (value1) +1
        Case <126
            'positive number
            value1 = Temperature
        Case >125
            'out of range high
            value1 = 80 'default value
    End Select                       
 
    value2 = 0
 
    Write_REG(REG_TSET, value1,value2)
End Sub
 
Public Sub SetTset100 (Temperature As Integer)
    Select Temperature
        Case < 0 'negative temperature
            value1 = -Temperature/100
            Select value1
                Case > 55
                    'out of range low
                    value1 = 75 'default value
                Else 
                    'negative number
                    value1 = Not (value1) +1
               End Select
        Case > 12500
            'out of range high
            value1 = 75 'default value
       Else
           'positive number
            value1 = Temperature/100
            value1 = value1
    End Select 
 
    If Temperature < 0 Then
        Temperature = - Temperature
    End If                      
    value5 = Temperature/100    'isolate fractional part
    value5 = value5*100
    value5 = Temperature-value5 'isolate fractional part
    If value5 >= 50 Then         'if fractional part equal or greater than 0.5, set value2 bit 7 
        value2.7 = 1
    EndIf
 
    Write_REG(REG_TSET, value1,value2)
End Sub
 
Public Sub SetMode(mode As Byte, value1 As Byte)
    Read_REG(REG_CONFIG, value3, value4)    'Register is only 1 byte.  This is covered in the Read_REG command. Still must pass 2 bytes
     Select mode
        Case = 1
            value3.0 = value1.0
        Case = 2
            value3.1 = value1.1
        Case = 3
            value3.2 = value1.2
        Case = 4
            Select value1
                Case = 1
                    value3.3 = 0
                    value3.4 = 0
                Case = 2
                    value3.3 = 1
                    value3.4 = 0
                Case = 4
                    value3.3 = 0
                    value3.4 = 1
               Case = 6
                    value3.3 = 1
                    value3.4 = 1
               Else           'if error in value, set default
                    value3.3 = 0
                    value3.4 = 0
            End Select 
        Case = 5
            Select value1
                Case = 9
                    value3.5 = 0
                    value3.6 = 0
                Case = 10
                    value3.5 = 1
                    value3.6 = 0
                Case = 11
                    value3.5 = 0
                    value3.6 = 1
               Case = 12
                    value3.5 = 1
                    value3.6 = 1
               Else           'if error in value, set default
                    value3.5 = 0
                    value3.6 = 0
           End Select 
        Case = 6
             value3.7 = value1.7
    End Select
 
    Write_REG(REG_CONFIG, value3, value4)
End Sub
 
I2CDevice = $90     'default address 
I2CPointer = $00
 
 
 
I2C.Initialize
I2C.Start
I2C.Stop             

Posted: 8 years 8 months ago by Anonymous #5488
Anonymous's Avatar
Nice Jon, you've encapsulated the I2C interface with your module and made a handy set of routines!

The PICkit Serial I2C Demo Board looks like a great find
Posted: 8 years 8 months ago by Anonymous #5489
Anonymous's Avatar
The things I do to test out my code!

I hadn't actually tested the response to negative temperatures, but the math worked out. An early winter storm here has allowed me to test it...once the power came back on! The power was off for nearly 24 hours and this morning the temperature was down to 10 degrees C (51 degrees F) and tonight's temperature may get down to -10 C (13 F), which is really unusual for this area at any time of the year.

Since the power is back on, and the temperature is below freezing, I took the opportunity to stick the sensor out the window and verify the response around zero degrees C.
The Temperature is 3 degrees C
The Temperature is 37 degrees F
.
.
.
The Temperature is 2 degrees C
The Temperature is 35 degrees F
.
.
.
The Temperature is 1 degrees C
The Temperature is 33 degrees F
.
.
.
The Temperature is 0 degrees C
The Temperature is 32 degrees F
.
.
.
The Temperature is -2 degrees C
The Temperature is 29 degrees F
.
.
.
The Temperature is -1 degrees C
The Temperature is 31 degrees F
.
.
.
The Temperature is -3 degrees C
The Temperature is 27 degrees F
Seems to work fine, although there may be a little quirk between -1 and -2 degrees. The readings jumped from 0 to -2, then to -1 and on to -3. I don't want to be that cold anyway
Posted: 8 years 8 months ago by Anonymous #5490
Anonymous's Avatar
That was a pretty good storm you had in Washington. We got the same storm about 1-2 days later. We dropped down to -10 here in Salmon, Idaho.
I take it your using the TAP-28 and wearing it out? LOL
Asked Santa to get me some as well as a Pickit2 for Christmas.Keep seeing how much it gets used here so I figured I better get with the program on the same ball-field.

Forum Activity

Member Access