| 
 
 
 
  
   
 
  
 
 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 
             |  
            
                
                
                
                
             |    					
         
 
   
	 
     
	 | 
 
 
 |