Phoenix Contact PLCNext Socket to Eth Scale
Overview
Simple Ohaus scale with Ethernet and we need the data!
Our scale, an Ohaus Valor 7000 gets its IP via DHCP so we have our DHCP server assigning 192.168.4.179. The TCP port for sending and receiving data is 9761.
To get data from our scale sending ‘P\r\n’ seems to work. If you’re not familiar with that notation \r = carriage return and \n = new line.
adamd@pop-os:~$ nc 192.168.4.179 9761
P
2.0135 lb
P
3.0865 lb ?
P
12.6450 lb
Points of note:
- I used netcat or nc on Linux to connect directly to the scale for testing. Other options would be telnet or putty. Very valuable to test it in a simple terminal before trying to get it working via socket programming.
- Unstable readings have a ? at the end.
- The whole number part can be one or two digits.
- There are spaces present before our number.
Function block ‘ScaleGetData’
While not complete this code is getting the job done. Missing is error handling, dealing with different units, etc. Also since we start our exponent at -4 and don’t properly look for a decimal point this only works because this device always sends 4 places after the decimal.
There are many ways to accomplish this task. Another, potentially better way, is to use the buf_to_real function after capturing the section containing our value from the returned string.
Variables:
Group,Name,DataType,Usage,IsTranslate,Comment,InitValue,AccessSpecifier,IsRetain,IsConstant,IsOpc,IsHmi,IsProficloud,Address
,sIpAddr,STRING,Input,False,,,None,False,False,False,False,False,
,uiPort,UINT,Input,False,,,None,False,False,False,False,False,
,SockScale,TLS_SOCKET_2,Local,False,,,None,False,False,False,False,False,
,bConnect,BOOL,Input,False,,,None,False,False,False,False,False,
,dwScaleHandle,DWORD,Local,False,,,None,False,False,False,False,False,
,baOutBuf,ByteArray35,Local,False,,,None,False,False,False,False,False,
,SockScaleSend,TLS_SEND_2,Local,False,,,None,False,False,False,False,False,
,bRequestData,BOOL,Input,False,,,None,False,False,False,False,False,
,SockScaleRec,TLS_RECEIVE_2,Local,False,,,None,False,False,False,False,False,
,bEnableReceive,BOOL,Local,False,,,None,False,False,False,False,False,
,baInBuf,ByteArray35,Local,False,,,None,False,False,False,False,False,
,bGetData,BOOL,Local,False,,,None,False,False,False,False,False,
,iBytesAvailable,INT,Local,False,,,None,False,False,False,False,False,
,x,INT,Local,False,,,None,False,False,False,False,False,
,rTemp,REAL,Local,False,,,None,False,False,False,False,False,
,iExponent,INT,Local,False,,,None,False,False,False,False,False,
,bStable,BOOL,Output,False,,,None,False,False,False,False,False,
,rThisDigit,REAL,Local,False,,,None,False,False,False,False,False,
,rValueOut,REAL,Output,False,,,None,False,False,False,False,False,
,bNewRead,BOOL,Output,False,,,None,False,False,False,False,False,
,bConnectedOk,BOOL,Output,False,,,None,False,False,False,False,False,
Code:
SockScale(ACTIVATE := bConnect, DEST_IP := sIpAddr, DEST_PORT := uiPort, HANDLE => dwScaleHandle);
bConnectedOK := SockScale.ACTIVE;
baOutBuf[0] := 80; // 'P'
baOutBuf[1] := 13; // 'Carriage Return'
baOutBuf[2] := 10; // 'Line Feed'
SockScaleSend(REQ := bRequestData, HANDLE := dwScaleHandle, DATA_CNT := udint#3, DATA := baOutBuf);
// ******************************************************************************************
// *****************************************************************************************
SockScaleRec(EN_R := bEnableReceive, HANDLE := dwScaleHandle, EXP_DATA_CNT := SIZEOF(baInBuf),DATA := baInBuf);
(* Receiving data tricks *)
(* Set ExpectedDataCount = buffer size. This will make DATA_CNT actually give values up to max buffer size *)
(* Toggle EnableReceive off, then on again to reset DATA_CNT to zero *)
If bGetData or SockScaleRec.DATA_CNT > 1 THEN //Is there any data?
iBytesAvailable := to_int(SockScaleRec.DATA_CNT); //How many bytes to loop through
bEnableReceive := False; //need to toggle to reset DATA_CNT
rTemp := 0.0;
iExponent := -4; // Start with -4 or 10**-4 which is 0.0001 and work up
bStable := True;
for x := (iBytesAvailable - 1) to 0 BY -1 DO
// ASCII numbers are 0x30 to 0x39, we capture all ASCII numbers
IF baInBuf[x] >= 16#30 and baInBuf[x] <= 16#39 THEN
rThisDigit := to_real(TO_DINT(baInBuf[x]) - 16#30); // Trick for ASCII to value conversion
rTemp := rTemp + (rThisDigit * (10.0**iExponent));
iExponent := iExponent + 1;
End_if;
If baInBuf[x] = byte#63 then //Is there a ? in the string?
bStable := False;
End_if;
End_For;
rValueOut := rTemp; //pass out the final anser
bGetData := false;
bNewRead := True;
ELSE
//If we are connected keep receive on
bEnableReceive := SockScale.ACTIVE;
End_if;
If NOT(bRequestData) THEN
rValueOut := 0.0;
bNewRead := False;
End_if;
Implemented in code
ScaleGetData1(sIpAddr := '192.168.4.179', uiPort := 9761, bConnect := bDoIt, bRequestData := bGetData,
bStable => bGoodValue,
rValueOut => rTheValue,
bNewRead => bNewData,
bConnectedOk => bConnectSuccess);