' *****************************************************************************
' * MAX31855 Thermocouple Temperature Sensor - Compact Software SPI Library
' * ---------------------------------------------------------------------------
' * Device:      MAX31855K
' * Sensor:      K-type thermocouple
' * Interface:   Read-only SPI-compatible serial interface (software bit-bang)
' * Data format: 32-bit serial word, MSB first
' * Resolution:  Thermocouple: 0.25 °C/LSB
' *              Cold junction: 0.0625 °C/LSB
' * ---------------------------------------------------------------------------
' * By COS (dogflu66@yahoo.es)
' * PIC18F46K22 @ 64 MHz (Fosc/4)
' * Oshonsoft PIC18 Basic Compiler v6.10
' * v20261003
' * ---------------------------------------------------------------------------
' *	MAX31855 pin configuration, pin names used in the MRC167A module.
' *
' * The MAX31855 performs cold-junction compensation and converts the
' * thermocouple voltage into a digital signed 14-Bit temperature value.
' *
' * Communication is read-only: the MAX31855 does not receive commands or data.
' * The PIC controls CS and SCK and reads the serial data from the SO pin.
' *
' * MAX31855_Read() returns the measured thermocouple temperature directly
' * in degrees Celsius. The internal cold-junction temperature is returned
' * through the internal_temp argument.
' *
' * The error_code argument is updated according to the three MAX31855
' * fault bits:
' *
' *     OC  - Open Circuit
' *     SCG - Short Circuit to GND
' *     SCV - Short Circuit to VCC
' *
' * If an open thermocouple, short circuit to GND, or short circuit to VCC
' * is detected, the function returns -999.0 °C as an error indication.
' *
' * NOTE:
' * The MAX31855 starts a new temperature conversion when CS returns HIGH.
' * Conversion continues while CS remains HIGH.
' *****************************************************************************

' -----------------------------------------------------------------------------
' MAX31855 pin configuration, pin names used in the MRC167A module CS CLK DO.
' -----------------------------------------------------------------------------
Symbol MAX31855_CS =       LATC.2      ' (CS) Chip Select output
Symbol MAX31855_SCK =      LATC.3      ' (CLK) Serial Clock output
Symbol MAX31855_SO =       PORTC.5     ' (DO) Serial Data input (SO / MISO)

Symbol MAX31855_CS_IO =    TRISC.2     ' Direction control
Symbol MAX31855_SCK_IO =   TRISC.3     ' Direction control
Symbol MAX31855_SO_IO =    TRISC.5     ' Direction control

' -----------------------------------------------------------------------------
' MAX31855 diagnostic fault bits
' -----------------------------------------------------------------------------
Const MAX31855_ERROR_OC  = 0x01        ' OC  = Open Circuit
Const MAX31855_ERROR_SCG = 0x02        ' SCG = Short Circuit to GND
Const MAX31855_ERROR_SCV = 0x04        ' SCV = Short Circuit to VCC

' -----------------------------------------------------------------------------
' Initialize MAX31855 interface
' -----------------------------------------------------------------------------
Function MAX31855_Init() As Byte

    Low MAX31855_CS_IO             ' Configure CS as output
    Low MAX31855_SCK_IO            ' Configure SCK as output
    High MAX31855_SO_IO            ' Configure SO as input

    High MAX31855_CS               ' MAX31855 initially deselected
    Low MAX31855_SCK               ' Clock idle state = LOW

End Function

' -----------------------------------------------------------------------------
' Read MAX31855 temperature and diagnostic data
'
' Returns:
'   Thermocouple temperature in degrees Celsius.
'   -999.0 if a thermocouple fault is detected.
'
' Arguments:
'   error_code    - MAX31855 fault code (OC, SCG, or SCV).
'   internal_temp - Internal cold-junction temperature in degrees Celsius.
' -----------------------------------------------------------------------------
Function MAX31855_Read(ByRef error_code As Byte, ByRef internal_temp As Single) As Single

    Dim i As Byte
    Dim data_raw As Long
    Dim temp_comp As LongInt
    Dim temp_celsius As Single
    Dim SO_Input As Byte

    data_raw = 0
    temp_celsius = 0.0
    SO_Input = 0

    Low MAX31855_CS               ' Select MAX31855
    WaitMs 1

    ' Read the 32-bit serial data word, MSB first (software bit-banging)
    CFor (i = 0; i < 32; i++)
        High MAX31855_SCK
        WaitMs 1

        SO_Input.0 = MAX31855_SO
        data_raw = (data_raw << 1) | SO_Input

        Low MAX31855_SCK
        WaitMs 1
    CNext

    High MAX31855_CS              ' Deselect MAX31855

    ' -------------------------------------------------------------------------
    ' 1. Check global fault bit (D16)
    ' -------------------------------------------------------------------------
    If BitTest(data_raw, 16) Then

        ' Extract the individual fault bits D2..D0:
        ' D0 = OC, D1 = SCG, D2 = SCV
        error_code = CByte (data_raw & 0x00000007)

        internal_temp = 0.0

        ' Return error indication
        ReturnValue -999.0
        Exit
    Endif

    error_code = 0                ' No fault detected

    ' -------------------------------------------------------------------------
    ' 2. Process internal cold-junction temperature (D15..D4)
    ' -------------------------------------------------------------------------

    ' Extract the 12-bit signed cold-junction temperature value
    temp_comp = CLongInt ((data_raw >> 4) & 0x00000FFF)

    ' Sign-extend the 12-bit value.
    ' Bit 11 becomes the sign bit after shifting.
    If BitTest(temp_comp, 11) Then
        temp_comp = temp_comp | 0xFFFFF000
    Endif

    ' Cold-junction temperature resolution = 0.0625 °C/LSB
    internal_temp = CSingle temp_comp * 0.0625

    ' -------------------------------------------------------------------------
    ' 3. Process thermocouple temperature (D31..D18)
    ' -------------------------------------------------------------------------

    ' Shift the 14-bit signed thermocouple value to the least significant bits
    temp_comp = CLongInt (data_raw >> 18)

    ' Sign-extend the 14-bit value.
    ' Bit 13 becomes the sign bit after shifting.
    If BitTest(temp_comp, 13) Then
        temp_comp = temp_comp | 0xFFFFC000
    Endif

    ' Thermocouple temperature resolution = 0.25 °C/LSB
    temp_celsius = CSingle temp_comp * 0.25

    ReturnValue temp_celsius

End Function
