320 lines
10 KiB
Markdown
320 lines
10 KiB
Markdown
|
|
## Introduction
|
|
|
|
This document provides an implementation guide for establishing communication between a Maselli sensor (which uses the ADAM protocol over RS485) and a Siemens S7-315 DP/PN PLC using a Waveshare RS232/485 TO WIFI ETH (B) gateway. This implementation handles the unidirectional communication where data flows from the sensor to the PLC.
|
|
|
|
## Maselli Protocol with ADAM Overview
|
|
|
|
As per the provided documentation, the Maselli sensor communicates with the following characteristics:
|
|
|
|
- **Maselli UR29**: RS485 with 115200 baud, 8N1 settings
|
|
|
|
- **Maselli UR62**: RS485 with 19200 baud, 8N1 settings
|
|
|
|
- **Communication Type**: Unidirectional (sensor sends data to PLC)
|
|
|
|
- **Data Format**: String with specific format:
|
|
|
|
```
|
|
# XX XX.YYY CkCk Cr
|
|
```
|
|
|
|
Where:
|
|
|
|
- `#` is the start character
|
|
- `XX` is the ADAM address (2 chars)
|
|
- `XX.YYY` is the Brix or Temperature value in mA (6 chars)
|
|
- `CkCk` is the checksum (2 chars)
|
|
- `Cr` is the carriage return
|
|
- **Value Range Example**:
|
|
|
|
- 4 mA corresponds to Low Brix value (e.g., 0 Brix)
|
|
- 20 mA corresponds to High Brix value (e.g., 80 Brix)
|
|
|
|
## SCL Implementation
|
|
|
|
The following SCL code provides a complete implementation for handling this communication. The implementation consists of multiple parts:
|
|
|
|
1. A function block for managing TCP/IP communication with the gateway
|
|
2. Functions for parsing the Maselli protocol string
|
|
3. Functions for scaling the mA value to the appropriate Brix value
|
|
4. Configuration functions for the TCP connection
|
|
|
|
### Main Function Block
|
|
|
|
```scl
|
|
FUNCTION_BLOCK "FB_Maselli_Communications"
|
|
VAR_INPUT
|
|
xExecute : BOOL; // Trigger to initiate connection
|
|
tConnectionID : TCON_IP_v4; // TCP connection parameters
|
|
END_VAR
|
|
|
|
VAR_OUTPUT
|
|
xConnected : BOOL; // Connection status
|
|
xError : BOOL; // Communication error
|
|
wErrorID : WORD; // Error code
|
|
rBrixValue : REAL; // Calculated Brix value
|
|
rTempValue : REAL; // Calculated Temperature value (if applicable)
|
|
rCurrentmA : REAL; // Received mA value
|
|
END_VAR
|
|
|
|
VAR
|
|
// TCP communication variables
|
|
fbTCON : TCON; // FB for TCP connection
|
|
fbTRCV : TRCV; // FB for TCP reception
|
|
xTCONExecute : BOOL;
|
|
xTRCVExecute : BOOL;
|
|
wTCONID : WORD := 1; // Connection ID
|
|
|
|
// Buffer and processing variables
|
|
aRxBuffer : ARRAY[0..255] OF BYTE; // Reception buffer
|
|
iRxLength : INT; // Received length
|
|
sRxString : STRING[255]; // Reception string
|
|
sParsedValue : STRING[6]; // Extracted value as string (XX.YYY)
|
|
|
|
// Parsing variables
|
|
iState : INT := 0; // Parsing state
|
|
xNewDataReceived : BOOL := FALSE; // New data flag
|
|
|
|
// Scaling variables
|
|
rLowBrix : REAL := 0.0; // Low Brix value (4mA)
|
|
rHighBrix : REAL := 80.0; // High Brix value (20mA)
|
|
END_VAR
|
|
|
|
VAR CONSTANT
|
|
START_CHAR : BYTE := 16#23; // '#' in ASCII
|
|
END_VAR
|
|
|
|
BEGIN
|
|
// ---- TCP Connection Management ----
|
|
IF xExecute AND NOT xConnected THEN
|
|
xTCONExecute := TRUE;
|
|
END_IF;
|
|
|
|
// Establish connection
|
|
fbTCON(
|
|
EN := TRUE,
|
|
ENO => ,
|
|
REQ := xTCONExecute,
|
|
ID := wTCONID,
|
|
CONNECT := tConnectionID,
|
|
DONE => xConnected,
|
|
BUSY => ,
|
|
ERROR => xError,
|
|
STATUS => wErrorID
|
|
);
|
|
|
|
// Reset connection trigger
|
|
IF xConnected OR xError THEN
|
|
xTCONExecute := FALSE;
|
|
END_IF;
|
|
|
|
// ---- Data Reception ----
|
|
IF xConnected THEN
|
|
xTRCVExecute := TRUE;
|
|
|
|
// Receive data
|
|
fbTRCV(
|
|
EN := TRUE,
|
|
ENO => ,
|
|
REQ := xTRCVExecute,
|
|
ID := wTCONID,
|
|
LEN := 0, // Adhoc mode (receives whatever is available)
|
|
DATA := aRxBuffer,
|
|
RCVD_LEN => iRxLength,
|
|
DONE => xNewDataReceived,
|
|
BUSY => ,
|
|
ERROR => xError,
|
|
STATUS => wErrorID
|
|
);
|
|
|
|
// Process received data
|
|
IF xNewDataReceived AND iRxLength > 0 THEN
|
|
// Convert data to string for processing
|
|
sRxString := '';
|
|
FOR i := 0 TO iRxLength-1 DO
|
|
sRxString := CONCAT(IN1 := sRxString,
|
|
IN2 := CHR(IN := aRxBuffer[i]));
|
|
END_FOR;
|
|
|
|
// Process Maselli/ADAM protocol
|
|
ParseMaselliString(sRxString);
|
|
|
|
// Calculate Brix value based on mA value (linear scale)
|
|
rBrixValue := LinearScale(rCurrentmA, 4.0, 20.0, rLowBrix, rHighBrix);
|
|
|
|
// Reset flag
|
|
xNewDataReceived := FALSE;
|
|
END_IF;
|
|
END_IF;
|
|
END_FUNCTION_BLOCK
|
|
```
|
|
|
|
### Parsing Function
|
|
|
|
```scl
|
|
// Function to process the received Maselli/ADAM string
|
|
FUNCTION "ParseMaselliString" : VOID
|
|
VAR_INPUT
|
|
sInputString : STRING;
|
|
END_VAR
|
|
VAR_TEMP
|
|
sCurrentChar : STRING(1);
|
|
iPos : INT := 0;
|
|
iParseState : INT := 0; // 0:Waiting for #, 1:Reading addr, 2:Reading value, 3:Reading checksum
|
|
sAddrStr : STRING(2);
|
|
sValueStr : STRING(6);
|
|
sChecksumStr : STRING(2);
|
|
END_VAR
|
|
BEGIN
|
|
// Reset variables
|
|
sAddrStr := '';
|
|
sValueStr := '';
|
|
sChecksumStr := '';
|
|
|
|
// Parse the string character by character
|
|
FOR iPos := 0 TO LEN(sInputString) - 1 DO
|
|
sCurrentChar := MID(IN := sInputString, L := 1, P := iPos + 1);
|
|
|
|
CASE iParseState OF
|
|
0: // Waiting for start character '#'
|
|
IF sCurrentChar = '#' THEN
|
|
iParseState := 1;
|
|
END_IF;
|
|
|
|
1: // Reading ADAM address (2 characters)
|
|
sAddrStr := CONCAT(IN1 := sAddrStr, IN2 := sCurrentChar);
|
|
IF LEN(sAddrStr) = 2 THEN
|
|
iParseState := 2;
|
|
END_IF;
|
|
|
|
2: // Reading mA value (6 characters, format XX.YYY)
|
|
sValueStr := CONCAT(IN1 := sValueStr, IN2 := sCurrentChar);
|
|
IF LEN(sValueStr) = 6 THEN
|
|
iParseState := 3;
|
|
// Convert string to real value
|
|
#rCurrentmA := STRING_TO_REAL(sValueStr);
|
|
END_IF;
|
|
|
|
3: // Reading checksum (2 characters)
|
|
sChecksumStr := CONCAT(IN1 := sChecksumStr, IN2 := sCurrentChar);
|
|
// Checksum validation not implemented in this simplified example
|
|
END_CASE;
|
|
END_FOR;
|
|
END_FUNCTION
|
|
```
|
|
|
|
### Scaling Function
|
|
|
|
```scl
|
|
// Function to linearly scale the mA value to Brix
|
|
FUNCTION "LinearScale" : REAL
|
|
VAR_INPUT
|
|
rInput : REAL; // Value to scale (mA)
|
|
rInMin : REAL; // Input minimum (4mA)
|
|
rInMax : REAL; // Input maximum (20mA)
|
|
rOutMin : REAL; // Output minimum (0 Brix)
|
|
rOutMax : REAL; // Output maximum (80 Brix)
|
|
END_VAR
|
|
BEGIN
|
|
// Linear scaling formula
|
|
#LinearScale := (rInput - rInMin) * (rOutMax - rOutMin) / (rInMax - rInMin) + rOutMin;
|
|
|
|
// Ensure result is within limits
|
|
IF #LinearScale < rOutMin THEN
|
|
#LinearScale := rOutMin;
|
|
ELSIF #LinearScale > rOutMax THEN
|
|
#LinearScale := rOutMax;
|
|
END_IF;
|
|
END_FUNCTION
|
|
```
|
|
|
|
### Main Application Block
|
|
|
|
```scl
|
|
// Main application block
|
|
ORGANIZATION_BLOCK "OB1"
|
|
VAR_TEMP
|
|
// Temporary variables
|
|
END_VAR
|
|
BEGIN
|
|
// Configure TCP connection
|
|
"ConfigureTCPConnection"();
|
|
|
|
// Process Maselli data
|
|
"FB_Maselli_Communications"(
|
|
xExecute := TRUE,
|
|
tConnectionID := "g_tConnection"
|
|
);
|
|
|
|
// Additional code to use Brix values can be added here
|
|
END_ORGANIZATION_BLOCK
|
|
```
|
|
|
|
### Connection Configuration Function
|
|
|
|
```scl
|
|
// Function to configure TCP connection parameters
|
|
FUNCTION "ConfigureTCPConnection" : VOID
|
|
VAR_GLOBAL
|
|
g_tConnection : TCON_IP_v4; // Global variable for connection parameters
|
|
END_VAR
|
|
BEGIN
|
|
// Configure TCP connection parameters
|
|
g_tConnection.InterfaceId := 64; // Ethernet interface ID (verify in hardware)
|
|
g_tConnection.ID := 1; // Connection ID
|
|
g_tConnection.ConnectionType := 11; // Connection type: TCP
|
|
g_tConnection.ActiveEstablished := TRUE; // PLC initiates connection
|
|
|
|
// IP and port of Waveshare gateway
|
|
g_tConnection.RemoteAddress.ADDR[1] := 192; // IP Address: 192.168.x.x
|
|
g_tConnection.RemoteAddress.ADDR[2] := 168; // Adjust according to gateway IP
|
|
g_tConnection.RemoteAddress.ADDR[3] := 1; // Adjust according to gateway IP
|
|
g_tConnection.RemoteAddress.ADDR[4] := 10; // Adjust according to gateway IP
|
|
g_tConnection.RemotePort := 8899; // Default gateway port
|
|
|
|
// Local port for TCP connection
|
|
g_tConnection.LocalPort := 2000; // Arbitrary local port
|
|
END_FUNCTION
|
|
```
|
|
|
|
## Configuration Guide
|
|
|
|
To implement this solution, follow these steps:
|
|
|
|
### 1. Configure the Waveshare Gateway
|
|
|
|
Configure the Waveshare RS232/485 TO WIFI ETH (B) gateway in transparent transmission mode with these parameters:
|
|
|
|
- **For UR29 sensor**:
|
|
|
|
- RS485: 115200 baud, 8N1
|
|
- TCP Server mode (recommended)
|
|
- Fixed IP address on your network
|
|
- **For UR62 sensor**:
|
|
|
|
- RS485: 19200 baud, 8N1
|
|
- TCP Server mode (recommended)
|
|
- Fixed IP address on your network
|
|
|
|
### 2. PLC Configuration
|
|
|
|
- Import the SCL code into your TIA Portal project
|
|
- Adjust the IP address settings in the `ConfigureTCPConnection` function to match your gateway's IP
|
|
- Modify the `rLowBrix` and `rHighBrix` values according to your specific application requirements
|
|
- Configure the Ethernet port of the S7-315 PLC to be on the same subnet as the gateway
|
|
|
|
### 3. Verification
|
|
|
|
After implementing the code:
|
|
|
|
- Monitor the `xConnected` output to verify the connection status
|
|
- Check the `rBrixValue` output to see the converted Brix values
|
|
- Use the `xError` and `wErrorID` outputs for troubleshooting if connection issues occur
|
|
|
|
## Additional Notes
|
|
|
|
- This implementation focuses on handling the reception of data in the specified Maselli/ADAM format
|
|
- The checksum validation is not implemented in this example but could be added for improved reliability
|
|
- For optimal performance, ensure the network connection between the PLC and the gateway is stable
|
|
- Consider adding watchdog functionality to detect communication failures |