News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

LM75AD. I2C Temperature Sensor Interface

Started by top204, Today at 03:21 PM

Previous topic - Next topic

top204

I saw some posts concerning an LM75AD, temperature sensing device on the forum recently, and I looked into my code listings to see if I had created code for one at some point in the past, and it turned out that I had not. So I set about creating a simple library for reading and setting up an LM75AD temperature sensor, using a bit-bashed (software) I2C interface, so it will work on PIC devices that do not have a compatible I2C peripheral.

The LM75AD library code is listed below, and should be named as "LM75AD.inc":
$ifndef _LM75AD_INC_
$define _LM75AD_INC_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interface to an LM75AD, I2C temperature sensor device.
'
' Written by Les Johnson for the Positron8 BASIC compiler
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook
'
' Setup the default I2C pins for the I2CIn and I2COut commands interfacing the LM75A device
'
$ifndef LM75A_SCL_Pin                                           ' Has the $define LM75A_SCL_Pin been used in the main code listing?
    $define LM75A_SCL_Pin PORTC.3                               ' No. So set the default pin that connects to the LM75A I2C SCL line
    $SendWarning "$define LM75A_SCL_Pin is not in the main code listing. So defaulting to pin PORTC.3"
$endif

$ifndef LM75A_SDA_Pin                                           ' Has the $define LM75A_SDA_Pin been used in the main code listing?
    $define LM75A_SDA_Pin PORTC.4                               ' No. So set the default pin that connects to the LM75A I2C SDA line
    $SendWarning "$define LM75A_SDA_Pin is not in the main code listing. So defaulting to pin PORTC.4"
$endif

$define cLM75A_DEFAULT_ADDRESS    %10010000                     ' Default I2C address ($48 << 1)
$define cLM75A_DEGREES_RESOLUTION 0.125                         ' The resolution of the temperature, when converted to degrees
'
' LM75 Registers
'
$define cLM75A_TEMP_REG         0                               ' Temperature register (read-only)
$define cLM75A_CONFIG_REG       1                               ' Configuration register
$define cLM75A_HYST_REG         2                               ' Hysterisis register
$define cLM75A_OS_REG           3                               ' OS register
$define cLM75A_PRODIC_REG       7                               ' Product ID register (Only valid for Texas Instruments devices)

$define cLM75A_CONF_OS_COMP_INT 1                               ' OS operation mode selection
$define cLM75A_CONF_OS_POL      2                               ' OS polarity selection
$define cLM75A_CONF_OS_F_QUE    3                               ' OS fault queue programming
'
' LM75 OS Polarity values
'
$define cLM75A_OS_POL_ACTIVELOW   %00000000
$define cLM75A_OS_POL_ACTIVEHIGH  %00000100
'
' LM75 Device Mode values
'
$define cLM75A_DEV_MODE_COMPARATOR %00000000
$define cLM75A_DEV_MODE_INTERRUPT  %00000010
'
' LM75 Fault Queue values
'
$define cLM75A_NUM_OF_FAULTS_1     %00000000
$define cLM75A_NUM_OF_FAULTS_2     %00001000
$define cLM75A_NUM_OF_FAULTS_4     %00010000
$define cLM75A_NUM_OF_FAULTS_6     %00011000
'
' Create global variables for the library here
'
    Dim LM75A_bI2CAddress  As Byte                              ' Holds the required I2C address for the LM75A device
    Dim LM75A_wRawValue    As SWord                             ' Holds the raw 16-bit value read from the LM75A device
    Dim LM75A_fTemperature As Float                             ' Holds the temperature sent or received to/from the LM75A device

'---------------------------------------------------------------------------------------------
' Read the temperature in degrees Centigrade
' Input     : None
' Output    : Returns the temperature value in degrees Centigrade
' Notes     : None
'
Proc LM75A_GetTempInDeg(), Float
    Dim wRawValue As Result.SWord                               ' Holds the raw temperature data

    wRawValue = LM75A_GetRawTemp()                              ' Read the raw temperature value
    wRawValue = wRawValue >> 5                                  ' Sign shift the data for 11-bit reading
    Result = wRawValue * cLM75A_DEGREES_RESOLUTION              ' Convert the result into degrees Centigrade
