Our full technical support staff does not monitor this forum. If you need assistance from a member of our staff, please submit your question from the Ask a Question page.

### Float16 (half Precision)

Curt_Ingram Nov 8, 2021 02:13 AM

I'm trying to read data from a Morningstar Sunsaver MPPT that outputs modbus in Float16, is there anyone that has done this with the modbuusmaster command?

nsw Nov 8, 2021 10:32 AM

There is an example program on our website for the Morningstar Sunsaver MPPT using a CR1000X. It can be found here:

https://s.campbellsci.com/documents/us/miscellaneous/CR1000X-38898.dld

Curt_Ingram Nov 9, 2021 01:49 AM

unfortunately, I made a mistake.  It is a TriStar MPPT, and they changed all of their output types to float16.  The example provided does work with my sunsavers for sure but no this new controller.  :(

Thanks you for the reply though!

Curt

notcabbage Nov 9, 2021 03:23 AM

Here's a (clunky) subroutine I whipped up to convert an Integer16 into a float16. Basically, we're just reading 2 bytes in a modbus register, converting that signed integer16 to binary, and then converting back to a float 16.

Example: Reading the battery voltage register we get back 21226

Subroutine:

```Public Result, MPPTCharger, battvolts As Long, value As Float

'========FLOAT 16===========
Sub f\$float16 (returnValue, int16 As Long)
Dim binary As String, exponent As Long, i As Long, temp As Long, mantissa As Float
binary=FormatLong (int16,"%b")
'##EXPONENT##
exponent = -15
For i = 1 To 5
temp = Mid(binary,6-i,1)
exponent += temp*2^(i-1)
Next i
exponent = 2^exponent
'##MANTISSA'
mantissa = 0
For i = 6 To 15
temp = Mid(binary,21-i,1)
mantissa += temp*2^(i-6)
Next i
mantissa = 1+ mantissa/1024
If int16 < 0 Then
mantissa = mantissa*-1
End If
returnValue = exponent*mantissa
EndSub

SlowSequence
Scan (15,Sec,0,0)
TCPOpen ("127.0.0.1",502,1,500,MPPTCharger,1)
ModbusMaster (Result, MPPTCharger,9600,1,3,battvolts,25,1,3,200,1)
Call f\$float16(value,battvolts)
NextScan```

This returns the expected value of 55.3125. Hopefully a MoveBytes wizard can come around and do something slicker, but this is my solution until ModbusMaster can handle half-precision floats.

Jaab Nov 10, 2021 07:06 PM

Here is a program developed for the Tristar by someone at CSI that we've used in the past:

Public result
Public modin(82) As Long

Public N_sys_V

Public Charge_Current, Battery_Terminal_Voltage, Array_Current, Array_Voltage
Public HeatSink_Temperature, Battery_Temperature
Public Charger_Output_Power, Array_Vmp,Array_Pmax,Array_Voc

DataTable(Power,true,-1)
DataInterval(0,30,sec,10)
Sample (1,Charge_Current,FP2)
Sample (1,Battery_Terminal_Voltage,FP2)
Sample (1,Battery_Current,FP2)
Sample (1,HeatSink_Temperature,FP2)
Sample (1,Battery_Temperature,FP2)
Sample (1,Array_Vmp,FP2)
Sample (1,Array_Voc,FP2)
Sample (1,Array_Pmax,FP2)
Sample (1,Charger_Output_Power,FP2)
EndTable

Function LongToFloat16(SourceLong As Long) As Float

'Takes a Float16 stored in the lower 2 bytes of a Long, and converts to a Float

Dim SignBit As Long
Dim Exponent As Long
Dim Fraction As Long
Dim tempLong As Long
Dim result As Float 'The Float16 moved into a single precision 32 bit float

Erase(tempLong)
Erase(result)

SignBit = (SourceLong >> 15) AND 1
Exponent = ((SourceLong >> 10) AND 31) -15 + 127 'Float16 has a bias of 15, Float32 has a bias of 127

If Exponent = 143 Then Exponent = 255 'NAN catch
If Exponent = 112 Then Exponent = 0 'Zero catch
Fraction = SourceLong AND 1023

tempLong = (Exponent << 23) OR (Fraction << 13 )
MoveBytes (result,0,tempLong,0,4)
If SignBit Then result = result * -1 'Since long are signed, I can't just OR the sign bit

Return result
EndFunction

BeginProg  SerialOpen (ComRS232,9600,7,0,50)

Scan (5,Sec,0,0)

'Code to measure Tristar charge controller
ModbusMaster (result,ComRS232,9600,1,3,modin(),1,82,3,100,3)

N_sys_V=LongToFloat16((modin(2)))
Charge_Current = LongToFloat16((modin(17)))
Battery_Terminal_Voltage = LongToFloat16((modin(19)))
Array_Current = LongToFloat16((modin(18)))
Array_Voltage = LongToFloat16((modin(20)))
'Battery_Sense_Voltage = LongToFloat16((modin(24)))
Battery_Current = LongToFloat16((modin(22)))
HeatSink_Temperature =LongToFloat16((modin(27)))
Battery_Temperature = LongToFloat16((modin(28)))
Charger_Output_Power = LongToFloat16((modin(61)))
Array_Vmp = LongToFloat16((modin(62)))
Array_Pmax = LongToFloat16((modin(63)))
Array_Voc = LongToFloat16((modin(64)))

CallTable power
NextScan

EndProg

Curt_Ingram Nov 11, 2021 03:48 AM

Wow! Thanks everyone!  I can't wait to give it a try!

Curt