The 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).
| 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.
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)
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.
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.
{ ***************************************************************************** * 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
The module is listed below. It should be saved as MCP9800.bas.
{ ***************************************************************************** * 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