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?
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
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
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.
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 Load_Voltage, Load_Current, Battery_Current
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,Load_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)))
Load_Voltage = LongToFloat16((modin(21)))
Battery_Current = LongToFloat16((modin(22)))
Load_Current = LongToFloat16((modin(23)))
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
Wow! Thanks everyone! I can't wait to give it a try!
Curt