EndProc

'---------------------------------------------------------------------------------------------
' Set the LM75A device's trip temperature
' Input     : pTemp holds the temperature of the trip (in non-fractional degrees Centigrade)
' Output    : None
' Notes     : None
'
Proc LM75A_SetOS_TripTemp(pTemp As LM75A_fTemperature)
    LM75A_Write16(cLM75A_OS_REG, pTemp * 256.0)
EndProc

'---------------------------------------------------------------------------------------------
' Set the LM75A device's polarity of the trip
' Input     : pPol holds the polarity mode:
'             cLM75A_OS_POL_ACTIVELOW   %00000000
'             cLM75A_OS_POL_ACTIVEHIGH  %00000100
' Output    : None
' Notes     : None
'
Proc LM75A_SetOS_Polarity(pPol As Byte)
    Dim bConfig As Byte

    bConfig = LM75A_Read8(cLM75A_CONFIG_REG)
    LM75A_Write8(cLM75A_CONFIG_REG, (bConfig & %11111011) | pPol)
EndProc

'---------------------------------------------------------------------------------------------
' Read the 16-bit raw temperature value from the LM75A device
' Input     : None
' Output    : Returns the 16-bit value read from the LM75A device
' Notes     : None
'
Proc LM75A_GetRawTemp(), LM75A_wRawValue
    I2CIn LM75A_SDA_Pin, LM75A_SCL_Pin, LM75A_bI2CAddress, cLM75A_TEMP_REG, [Result.Byte1, Result.Byte0]
EndProc

'---------------------------------------------------------------------------------------------
' Read a 16-bit value from the LM75A device
' Input     : pReg holds the register to read
' Output    : Returns the 16-bit value read from the LM75A device
' Notes     : None
'
Proc LM75A_Read16(pReg As Byte), LM75A_wRawValue
    I2CIn LM75A_SDA_Pin, LM75A_SCL_Pin, LM75A_bI2CAddress, pReg, [Result.Byte1, Result.Byte0]
EndProc

'---------------------------------------------------------------------------------------------
' Read an 8-bit value from the LM75A device
' Input     : pReg holds the register to read
' Output    : Returns the 8-bit value read from the LM75A device
' Notes     : None
'
Proc LM75A_Read8(pReg As Byte), Byte
    I2CIn LM75A_SDA_Pin, LM75A_SCL_Pin, LM75A_bI2CAddress, pReg, [Result]
EndProc

'---------------------------------------------------------------------------------------------
' Write a 16-bit value to the LM75A device
' Input     : pReg holds the register to write too
'           : pValue holds the 16-bit value to write to pReg
' Output    : None
' Notes     : None
'
Proc LM75A_Write16(pReg As Byte, pValue As Word)
    I2COut LM75A_SDA_Pin, LM75A_SCL_Pin, LM75A_bI2CAddress, pReg, [pValue.Byte1, pValue.Byte0]
EndProc

'---------------------------------------------------------------------------------------------
' Write an 8-bit value to the LM75A device
' Input     : pReg holds the register to write too
'           : pValue holds the 8-bit value to write to pReg
' Output    : None
' Notes     : None
'
Proc LM75A_Write8(pReg As Byte, pValue As Byte)
    I2COut LM75A_SDA_Pin, LM75A_SCL_Pin, LM75A_bI2CAddress, pReg, [pValue]
EndProc

'---------------------------------------------------------------------------------------------
' Convert a temperature value from Fahrenheit to Centigrade
' Input     : pTemp holds the temperature value in degrees Fahrenheit
' Output    : Returns the temperature value in degrees Centigrade
' Notes     : None
'
Proc LM75A_FahrenheitToDeg(pTemp As LM75A_fTemperature), pTemp
    Result = (pTemp - 32.0) / 1.8
EndProc

'---------------------------------------------------------------------------------------------
' Convert a temperature value from Centigrade to Fahrenheit
' Input     : pTemp holds the temperature value in degrees Centigrade
' Output    : Returns the temperature value in degrees Fahrenheit
' Notes     : None
'
Proc LM75A_DegToFahr(pTemp As LM75A_fTemperature), pTemp
    Result = (pTemp * 1.8) + 32.0
