diff --git a/Modbus/.project b/Modbus/.project new file mode 100644 index 0000000..c7d3ce5 --- /dev/null +++ b/Modbus/.project @@ -0,0 +1,29 @@ + + + Modbus + + + lpc_chip_15xx + DigitalIoPin + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/Modbus/inc/ModbusLeader.h b/Modbus/inc/ModbusLeader.h new file mode 100644 index 0000000..d038569 --- /dev/null +++ b/Modbus/inc/ModbusLeader.h @@ -0,0 +1,281 @@ +/** +@file +Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol). + +@defgroup setup ModbusMaster Object Instantiation/Initialization +@defgroup buffer ModbusMaster Buffer Management +@defgroup discrete Modbus Function Codes for Discrete Coils/Inputs +@defgroup register Modbus Function Codes for Holding/Input Registers +@defgroup constant Modbus Function Codes, Exception Codes +*/ +/* + + ModbusMaster.h - Arduino library for communicating with Modbus slaves + over RS232/485 (via RTU protocol). + + This file is part of ModbusMaster. + + ModbusMaster is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ModbusMaster is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ModbusMaster. If not, see . + + Written by Doc Walker (Rx) + Copyright © 2009-2013 Doc Walker <4-20ma at wvfans dot net> + +*/ + + +#ifndef ModbusMaster_h +#define ModbusMaster_h + + +/** +@def __MODBUSMASTER_DEBUG__ (1). +Set to 1 to enable debugging features within class: + - pin 4 cycles for each byte read in the Modbus response + - pin 5 cycles for each millisecond timeout during the Modbus response +*/ +#define __MODBUSMASTER_DEBUG__ (0) + + +/* _____STANDARD INCLUDES____________________________________________________ */ +// include types & constants of Wiring core API +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +//#include "WProgram.h" +#include +#include +#endif +#include + +uint32_t millis(); +#define BYTE 0xA5 + +/* _____UTILITY MACROS_______________________________________________________ */ + + +/* _____PROJECT INCLUDES_____________________________________________________ */ +// functions to calculate Modbus Application Data Unit CRC +//#include "util/crc16.h" +// moved inlcuding crc16.h to ModbusMaster.cpp + +// functions to manipulate words +///#include "util/word.h" +#include "word.h" +#include "SerialPort.h" + +/* _____CLASS DEFINITIONS____________________________________________________ */ +/** +Arduino class library for communicating with Modbus slaves over +RS232/485 (via RTU protocol). +*/ +class ModbusMaster +{ + public: + ModbusMaster(); + ModbusMaster(uint8_t); + ModbusMaster(uint8_t, uint8_t); + + void begin(); + void begin(uint16_t); + void idle(void (*)()); + + // Modbus exception codes + /** + Modbus protocol illegal function exception. + + 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 + applicable to newer devices, and was not implemented in the unit + 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 + unconfigured and is being asked to return register values. + + @ingroup constant + */ + static const uint8_t ku8MBIllegalFunction = 0x01; + + /** + Modbus protocol illegal data address exception. + + The data address received in the query is not an allowable address for + the server (or slave). More specifically, the combination of reference + number and transfer length is invalid. For a controller with 100 + 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 + 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 + request is submitted with a starting register address of 96 and a + quantity of registers of 5, then this request will fail with Exception + 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 + 100. + + @ingroup constant + */ + static const uint8_t ku8MBIllegalDataAddress = 0x02; + + /** + Modbus protocol illegal data value exception. + + 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 + remainder of a complex request, such as that the implied length is + incorrect. It specifically does NOT mean that a data item submitted for + storage in a register has a value outside the expectation of the + application program, since the MODBUS protocol is unaware of the + significance of any particular value of any particular register. + + @ingroup constant + */ + static const uint8_t ku8MBIllegalDataValue = 0x03; + + /** + Modbus protocol slave device failure exception. + + An unrecoverable error occurred while the server (or slave) was + attempting to perform the requested action. + + @ingroup constant + */ + static const uint8_t ku8MBSlaveDeviceFailure = 0x04; + + // Class-defined success/exception codes + /** + ModbusMaster success. + + Modbus transaction was successful; the following checks were valid: + - slave ID + - function code + - response code + - data + - CRC + + @ingroup constant + */ + static const uint8_t ku8MBSuccess = 0x00; + + /** + ModbusMaster invalid response slave ID exception. + + The slave ID in the response does not match that of the request. + + @ingroup constant + */ + static const uint8_t ku8MBInvalidSlaveID = 0xE0; + + /** + ModbusMaster invalid response function exception. + + The function code in the response does not match that of the request. + + @ingroup constant + */ + static const uint8_t ku8MBInvalidFunction = 0xE1; + + /** + ModbusMaster response timed out exception. + + The entire response was not received within the timeout period, + ModbusMaster::ku8MBResponseTimeout. + + @ingroup constant + */ + static const uint8_t ku8MBResponseTimedOut = 0xE2; + + /** + ModbusMaster invalid response CRC exception. + + The CRC in the response does not match the one calculated. + + @ingroup constant + */ + static const uint8_t ku8MBInvalidCRC = 0xE3; + + uint16_t getResponseBuffer(uint8_t); + void clearResponseBuffer(); + uint8_t setTransmitBuffer(uint8_t, uint16_t); + void clearTransmitBuffer(); + + void beginTransmission(uint16_t); + uint8_t requestFrom(uint16_t, uint16_t); + void sendBit(bool); + void send(uint8_t); + void send(uint16_t); + void send(uint32_t); + uint8_t available(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); + + private: + uint8_t _u8SerialPort; ///< serial port (0..3) initialized in constructor + uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in constructor + uint16_t _u16BaudRate; ///< baud rate (300..115200) initialized in begin() + static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers + uint16_t _u16ReadAddress; ///< slave register from which to read + uint16_t _u16ReadQty; ///< quantity of words to read + uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() + uint16_t _u16WriteAddress; ///< slave register to which to write + 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 + static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils + static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs + static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil + static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils + + // Modbus function codes for 16 bit access + static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers + static const uint8_t ku8MBReadInputRegisters = 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 timeout [milliseconds] + static const uint16_t ku16MBResponseTimeout = 2000; ///< Modbus timeout [milliseconds] + + // master function that conducts Modbus transactions + uint8_t ModbusMasterTransaction(uint8_t u8MBFunction); + + // idle callback function; gets called during idle time between TX and RX + void (*_idle)(); + SerialPort *MBSerial = NULL; // added by KRL +}; +#endif + +/** +@example examples/Basic/Basic.pde +@example examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde +*/ \ No newline at end of file diff --git a/Modbus/liblinks.xml b/Modbus/liblinks.xml new file mode 100644 index 0000000..1dc1803 --- /dev/null +++ b/Modbus/liblinks.xml @@ -0,0 +1,32 @@ + + + + + ${MacroStart}workspace_loc:/${ProjName}/inc${MacroEnd} + + + ${MacroStart}workspace_loc:/${ProjName}/inc${MacroEnd} + + + ${ProjName} + + + ${MacroStart}workspace_loc:/${ProjName}/Debug${MacroEnd} + + + ${MacroStart}workspace_loc:/${ProjName}/Release${MacroEnd} + + + ${ProjName} + + + diff --git a/Modbus/src/tester.cpp b/Modbus/src/tester.cpp new file mode 100644 index 0000000..a2935ea --- /dev/null +++ b/Modbus/src/tester.cpp @@ -0,0 +1,45 @@ +#if defined (__USE_LPCOPEN) +#if defined(NO_BOARD_LIB) +#include "chip.h" +#else +#include "board.h" +#endif +#endif + +#include +#include "ModbusMaster.h" +// TODO: insert other include files here + +// TODO: insert other definitions and declarations here + +int main(void) { + +#if defined (__USE_LPCOPEN) + // Read clock settings and update SystemCoreClock variable + SystemCoreClockUpdate(); +#if !defined(NO_BOARD_LIB) + // Set up and initialize all required blocks and + // functions related to the board hardware + Board_Init(); + // Set the LED to the state of "On" + Board_LED_Set(0, true); +#endif +#endif + + // TODO: insert code here + ModbusMaster MIO_12V(1); + ModbusMaster CO2_sensor(240); + ModbusMaster RH_sensor(241); + + + // Force the counter to be placed into memory + volatile static int i = 0 ; + // Enter an infinite loop, just incrementing a counter + while(1) { + i++ ; + // "Dummy" NOP to allow source level single + // stepping of tight while() loop + __asm volatile ("nop"); + } + return 0 ; +}