MODBUS
ModBus App Notes
Modbus protocol for CRC calculation and response events -v49.03.
Added MODBUS protocol to handle CRC calculation and response events.
Modbus RTU is available on RS2, RS4, AS1, AS2 - v49.32.
More than one of these can be active at the same time if required.
Setup example:
SETUP(RS2)
{
baud = 19200;
parity = N;
rxi = Y;
txi = Y;
proto = ModbusRTU; //define modbus as the protocol to use
}
All low level handling of Modbus requests and responses are handled by the TFT firmware and the 'interface' to the itronSMART code is via system variables (xxx refers to the interface name: RS2, RS4, AS1 or AS2):
Name Type Use
MB_xxx_MODE U8 Modbus mode (0=master, 1=slave)
MB_xxx_REGS PTR Pointer to a U16 array to hold read / write registers
MB_xxx_COILS PTR Pointer to a U8 array to hold read / write coil bit values
MB_xxx_SLAVEID U8 Slave address
MB_xxx_FUNC U8 Modbus function code (1/3/15/16)
MB_xxx_REGOFF U16 Offset into U16 register array for read / write action
MB_xxx_REGCNT U16 Number of registers to read / write (or have been read / written)
MB_xxx_COILOFF U16 Offset into U16 coil register array for read / write action
MB_xxx_COILCNT U16 Number of coil registers to read / write (or have been read / written)
MB_xxx_STATUS U8 Modbus status (0=idle, 1=tx, 1=rx, 2+ error)
MB_xxx_TIMEOUT U16 Response timeout in milliseconds
MB_xxx_DATAOK PTR Pointer to function that is called after a successful transaction
MB_xxx_DATAERR PTR Pointer to function that is called after an error has occurred
COIL data is converted from bits to bytes to make itronSMART access easier. For example a Modbus request to read 12 coils (2 Modbus data bytes) with offset of 6 will result in bytes 6 – 17 in the U8 coil registers being used.
Master |
Slave |
// New modbus test
lib(fnt, "SDHC/asc_32.fnt");
style(ps, page){back = black;}
style(ts, text){font = fnt; col = white; currel = TL;}
style(ts_cc, text){font = fnt; col = white; currel = CC;}
setup(RS2)
{
baud = 19200;
parity = N;
encode = sd;
txi = Y;
rxi = Y;
proto = ModbusRTU;
}
var(regs, 0, U16, 128);
load(MB_RS2_MODE, 0);
load(MB_RS2_REGS > "regs");
load(MB_RS2_SLAVEID, 1);
load(MB_RS2_TIMEOUT, 1000);
var(v1, 10, U16);
var(v2, 30, U16);
var(v3, 80, U16);
var(v4, 0, U16);
var(v5, 0, U16);
var(v6, 0, U16);
int(tim0, TIMER0, clear_status);
page(p, ps)
{
posn(100, 40); text(t1, "WR", ts);
posn(+0, +35); text(t2, "0", ts);
posn(+0, +30); text(t3, "1", ts);
posn(+0, +30); text(t4, "2", ts);
posn(130, 75); text(t5, v1, ts);
posn(+0, +30); text(t6, v2, ts);
posn(+0, +30); text(t7, v3, ts);
posn(340, 40); text(t8, "RD", ts);
posn(+0, +35); text(t9, "0", ts);
posn(+0, +30); text(t10, "1", ts);
posn(+0, +30); text(t11, "2", ts);
posn(370, 75); text(t12, "", ts);
posn(+0, +30); text(t13, "", ts);
posn(+0, +30); text(t14, "", ts);
posn(120, 136); key(k1, write, 240, 272, TOUCH);
posn(360, 136); key(k2, read, 240, 272, TOUCH);
posn(240, 256); text(status, "", ts_cc);
posn(460, 256); text(status_error, "", ts_cc);
}
func(read)
{
load(MB_RS2_FUNC, 3);
load(MB_RS2_REGOFF, 0);
load(MB_RS2_REGCNT, 3);
load(MB_RS2_DATAOK > "read_ok");
load(MB_RS2_DATAERR > "read_error");
load(RS2, 1);
}
func(read_ok)
{
load(v4, regs.0); text(t12, v4);
load(v5, regs.1); text(t13, v5);
load(v6, regs.2); text(t14, v6);;
text(status, "READ OK");;
load(TIMER0, 1500, 1);
}
func(read_error)
{
text(status, "READ ERROR");
text(status_error, MB_RS2_STATUS);;
load(TIMER0, 1500, 1);
}
func(write)
{
load(MB_RS2_FUNC, 16);
load(MB_RS2_REGOFF, 0);
load(MB_RS2_REGCNT, 3);
load(regs.0, v1);
load(regs.1, v2);
load(regs.2, v3);
load(MB_RS2_DATAOK > "write_ok");
load(MB_RS2_DATAERR > "write_error");
load(RS2, 1);
}
func(write_ok)
{
text(status, "WRITE OK");;
load(TIMER0, 1500, 1);
}
func(write_error)
{
text(status, "WRITE ERROR");
text(status_error, MB_RS2_STATUS);;
load(TIMER0, 1500, 1);
}
func(clear_status)
{
text(status, "");;
text(status_error, "");;
}
show(p); |
// New modbus test - slave
lib(fnt, "SDHC/asc_32.fnt");
style(ps, page){back = black; }
style(ts, text){font = fnt; col = white; currel = TL;}
setup(RS2)
{
baud = 19200;
parity = N;
encode = sd;
txi = Y;
rxi = Y;
proto = ModbusRTU;
}
var(regs, 0, U16, 128);
load(MB_RS2_MODE, 1);
load(MB_RS2_REGS > "regs");
load(MB_RS2_SLAVEID, 1);
load(MB_RS2_DATAOK > "ok");
load(MB_RS2_DATAERR > "error");
load(regs.0, 10);
load(regs.1, 9102);
load(regs.2, 234);
int(tim0, TIMER0, clear_status);
page(p, ps)
{
posn(240, 50); text(t1, regs.0, ts);
posn(240, 90); text(t2, regs.1, ts);
posn(240, 130); text(t3, regs.2, ts);
posn(240, 256); text(status, "", ts);
}
func(ok)
{
if(MB_RS2_FUNC==16?[text(status, "WRITE OK");;run(update_values);]:[text(status,
"READ OK");;]);
load(TIMER0, 1500, 1);
}
func(error)
{
if(MB_RS2_FUNC==16?[text(status, "WRITE ERROR");;]:[text(status, "READ
ERROR");;]);
load(TIMER0, 1500, 1);
}
func(update_values)
{
text(t1, regs.0);
text(t2, regs.1);
text(t3, regs.2);;
}
func(clear_status)
{
text(status, "");;
}
show(p);
|
Master operation
Write regs / coils
Load values into U16 / U8 variable that MB_xxx_REGS/MB_xxx_COILS points to.
Setup MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_xxx_COILOFF and use command LOAD(RS2, 1); to start request.
MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the success response is received from the slave.
Read regs / coils
Setup MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_xxx_COILOFF and use command LOAD(RS2, 1); to start request.
MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the success response is received from the slave.
Values can then be read from variable that MB_xxx_REGS/MB_xxx_COILS points to.
Slave operation
Write regs / coils
MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the successful request from the master.
Values can then be read from variable that MB_xxx_REGS/MB_xxx_COILS points to.
MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_xxx_COILOFF values should be read to know which registers were updated.
Read regs / coils
MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the successful request from the master.
MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_COILOFF values can be read to know which registers were read.
|
Update Information |
Version |
Title |
Date |
Details |
49.58 |
MODBUS |
07 Sep 15 |
|
* Fixed a problem that prevented a new transaction from being initiated from within the 'pass' or 'fail' functions
|
|
49.37 |
Modbus - Additional Functionality |
10 Jun 13 |
|
* Added support for function codes 5/6 (write single coil / register). * Added alternative means of accessing register / coil data using 2 dimensional array. 2 dim mode is automatically selected if MB_xxx_REGS / MB_xxx_COILS points to a 2 dim array. In this case the first dimension specified the address and the second holds the data. The coil array must be U16 in 2 dim mode. 2 dim mode is not fully tested.
|
|
49.34 |
Modbus - Removed debug messages for RS485 Modbus TX and RX. |
23 Feb 13 |
|
Modbus * Removed debug messages for RS485 Modbus TX and RX.
|
|
49.32 |
Modbus RTU - Modbus RTU is available on RS2, RS4, AS1, AS2. |
14 Feb 13 |
|
* Modbus RTU is available on RS2, RS4, AS1, AS2. More than one of these can be active at the same time if required. * Setup example: SETUP(RS2) { baud = 19200; parity = N; rxi = Y; txi = Y; proto = ModbusRTU; } * All low level handling of Modbus requests and responses are handled by the TFT firmware and the 'interface' to the itronSMART code is via system variables (xxx refers to the interface name: RS2, RS4, AS1 or AS2): Name Type Use MB_xxx_MODE U8 Modbus mode (0=master, 1=slave) MB_xxx_REGS PTR Pointer to a U16 array to hold read / write registers MB_xxx_COILS PTR Pointer to a U8 array to hold read / write coil bit values MB_xxx_SLAVEID U8 Slave address MB_xxx_FUNC U8 Modbus function code (1/3/15/16) MB_xxx_REGOFF U16 Offset into U16 register array for read / write action MB_xxx_REGCNT U16 Number of registers to read / write (or have been read / written) MB_xxx_COILOFF U16 Offset into U16 coil register array for read / write action MB_xxx_COILCNT U16 Number of coil registers to read / write (or have been read / written) MB_xxx_STATUS U8 Modbus status (0=idle, 1=tx, 1=rx, 2+ error) MB_xxx_TIMEOUT U16 Response timeout in milliseconds MB_xxx_DATAOK PTR Pointer to function that is called after a successful transaction MB_xxx_DATAERR PTR Pointer to function that is called after an error has occurred * COIL data is converted from bits to bytes to make itronSMART access easier. For example a Modbus request to read 12 coils (2 Modbus data bytes) with offset of 6 will result in bytes 6 – 17 in the U8 coil registers being used. * Master operation Write regs / coils Load values into U16 / U8 variable that MB_xxx_REGS/MB_xxx_COILS points to. Setup MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_xxx_COILOFF and use command LOAD(RS2, 1); to start request. MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the success response is received from the slave. Read regs / coils Setup MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_xxx_COILOFF and use command LOAD(RS2, 1); to start request. MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the success response is received from the slave. Values can then be read from variable that MB_xxx_REGS/MB_xxx_COILS points to. * Slave operation Write regs / coils MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the successful request from the master. Values can then be read from variable that MB_xxx_REGS/MB_xxx_COILS points to. MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_xxx_COILOFF values should be read to know which registers were updated. Read regs / coils MB_xxx_DATAOK/MB_xxx_DATAERR function will be called after the successful request from the master. MB_xxx_REGCNT/MB_xxx_COILCNT and MB_xxx_REGOFF/MB_COILOFF values can be read to know which registers were read. * Fixed interrupt handling
|
|
49.03 |
MODBUS RTU Master - Added MODBUS protocol to handle CRC calculation and response events. |
01 Jun 12 |
|
Added MODBUS protocol to handle CRC calculation and response events. * The following parameters have been added to the serial port setups :- > proto = Modbus; > func = funcprefix; > timeout = n; * In Modbus mode the LOAD(port, .....) is handled differently, parameters function as follows :- > LOAD(portname, address, function, register, variable); - portname = RS2, RS4, etc - address = Modbus slave address - function (modbus function code) = 3 or 16 (3=read from slave, 16=write to slave) - register = register location in slave to read / write - variable = data to write (or destination variable for data that is read) (only U32 or FLT supported) * For read actions a function will be called, the name of which depends on the func prefix and the address, function and register values. * Example (assuming func prefix of 'mod' :- > LOAD(RS4, 3, 3, 10, u23var); // read u32 value from register 10, slave address 3 and store in u32var On success :- FUNC(mod_3_3_10) { // do something with u32var... } On failure or timeout :- FUNC(mod_3_3_10_ERR) { // an error has occurred trying to read... }
|
|
49.00 |
CRC-16 Support - Support for additional CRC-16 algorithms has been implemented. |
22 Mar 12 |
|
Support for additional CRC-16 algorithms has been implemented. * CALC( dst16, srcBuf, "type", "CRC16" ); > Note CALC( dst32, srcBuf, "", "CRC16" ); will use the MODBUS ("modbus") algorithm
|
|
|
|