EndProc

'---------------------------------------------------------------------------------------------
' Setup the LM75A device
' Input     : pAddress holds the address of the LM75A being used
' Output    : None
' Notes     : None
'
Proc LM75A_Setup(pAddress As LM75A_bI2CAddress)
    LM75A_bI2CAddress = pAddress
EndProc

$endif      ' _LM75AD_INC_

A demonstration of the library operating is listed below:
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interface to an LM75AD, I2C temperature sensor device.
'
' Reads the temperature from the LM75A device.
' Displays the temperature in Centigrade and Fahrenheit on an alphanumeric LCD.
' Transmits the temperaure in Centigrade and Fahrenheit to a serial terminal.
'
' Written by Les Johnson for the Positron8 BASIC compiler
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook
'
    Device = 18F26K22                                           ' Tell the compiler what device to compile for
    Declare Xtal = 64                                           ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Heap_Arrays = On                               ' Make all arrays 'Heap' types, so they always get placed after standard variables
    Declare Auto_Heap_Strings = On                              ' Make all Strings 'Heap' types, so they always get placed after standard variables
    Declare Auto_Variable_Bank_Cross = On                       ' Make sure all multi-byte variables remain within a single RAM bank
    Declare Float_Display_Type = Fast                           ' Tell the compiler to use the faster and more accurate float to ASCII converter code
'
' Setup USART1 for debugging
'
    Declare Hserial1_Baud = 9600                                ' Set the Baud rate
    Declare HRSOut1_Pin   = PORTC.6                             ' Choose the pin for TX
'
' Setup the Alphanumeric LCD
'
    Declare LCD_DTPin     = PORTB.0                             ' Pins PORTB.0 to PORTB.3 connect to LCD pins D4 to D7
    Declare LCD_RSPin     = PORTB.4                             ' Connects to the LCD's RS pin
    Declare LCD_ENPin     = PORTB.5                             ' Connects to the LCD's EN pin
    Declare LCD_Type      = Alphanumeric                        ' Yell the compiler that the LCD is an Hitachi alphanumeric type
    Declare LCD_Interface = 4                                   ' Tell the compiler to use a 4-bit interface for the LCD
    Declare LCD_Lines     = 2                                   ' Tell the compiler that the LCD has 2 lines
    Declare LCD_CommandUs = 2000                                ' Tell the compiler to give a 2000us delay between commands sent to the LCD
    Declare LCD_DataUs    = 50                                  ' Tell the compiler to give a 50us delay between data sent to the LCD
'
' Setup I2C pins for the I2CIn and I2COut commands interfacing the LM75A device
'
$define LM75A_SCL_Pin PORTC.3                                   ' Connects to the LM75A I2C SCL line
$define LM75A_SDA_Pin PORTC.4                                   ' Connects to the LM75A I2C SDA line

    Include "LM75AD.inc"                                        ' Load the LM75AD library into the program
'
' Create global variables for the demo here
'
    Dim fTemperatureCent  As Float                              ' Holds the temperature in Centigrade
    Dim fTemperatureFahr  As Float                              ' Holds the temperature in Fahrenheit
    Dim fPrevTemperature  As Float = 1000                       ' Holds the previous temperature

'---------------------------------------------------------------------------------------------
' The main program starts here
' Read the temperature from the LM75A device.
' Display the temperature in Centigrade and Fahrenheit on an alphanumeric LCD.
' Transmit the temperaure in Centigrade and Fahrenheit to a serial terminal.
'
Main:
    Setup()                                                     ' Setup the program and any peripherals

    LM75A_SetOS_TripTemp(cLM75A_OS_POL_ACTIVEHIGH)              ' Setup the LM75A trip as high when active
    LM75A_SetOS_TripTemp(2.0)                                   ' Set the trip temperature to 2.0 degrees Centigrade

    Do                                                          ' Create a loop
        fTemperatureCent = LM75A_GetTempInDeg()                 ' Read the temperature in degrees Centigrade
        fTemperatureFahr = LM75A_DegToFahr(fTemperatureCent)    ' Convert it to Fahrenheit as well

        Print At 1, 1, Dec2 fTemperatureCent, " Deg C  ",_      ' \ Display the temperatures on the LCD
              At 2, 1, Dec2 fTemperatureFahr, " Deg F  "        ' /

        If fTemperatureCent <> fPrevTemperature Then            ' Is the current temperature the same as the previous temperature?
            HRSOut1Ln Dec2 fTemperatureCent, " Deg C \r",_      ' \ No. So transmit the temperatures to a serial terminat
                      Dec2 fTemperatureFahr, " Deg F  "         ' /
            fPrevTemperature = fTemperatureCent                 ' Keep a copy of the current temperature
        EndIf
    Loop                                                        ' Do it forever

