Arduino:
Code:
/**
* Modbus slave example 1:
* The purpose of this example is to link a data array
* from the Arduino to an external device.
*
* Recommended Modbus Master: QModbus
* http://qmodbus.sourceforge.net/
*/
#include <ModbusRtu.h>
// data array for modbus network sharing
uint16_t au16data[16] = {
3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };
/**
* Modbus object declaration
* u8id : node id = 0 for master, = 1..247 for slave
* u8serno : serial port (use 0 for Serial)
* u8txenpin : 0 for RS-232 and USB-FTDI
* or any pin number > 1 for RS-485
*/
Modbus slave(1,0,0); // this is slave @1 and RS-232 or USB-FTDI
typedef union
{
struct
{
uint16_t hi;
uint16_t lo;
} regs;
float value;
} Data;
Data data;
void setup()
{
slave.begin( 19200 ); // baud-rate at 19200
data.value = 1.0f;
au16data[0] = data.regs.hi;
au16data[1] = data.regs.lo;
}
void loop() {
slave.poll( au16data, 16 );
}
Codesys 3.5.12.20:
Code:
program PLC_PRG
var constant
READ_COILS : byte := 16#01;
READ_DISCRETE_INPUTS : byte := 16#02;
READ_HOLDING_REGISTERS : byte := 16#03;
READ_INPUT_REGISTERS : byte := 16#04;
WRITE_SINGLE_COIL : byte := 16#05;
WRITE_SINGLE_REGISTER : byte := 16#06;
WRITE_MULTIPLE_COILS : byte := 16#0F;
WRITE_MULTIPLE_REGISTERS : byte := 16#10;
MODE_IDLE: byte := 0;
MODE_CONNECT: byte := 1;
MODE_SET_DATA: byte := 2;
MODE_REQUEST: byte := 3;
MODE_CLOSE: byte := 4;
MODE_ERROR: byte := 5;
// Номера портов для устройств /dev/ttyUSBn Raspberry Pi 3.
TTYS0: byte := 1;
TTYS1: byte := 2;
TTYS2: byte := 3;
TTYS3: byte := 4;
TTYS4: byte := 5;
end_var
var
xBusy, xDone, xError: bool;
ex: byte;
mode: uint := MODE_CONNECT;
dw: dword;
start, stop, t: ulint;
sleepus: ulint := 100;
rvalue: real;
timeout: time;
tmpbuf: array [ 0 .. 255 ] of byte;
result: RTS_IEC_RESULT;
hCom: RTS_IEC_RESULT;
t1: ton;
pFloatValue: pointer to real;
ComSettings: COM_Settings := ( sPort := TTYS0, ulBaudrate := SYS_BR_19200, byParity := SYS_NOPARITY, byStopBits := SYS_ONESTOPBIT, ulBufferSize := 255 );
ReadHoldRegs: ModbusRequest := ( uiFunctionCode := READ_HOLDING_REGISTERS );
end_var
// Перед использованием необходимо:
// - обновить устройство;
// - обновить библиотеки;
// - настроить параметры последовательного порта;
case mode of
MODE_CONNECT:
// Настройка параметров соединения.
// Таймаут ожидания ответа.
timeout := t#50ms;
// Открываем порт.
hCom := SysComOpen( ComSettings.sPort, adr( result ) );
// Устанавливаем параметры порта.
result := SysComSetSettings( hCom, adr( ComSettings ), 0 );
t1( in := false );
mode := sel( result = Errors.ERR_OK, MODE_ERROR, MODE_REQUEST );
MODE_REQUEST:
SysTimeRtcHighResGet( start );
repeat
// Выполняем запрос.
ReadHoldRegs( xExecute := true, usiSlaveAddr := 1, uiReadOffset := 0, uiReadLen := 2,
hComPort := hCom, tTimeout := timeout, pReadBuf := adr( tmpbuf ),
xBusy => xBusy, xDone => xDone, xError => xError, byModbusErrorCode => ex );
SchedWaitSleep( sleepus );
until xDone or xError end_repeat
SysTimeRtcHighResGet( stop );
// Фактическое время выполнения запроса, [мсек].
t := stop - start;
if xDone then
pFloatValue := adr( tmpbuf[0] );
rvalue := pFloatValue^;
end_if
// Ошибка.
if xError then
case ex of
MB_ErrorCodes.RESPONSE_SUCCESS: ;
MB_ErrorCodes.RESPONSE_TIMEOUT: ;
MB_ErrorCodes.RESPONSE_INVALID_DATA: ;
MB_ErrorCodes.REQUEST_FAILED_TO_SEND: SysComClose( hCom ) ;
end_case
end_if
t1( in := false );
mode := sel( ex = MB_ErrorCodes.REQUEST_FAILED_TO_SEND, MODE_IDLE, MODE_ERROR );
// Интервал между запросами.
MODE_IDLE:
t1( in := true, pt := t#1s );
if t1.q then
ReadHoldRegs( xExecute := false );
mode := MODE_REQUEST;
end_if
// Ошибка.
MODE_ERROR:
t1( in := true, pt := t#1s );
if t1.q then mode := MODE_CONNECT; end_if
end_case