|
//-----------------------------------------------------------------------------
// SimpleSlave.vpl, created 2011-03-22 12:00
//
// This simple MODBUS slave is using the I/0 Extension to share its resources.
//
// IMPORTANT:
// As the memory, analog and digital in-/outputs are controlled by the firmware
// these must not be mapped using the Job configuration.
//
// LED's and switches can be controlled by the application as these are not
// accessible through MODBUS requests.
//
// To see which MODBUS commands that are supported by the I/O Extensions please
// see the "I/O Extension -> MODBUS commands" section of the online help
//
// Alternative communication with the master form the application:
//
// The only way to communicate with the MODBUS master from the application is
// through memory registers, as these can be accessed without mapping in the
// job, through the use of memioRead/memioReadX and memioWrite/memioWriteX
// functions.
//
// Note:
// When a memory register are accessed through MODBUS they are read as two
// 16bits addresses as they are 32bits long.
//
// The memory registers can be read as input register or read/written as
// holding registers.
//
// Start index of the memory registers are 0x1000 hex or 4096 decimal.
//
// MODBUS Configuration:
// Configuration of connection settings and node id is done through
// I/0 Extension, please see 'Using the I/O Extension' in the online help.
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
VAR_INPUT
SW : ARRAY [1..3] OF BOOL;
END_VAR;
VAR_OUTPUT
LED : ARRAY [1..4] OF BOOL;
END_VAR;
//-----------------------------------------------------------------------------
// THREAD_BLOCK: RegisterMonitor
// Monitor IO memory for changes.
//
// INPUT
// run : Start/Stop monitoring
// first : First index to monitor
// last : Last index to monitor
//-----------------------------------------------------------------------------
THREAD_BLOCK RegisterMonitor;
VAR_INPUT
run : BOOL := TRUE;
first : INT := 1;
last : INT := 4096;
END_VAR;
VAR
cur : ARRAY [1..4096] OF DINT;
old : ARRAY [1..4096] OF DINT;
msg : STRING := "register \1 has changed from \4 to ";
i : INT;
rc : INT;
rc_o : INT;
err : STRING := "RegisterMonitor - Failed to read memory ";
END_VAR;
DebugMsg(message := "RegisterMonitor - Started");
rc := 0;
rc_o := 0;
WHILE run DO
// read current memory
rc := memioReadX(index:=first, mem:=ADDR(cur), len:=(last - first + 1));
IF NOT (rc = 0) THEN
IF NOT (rc = rc_o) THEN
CASE rc OF
1 : DebugMsg(message := err + "'Invalid parameters'");
2 : DebugMsg(message := err + "'Index range was out of bounds'");
END_CASE;
rc_o := rc;
END_IF;
Sleep(delay := 1000);
ELSE
FOR i := first TO last DO
IF NOT ( cur[i] = old[i] ) THEN
DebugFmt(message := msg + dintToStr(v := cur[i]),
v1 := i, v4 := old[i]);
old[i] := cur[i];
END_IF;
END_FOR;
END_IF;
END_WHILE;
DebugMsg(message := "RegisterMonitor - Ended");
END_THREAD_BLOCK;
//-----------------------------------------------------------------------------
// PROGRAM: SimpleSlave
// Monitor switches and LED's
//-----------------------------------------------------------------------------
PROGRAM SimpleSlave;
VAR
regMon : RegisterMonitor;
regMonSW : RF_TRIG;
i : INT;
clk : DINT;
sn : DINT;
END_VAR;
DebugFmt(message := "Unit \4 ready", v4 := boardSerialNumber());
memioWrite(index:=1, value:=boardSerialNumber());
DebugFmt(message := "Serial number stored in register 0x1000h + 0x1001h");
// get initial message
regMonSW(Trig := NOT SW[1]);
LED[1] := ON;
BEGIN
regMonSW(Trig := SW[1]);
// Start / stop monitor thread
IF regMonSW.rq THEN
regMon.run := TRUE;
DebugMsg(message := "Turn off switch 1 to stop register monitoring.");
ELSIF regMonSW.fq THEN
regMon.run := FALSE;
DebugMsg(message := "Turn on switch 1 to start register monitoring.");
END_IF;
// Start thread if stopped and should be running
IF regMon.run AND NOT regMon._running THEN
regMon();
END_IF;
LED[2] := NOT regMon.run;
END;
END_PROGRAM;
|