'---------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Osc_64MHz()                                                 ' Set the device to 64MHz operation using its internal oscillator
    Cls                                                         ' Clear the LCD's screen
    LM75A_Setup(cLM75A_DEFAULT_ADDRESS)                         ' Setup the LM75A's I2C address
EndProc

'---------------------------------------------------------------------------------------------
' Set the PIC18F26K22 device to 64MHz operation using its internal oscillator
' Input     : None
' Output    : None
' Notes     : None
'
Proc Osc_64MHz()
    OSCCON  = $70
    OSCCON2 = $04
    OSCTUNE = $40
    DelayMS 100
EndProc

'---------------------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator on a PIC18F26K22 device.
' OSC pins RA6 and RA7 are general purpose I/O.
'
Config_Start
    FOSC     = INTIO67                                          ' Internal oscillator
    PRICLKEN = Off                                              ' Primary clock disabled
    MCLRE    = EXTMCLR                                          ' MCLR pin enabled
    WDTEN    = Off                                              ' Watchdog Timer disabled
    PLLCFG   = Off                                              ' Oscillator used directly
    FCMEN    = Off                                              ' Fail-Safe Clock Monitor disabled
    IESO     = Off                                              ' Oscillator Switchover mode disabled
    PWRTEN   = On                                               ' Power up timer enabled
    BOREN    = Off                                              ' Brown-out Reset disabled
    BORV     = 190                                              ' VBOR set to 1.9 V nominal
    WDTPS    = 128                                              ' Watchdog Timer Postscale is 1:128
    HFOFST   = Off                                              ' The Access clock is not held Off until the HF-INTOSC is stable
    PBADEN   = Off                                              ' PORTB<4:0> pins are configured as digital on reset
    CCP2MX   = PORTC1                                           ' CCP2 input/output is multiplexed with RC1
    CCP3MX   = PORTB5                                           ' P3A/CCP3 input/output is multiplexed with RB5
    T3CMX    = PORTC0                                           ' T3CKI is on RC0
    P2BMX    = PORTB5                                           ' P2B is on RB5
    STVREN   = On                                               ' Stack full/underflow will cause a reset
    LVP      = Off                                              ' Single-Supply ICSP disabled
    Debug    = Off                                              ' Background debugger disabled. RB6 and RB7 configured as general purpose I/O pins
    XINST    = Off                                              ' Extra mnemonics disabled
    Cp0      = Off                                              ' Block 0 (000800-001FFF) not code protected
    CP1      = Off                                              ' Block 1 (002000-003FFF) not code protected
    CPB      = Off                                              ' Boot block (000000-0007FF) not code protected
    CPD      = Off                                              ' Data EEPROM not code protected
    WRT0     = Off                                              ' Block 0 (000800-001FFF) not write protected
    WRT1     = Off                                              ' Block 1 (002000-003FFF) not write protected
    WRTB     = Off                                              ' Boot block (000000-0007FF) not write protected
    WRTC     = On                                               ' Configuration registers (300000-3000FF) write protected
    WRTD     = Off                                              ' Data EEPROM not write protected
    EBTR0    = Off                                              ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1    = Off                                              ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB    = Off                                              ' Boot block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End

The demonstration, sets the trip of the LM75AD device, then, within a loop, reads the device and displays the temperature in Centigrade and Fahrenheit on an LCD, and transmits the temperature values to a serial terminal.

Below is a screenshot of the demonstration operating in the proteus simulator, and the code listings and proteus files are attached to this post:

LM75AD_Screenshot.jpg

Regards
Les