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 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

Curt_Ingram
Nov 11, 2021 03:48 AM

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

Curt