Witaj
Jeśli masz timeout to przyczyn może być wiele. Po pierwsze moduł ESEA wymaga zmostkowania linii TxD z RxD oraz -TxD -RxD (1-2 i 5-6). Po drugie upewnij się, że masz połączone masy ESEA z masą sterownika a sygnał RxDTxD dochodzi do D+ a -RxDTxD do D-.
Jeśli masz prawidłowo podłączony moduł ESEA to przy wysyłaniu zapytania modbus ze sterownika powinna migać dioda D1 (poza tym D3 powinno cały czas migać a D4 świecić ciągle. Jeśli sterownik odbierze poprawne dane, to powinien odpowiedzieć (mruganie D2, któremu towarzyszy mruganie diody).
Do tego transmisja musi być skonfigurowana identycznie po obu stronach.
U mnie jest 9600 8E1 dla ESEA, a ESEA ma ustawiony adres 2.
Poniżej mój program (troszkę go przerobiłem, żebyś miał łatwiej zmienić parametry transmisji). W jednym bloku obsługuję 3 urządzenia, więc musiałbyś program sobie okroić, żeby nie wykonywał niepotrzebnych operacji i nie czekał na nieistniejące urządzenia.
Program wymaga zdefiniowania zmiennych globalnych, które są zapisywane lub czytane:
temp_table: ARRAY[0..124] OF REAL;
hr_parameters_read: ARRAY[1..228] OF WORD;
dimmer_state: ARRAY[1..4] OF WORD;
A to program:
PROGRAM Modbus3
VAR CONSTANT
num_temp_sensors: INT := 17;
num_dimmer_modules: INT := 2; (* number of dimmers SCB + SCR *)
dimmer_array_size : INT := 4; (* must be 2 * num_dimmer_modules *)
max_errors: INT := 10; (* maximum retries before give up *)
HR_ADDRESS: BYTE := 1; (* heat recovery unit modbus address *)
TEMP_ADDRESS: BYTE := 7; (* WIRE-CHIP module modbus address *)
DIMMER_ADDRESS: BYTE := 2; (* dimmer SCR mosbus address *)
baudrate: COM_BAUDRATE := BAUD_9600;(* baudrate *)
com_port: BYTE := 16#03; (* port number ( 16#01 - built-in *)
stopbits: COM_STOPBITS := STOPBITS_1;
bytesize: COM_BYTESIZE := BS_8;
flow_control: COM_FLOW_CONTROL := HALFDUPLEX;
modbus_timeout: TIME := t#500ms; (* modbus awating response time *)
END_VAR
VAR
QueryAddress: INT :=0;
modbus_port: MODBUS_EXTENDED_MASTER;
modbus_query: typModbusExtendedQuery;
modbus_response: typModbusResponse;
modbus_exec: BOOL :=FALSE;
modbus_open_port: BOOL := FALSE;
modbus_parity: COM_PARITY := PARITY_NO; (* fo ESEA dimmer parity - even, for HR unit and WIRE-CHIP - none *)
(* modbus_error: enumMB_ERROR;*)
CUR_TIME: TIME;
LAST_READ_TEMP: TIME;
LAST_READ_HR: TIME;
HR_READ_Start: INT :=1;
READ_PERIOD_TEMP: TIME := T#10s;
READ_PERIOD_HR: TIME := T#9s;
DataToRead: BOOL := FALSE;
index: INT :=0;
WriteDimmer: BOOL :=FALSE;
ReadDimmer: BOOL := FALSE;
LAST_READ_DIMMER: TIME;
READ_PERIOD_DIMMER: TIME := T#16s;
dimmer_last_state: ARRAY[1..dimmer_array_size] OF INT;
State: INT := 0;
NUM_ERRORS: INT := 0;
WriteHR: BOOL := FALSE;
ReadHR: BOOL := FALSE;
HRLastTempSetPoint: REAL;
HRTempSetPoint: REAL;
LAST_CUR_TIME: TIME := T#0s;
HR_ERROR: BOOL := FALSE;
DIMMER_ERROR: BOOL := FALSE;
TEMP_ERROR: BOOL := FALSE;
END_VAR
CUR_TIME := DWORD_TO_TIME(T_PLC_MS());
IF CUR_TIME < LAST_CUR_TIME THEN (* TIME variable rollover *)
LAST_READ_DIMMER := T#16s;
LAST_READ_TEMP := T#10s;
LAST_READ_HR := T#9s;
END_IF
CASE State OF
0:
(*modbus_open_port := FALSE;*)
IF WriteDimmer THEN
modbus_query.SlaveAddress := DIMMER_ADDRESS;
modbus_query.FunctionCode := 16#10; (* Function WRITE *)
modbus_query.Write_StartAddress := 1199; (* Write from address 41200 *)
modbus_query.Write_Quantity := 2 * num_dimmer_modules; (* Read twice number of dimmer modules *)
FOR index:= 1 TO 2 * num_dimmer_modules DO
modbus_query.Write_Data [index-1] := dimmer_state [index];
END_FOR
STATE := 10;
ELSIF CUR_TIME > LAST_READ_DIMMER + READ_PERIOD_DIMMER OR ReadDimmer THEN
modbus_query.SlaveAddress := DIMMER_ADDRESS; (* read dimmer address - 1-wire chip *)
modbus_query.FunctionCode := 16#3; (* Function READ *)
modbus_query.Read_StartAddress := 1199; (* Read from address 1199 *)
modbus_query.Read_Quantity := 2 * num_dimmer_modules; (* Read number of sensors bytes *)
STATE := 10;
ELSIF WriteHR THEN
modbus_query.SlaveAddress := HR_ADDRESS; (* write address 1 - heat recovery unit *)
modbus_query.FunctionCode := 16#10; (* Function WRITE multiple register *)
modbus_query.Write_StartAddress := 1; (* Write address 1 - TempSetpoint *)
modbus_query.Write_Quantity := 1; (* Write 1 bytes *)
modbus_query.Write_Data [0] := REAL_TO_INT (HRTempSetPoint * 10);
STATE := 10;
ELSIF CUR_TIME > LAST_READ_HR + READ_PERIOD_HR OR ReadHR OR HR_READ_Start > 1 THEN
modbus_query.SlaveAddress := HR_ADDRESS; (* read address 1 - heat recovery unit *)
modbus_query.FunctionCode := 16#3; (* Function READ *)
modbus_query.Read_StartAddress := HR_READ_Start; (* Read from start address 1 or 33 *)
IF HR_Read_Start = 221 THEN
modbus_query.Read_Quantity := 8; (* Read 8 bytes *)
ELSE
modbus_query.Read_Quantity := 32; (* Read 32 bytes *)
END_IF
STATE := 10;
ELSIF CUR_TIME > LAST_READ_TEMP + READ_PERIOD_TEMP THEN
modbus_query.SlaveAddress := TEMP_ADDRESS; (* read address 7 - 1-wire chip *)
modbus_query.FunctionCode := 16#3; (* Function READ *)
modbus_query.Read_StartAddress := 0; (* Read from address 0 *)
modbus_query.Read_Quantity := num_temp_sensors; (* Read number of sensors bytes *)
STATE := 10;
END_IF
IF modbus_query.SlaveAddress = DIMMER_ADDRESS THEN
IF modbus_parity <> PARITY_EVEN THEN
modbus_open_port := FALSE;
END_IF
modbus_parity := PARITY_EVEN;
ELSE
IF modbus_parity <> PARITY_NO THEN
modbus_open_port := FALSE;
END_IF
modbus_parity := PARITY_NO;
END_IF
10:
IF NOT modbus_port.ENABLE THEN
modbus_open_port := TRUE;
ELSE
STATE := 20;
END_IF
20:
IF NOT modbus_exec THEN
modbus_exec := TRUE;
ELSE
STATE := 30;
END_IF
30:
IF NOT modbus_exec THEN
IF modbus_port.MB_Error = MB_NO_ERROR AND modbus_response.SlaveAddress = modbus_query.SlaveAddress THEN
IF modbus_response.FunctionCode = 16#3 THEN
CASE modbus_response.SlaveAddress OF
HR_ADDRESS:
HR_READ_Start := modbus_response.StartAddress;
FOR index := 0 TO modbus_response.Quantity-1 DO
hr_parameters_read[HR_READ_Start + index] := modbus_response.Data[index];
END_FOR
HR_READ_Start := HR_READ_Start + 32;
IF HR_READ_Start > 221 THEN
HR_READ_Start := 1;
ReadHR := FALSE;
HR_ERROR :=FALSE;
ELSIF HR_READ_Start > 128 THEN
HR_READ_Start := 221;
END_IF
LAST_READ_HR := CUR_TIME;
DIMMER_ADDRESS:
FOR index:= 1 TO 2 * num_dimmer_modules DO
dimmer_last_state [index] := modbus_response.Data [index-1];
END_FOR;
LAST_READ_DIMMER := CUR_TIME;
ReadDimmer := FALSE;
DIMMER_ERROR := FALSE;
TEMP_ADDRESS:
IF modbus_response.StartAddress = 0 THEN (* this prevents wrong data being read from temp sensors *)
temp_table := WORD_ARRAY_TO_TEMP(input_array := modbus_response.Data, num_elements := modbus_response.Quantity);
LAST_READ_TEMP := CUR_TIME;
TEMP_ERROR := FALSE;
END_IF
END_CASE
ELSIF modbus_response.FunctionCode = 16#10 OR modbus_response.FunctionCode = 16#6 THEN
CASE modbus_response.SlaveAddress OF
DIMMER_ADDRESS:
WriteDimmer := FALSE;
ReadDimmer := TRUE;
DIMMER_ERROR := FALSE;
HR_ADDRESS:
WriteHR := FALSE;
ReadHR := TRUE;
HR_ERROR := FALSE;
END_CASE
END_IF
ELSE
NUM_ERRORS := NUM_ERRORS + 1;
IF NUM_ERRORS > max_errors THEN
NUM_ERRORS := 0;
CASE modbus_query.SlaveAddress OF
TEMP_ADDRESS:
LAST_READ_TEMP := CUR_TIME;
TEMP_ERROR := TRUE;
DIMMER_ADDRESS:
LAST_READ_DIMMER := CUR_TIME;
DIMMER_ERROR := TRUE;
HR_ADDRESS:
LAST_READ_HR := CUR_TIME;
HR_READ_START := 1;
HR_ERROR := TRUE;
END_CASE
END_IF
END_IF
STATE := 40;
END_IF
40:
(*modbus_open_port := FALSE;*)
modbus_query.SlaveAddress := 0;
modbus_query.FunctionCode := 16#0;
modbus_query.Read_StartAddress := 0;
modbus_query.Read_Quantity := 0;
STATE := 0;
END_CASE
IF HRLastTempSetPoint <> HRTempSetPoint AND HRTempSetPoint <> 0 THEN
HRLastTempSetPoint := HRTempSetPoint;
IF HRLastTempSetPoint <> 0 THEN
WriteHR := TRUE;
END_IF
END_IF
IF NOT ReadDimmer THEN
FOR index := 1 TO 2 * num_dimmer_modules DO
IF dimmer_last_state [index] <> dimmer_state [index] THEN
WriteDimmer := TRUE;
(*dimmer_last_state [index] := dimmer_state [index];*)
END_IF
END_FOR
END_IF
modbus_port(StartFunction := modbus_exec, ExtQuery := modbus_query, Response := modbus_response, ENABLE := modbus_open_port, ASCII_Mode := FALSE, bCOM_PORT := com_port, cbCOM_BAUDRATE := baudrate, csCOM_STOPBITS := stopbits, cbsCOM_BYTESIZE := bytesize, cpCOM_PARITY := modbus_parity, cfCOM_FLOW_CONTROL := flow_control, tTIME_OUT := modbus_timeout );
LAST_CUR_TIME := CUR_TIME;