modbus: include timer

This commit is contained in:
Vasily Davydov 2022-10-27 13:14:37 +03:00
parent a3332c562f
commit 2bef3ce8c0

View File

@ -1,6 +1,7 @@
/** /**
@file @file
Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol). Arduino library for communicating with Modbus slaves over RS232/485 (via RTU
protocol).
@defgroup setup ModbusMaster Object Instantiation/Initialization @defgroup setup ModbusMaster Object Instantiation/Initialization
@defgroup buffer ModbusMaster Buffer Management @defgroup buffer ModbusMaster Buffer Management
@ -33,10 +34,10 @@ Arduino library for communicating with Modbus slaves over RS232/485 (via RTU pro
*/ */
#ifndef ModbusMaster_h #ifndef ModbusMaster_h
#define ModbusMaster_h #define ModbusMaster_h
#include "Timer.h"
/** /**
@def __MODBUSMASTER_DEBUG__ (1). @def __MODBUSMASTER_DEBUG__ (1).
@ -46,24 +47,24 @@ Set to 1 to enable debugging features within class:
*/ */
#define __MODBUSMASTER_DEBUG__ (0) #define __MODBUSMASTER_DEBUG__ (0)
/* _____STANDARD INCLUDES____________________________________________________
/* _____STANDARD INCLUDES____________________________________________________ */ */
// include types & constants of Wiring core API // include types & constants of Wiring core API
#if defined(ARDUINO) && ARDUINO >= 100 #if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h" #include "Arduino.h"
#else #else
//#include "WProgram.h" //#include "WProgram.h"
#include <stdint.h>
#include <cstddef> #include <cstddef>
#include <stdint.h>
#endif #endif
uint32_t millis();
#define BYTE 0xA5 #define BYTE 0xA5
/* _____UTILITY MACROS_______________________________________________________ */ /* _____UTILITY MACROS_______________________________________________________
*/
/* _____PROJECT INCLUDES_____________________________________________________
/* _____PROJECT INCLUDES_____________________________________________________ */ */
// functions to calculate Modbus Application Data Unit CRC // functions to calculate Modbus Application Data Unit CRC
//#include "util/crc16.h" //#include "util/crc16.h"
// moved inlcuding crc16.h to ModbusMaster.cpp // moved inlcuding crc16.h to ModbusMaster.cpp
@ -72,207 +73,223 @@ uint32_t millis();
///#include "util/word.h" ///#include "util/word.h"
#include "word.h" #include "word.h"
#include "SerialPort.h" #include "SerialPort.h"
/* _____CLASS DEFINITIONS____________________________________________________ */ /* _____CLASS DEFINITIONS____________________________________________________
*/
/** /**
Arduino class library for communicating with Modbus slaves over Arduino class library for communicating with Modbus slaves over
RS232/485 (via RTU protocol). RS232/485 (via RTU protocol).
*/ */
class ModbusMaster class ModbusMaster
{ {
public: public:
ModbusMaster(); ModbusMaster ();
ModbusMaster(uint8_t); ModbusMaster (uint8_t);
ModbusMaster(uint8_t, uint8_t); ModbusMaster (uint8_t, uint8_t);
void begin(); void begin ();
void begin(uint16_t); void begin (uint16_t);
void idle(void (*)()); void idle (void (*) ());
// Modbus exception codes // Modbus exception codes
/** /**
Modbus protocol illegal function exception. Modbus protocol illegal function exception.
The function code received in the query is not an allowable action for The function code received in the query is not an allowable action for
the server (or slave). This may be because the function code is only the server (or slave). This may be because the function code is only
applicable to newer devices, and was not implemented in the unit applicable to newer devices, and was not implemented in the unit
selected. It could also indicate that the server (or slave) is in the selected. It could also indicate that the server (or slave) is in the
wrong state to process a request of this type, for example because it is wrong state to process a request of this type, for example because it is
unconfigured and is being asked to return register values. unconfigured and is being asked to return register values.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBIllegalFunction = 0x01; static const uint8_t ku8MBIllegalFunction = 0x01;
/** /**
Modbus protocol illegal data address exception. Modbus protocol illegal data address exception.
The data address received in the query is not an allowable address for The data address received in the query is not an allowable address for
the server (or slave). More specifically, the combination of reference the server (or slave). More specifically, the combination of reference
number and transfer length is invalid. For a controller with 100 number and transfer length is invalid. For a controller with 100
registers, the ADU addresses the first register as 0, and the last one registers, the ADU addresses the first register as 0, and the last one
as 99. If a request is submitted with a starting register address of 96 as 99. If a request is submitted with a starting register address of 96
and a quantity of registers of 4, then this request will successfully and a quantity of registers of 4, then this request will successfully
operate (address-wise at least) on registers 96, 97, 98, 99. If a operate (address-wise at least) on registers 96, 97, 98, 99. If a
request is submitted with a starting register address of 96 and a request is submitted with a starting register address of 96 and a
quantity of registers of 5, then this request will fail with Exception quantity of registers of 5, then this request will fail with Exception
Code 0x02 "Illegal Data Address" since it attempts to operate on Code 0x02 "Illegal Data Address" since it attempts to operate on
registers 96, 97, 98, 99 and 100, and there is no register with address registers 96, 97, 98, 99 and 100, and there is no register with address
100. 100.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBIllegalDataAddress = 0x02; static const uint8_t ku8MBIllegalDataAddress = 0x02;
/** /**
Modbus protocol illegal data value exception. Modbus protocol illegal data value exception.
A value contained in the query data field is not an allowable value for A value contained in the query data field is not an allowable value for
server (or slave). This indicates a fault in the structure of the server (or slave). This indicates a fault in the structure of the
remainder of a complex request, such as that the implied length is remainder of a complex request, such as that the implied length is
incorrect. It specifically does NOT mean that a data item submitted for incorrect. It specifically does NOT mean that a data item submitted for
storage in a register has a value outside the expectation of the storage in a register has a value outside the expectation of the
application program, since the MODBUS protocol is unaware of the application program, since the MODBUS protocol is unaware of the
significance of any particular value of any particular register. significance of any particular value of any particular register.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBIllegalDataValue = 0x03; static const uint8_t ku8MBIllegalDataValue = 0x03;
/** /**
Modbus protocol slave device failure exception. Modbus protocol slave device failure exception.
An unrecoverable error occurred while the server (or slave) was An unrecoverable error occurred while the server (or slave) was
attempting to perform the requested action. attempting to perform the requested action.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBSlaveDeviceFailure = 0x04; static const uint8_t ku8MBSlaveDeviceFailure = 0x04;
// Class-defined success/exception codes // Class-defined success/exception codes
/** /**
ModbusMaster success. ModbusMaster success.
Modbus transaction was successful; the following checks were valid: Modbus transaction was successful; the following checks were valid:
- slave ID - slave ID
- function code - function code
- response code - response code
- data - data
- CRC - CRC
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBSuccess = 0x00; static const uint8_t ku8MBSuccess = 0x00;
/** /**
ModbusMaster invalid response slave ID exception. ModbusMaster invalid response slave ID exception.
The slave ID in the response does not match that of the request. The slave ID in the response does not match that of the request.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBInvalidSlaveID = 0xE0; static const uint8_t ku8MBInvalidSlaveID = 0xE0;
/** /**
ModbusMaster invalid response function exception. ModbusMaster invalid response function exception.
The function code in the response does not match that of the request. The function code in the response does not match that of the request.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBInvalidFunction = 0xE1; static const uint8_t ku8MBInvalidFunction = 0xE1;
/** /**
ModbusMaster response timed out exception. ModbusMaster response timed out exception.
The entire response was not received within the timeout period, The entire response was not received within the timeout period,
ModbusMaster::ku8MBResponseTimeout. ModbusMaster::ku8MBResponseTimeout.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBResponseTimedOut = 0xE2; static const uint8_t ku8MBResponseTimedOut = 0xE2;
/** /**
ModbusMaster invalid response CRC exception. ModbusMaster invalid response CRC exception.
The CRC in the response does not match the one calculated. The CRC in the response does not match the one calculated.
@ingroup constant @ingroup constant
*/ */
static const uint8_t ku8MBInvalidCRC = 0xE3; static const uint8_t ku8MBInvalidCRC = 0xE3;
uint16_t getResponseBuffer(uint8_t); uint16_t getResponseBuffer (uint8_t);
void clearResponseBuffer(); void clearResponseBuffer ();
uint8_t setTransmitBuffer(uint8_t, uint16_t); uint8_t setTransmitBuffer (uint8_t, uint16_t);
void clearTransmitBuffer(); void clearTransmitBuffer ();
void beginTransmission(uint16_t); void beginTransmission (uint16_t);
uint8_t requestFrom(uint16_t, uint16_t); uint8_t requestFrom (uint16_t, uint16_t);
void sendBit(bool); void sendBit (bool);
void send(uint8_t); void send (uint8_t);
void send(uint16_t); void send (uint16_t);
void send(uint32_t); void send (uint32_t);
uint8_t available(void); uint8_t available (void);
uint16_t receive(void); uint16_t receive (void);
uint8_t readCoils (uint16_t, uint16_t);
uint8_t readDiscreteInputs (uint16_t, uint16_t);
uint8_t readHoldingRegisters (uint16_t, uint16_t);
uint8_t readInputRegisters (uint16_t, uint8_t);
uint8_t writeSingleCoil (uint16_t, uint8_t);
uint8_t writeSingleRegister (uint16_t, uint16_t);
uint8_t writeMultipleCoils (uint16_t, uint16_t);
uint8_t writeMultipleCoils ();
uint8_t writeMultipleRegisters (uint16_t, uint16_t);
uint8_t writeMultipleRegisters ();
uint8_t maskWriteRegister (uint16_t, uint16_t, uint16_t);
uint8_t readWriteMultipleRegisters (uint16_t, uint16_t, uint16_t, uint16_t);
uint8_t readWriteMultipleRegisters (uint16_t, uint16_t);
uint8_t readCoils(uint16_t, uint16_t); private:
uint8_t readDiscreteInputs(uint16_t, uint16_t); uint8_t _u8SerialPort; ///< serial port (0..3) initialized in constructor
uint8_t readHoldingRegisters(uint16_t, uint16_t); uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in constructor
uint8_t readInputRegisters(uint16_t, uint8_t); uint16_t _u16BaudRate; ///< baud rate (300..115200) initialized in begin()
uint8_t writeSingleCoil(uint16_t, uint8_t); static const uint8_t ku8MaxBufferSize
uint8_t writeSingleRegister(uint16_t, uint16_t); = 64; ///< size of response/transmit buffers
uint8_t writeMultipleCoils(uint16_t, uint16_t); uint16_t _u16ReadAddress; ///< slave register from which to read
uint8_t writeMultipleCoils(); uint16_t _u16ReadQty; ///< quantity of words to read
uint8_t writeMultipleRegisters(uint16_t, uint16_t); uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus
uint8_t writeMultipleRegisters(); ///< slave response; read via
uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t); ///< GetResponseBuffer()
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t); uint16_t _u16WriteAddress; ///< slave register to which to write
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t); uint16_t _u16WriteQty; ///< quantity of words to write
uint16_t
_u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to
///< transmit to Modbus slave; set
///< via SetTransmitBuffer()
uint16_t *txBuffer; // from Wire.h -- need to clean this up Rx
uint8_t _u8TransmitBufferIndex;
uint16_t u16TransmitBufferLength;
uint16_t *rxBuffer; // from Wire.h -- need to clean this up Rx
uint8_t _u8ResponseBufferIndex;
uint8_t _u8ResponseBufferLength;
private: // Modbus function codes for bit access
uint8_t _u8SerialPort; ///< serial port (0..3) initialized in constructor static const uint8_t ku8MBReadCoils
uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in constructor = 0x01; ///< Modbus function 0x01 Read Coils
uint16_t _u16BaudRate; ///< baud rate (300..115200) initialized in begin() static const uint8_t ku8MBReadDiscreteInputs
static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers = 0x02; ///< Modbus function 0x02 Read Discrete Inputs
uint16_t _u16ReadAddress; ///< slave register from which to read static const uint8_t ku8MBWriteSingleCoil
uint16_t _u16ReadQty; ///< quantity of words to read = 0x05; ///< Modbus function 0x05 Write Single Coil
uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() static const uint8_t ku8MBWriteMultipleCoils
uint16_t _u16WriteAddress; ///< slave register to which to write = 0x0F; ///< Modbus function 0x0F Write Multiple Coils
uint16_t _u16WriteQty; ///< quantity of words to write
uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx
uint8_t _u8TransmitBufferIndex;
uint16_t u16TransmitBufferLength;
uint16_t* rxBuffer; // from Wire.h -- need to clean this up Rx
uint8_t _u8ResponseBufferIndex;
uint8_t _u8ResponseBufferLength;
// Modbus function codes for bit access // Modbus function codes for 16 bit access
static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils static const uint8_t ku8MBReadHoldingRegisters
static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs = 0x03; ///< Modbus function 0x03 Read Holding Registers
static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil static const uint8_t ku8MBReadInputRegisters
static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils = 0x04; ///< Modbus function 0x04 Read Input Registers
static const uint8_t ku8MBWriteSingleRegister
= 0x06; ///< Modbus function 0x06 Write Single Register
static const uint8_t ku8MBWriteMultipleRegisters
= 0x10; ///< Modbus function 0x10 Write Multiple Registers
static const uint8_t ku8MBMaskWriteRegister
= 0x16; ///< Modbus function 0x16 Mask Write Register
static const uint8_t ku8MBReadWriteMultipleRegisters
= 0x17; ///< Modbus function 0x17 Read Write Multiple Registers
// Modbus function codes for 16 bit access // Modbus timeout [milliseconds]
static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers static const uint16_t ku16MBResponseTimeout
static const uint8_t ku8MBReadInputRegisters = 0x04; ///< Modbus function 0x04 Read Input Registers = 2000; ///< Modbus timeout [milliseconds]
static const uint8_t ku8MBWriteSingleRegister = 0x06; ///< Modbus function 0x06 Write Single Register
static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers
static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register
static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers
// Modbus timeout [milliseconds] // master function that conducts Modbus transactions
static const uint16_t ku16MBResponseTimeout = 2000; ///< Modbus timeout [milliseconds] uint8_t ModbusMasterTransaction (uint8_t u8MBFunction);
// master function that conducts Modbus transactions // idle callback function; gets called during idle time between TX and RX
uint8_t ModbusMasterTransaction(uint8_t u8MBFunction); void (*_idle) ();
SerialPort *MBSerial = NULL; // added by KRL
// idle callback function; gets called during idle time between TX and RX
void (*_idle)();
SerialPort *MBSerial = NULL; // added by KRL
}; };
#endif #endif