Add modbus leader class & tester
This commit is contained in:
parent
39c3fcd202
commit
1c42148a64
29
Modbus/.project
Normal file
29
Modbus/.project
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>Modbus</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
<project>lpc_chip_15xx</project>
|
||||||
|
<project>DigitalIoPin</project>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||||
|
<triggers>full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
281
Modbus/inc/ModbusLeader.h
Normal file
281
Modbus/inc/ModbusLeader.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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 <stdint.h>
|
||||||
|
#include <cstddef>
|
||||||
|
#endif
|
||||||
|
#include <chip.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
32
Modbus/liblinks.xml
Normal file
32
Modbus/liblinks.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<!-- liblinks.xml
|
||||||
|
|
||||||
|
NXP LPCXpresso IDE "Smart update wizard" script file
|
||||||
|
When executed on a particular application project, will
|
||||||
|
add appropriate links to the specified library project.
|
||||||
|
|
||||||
|
Note that this script assumes that the application project
|
||||||
|
contains the standard 'Debug' and 'Release' build
|
||||||
|
configurations.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project name="" update="true">
|
||||||
|
<setting id="all.compiler.inc">
|
||||||
|
<value>${MacroStart}workspace_loc:/${ProjName}/inc${MacroEnd}</value>
|
||||||
|
</setting>
|
||||||
|
<setting id="assembler.inc">
|
||||||
|
<value>${MacroStart}workspace_loc:/${ProjName}/inc${MacroEnd}</value>
|
||||||
|
</setting>
|
||||||
|
<setting id="linker.libs">
|
||||||
|
<value>${ProjName}</value>
|
||||||
|
</setting>
|
||||||
|
<setting id="linker.paths" buildType="Debug">
|
||||||
|
<value>${MacroStart}workspace_loc:/${ProjName}/Debug${MacroEnd}</value>
|
||||||
|
</setting>
|
||||||
|
<setting id="linker.paths" buildType="Release">
|
||||||
|
<value>${MacroStart}workspace_loc:/${ProjName}/Release${MacroEnd}</value>
|
||||||
|
</setting>
|
||||||
|
<requires msg="Library project `${ProjName}` not found">
|
||||||
|
<value>${ProjName}</value>
|
||||||
|
</requires>
|
||||||
|
</project>
|
||||||
|
|
||||||
45
Modbus/src/tester.cpp
Normal file
45
Modbus/src/tester.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#if defined (__USE_LPCOPEN)
|
||||||
|
#if defined(NO_BOARD_LIB)
|
||||||
|
#include "chip.h"
|
||||||
|
#else
|
||||||
|
#include "board.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cr_section_macros.h>
|
||||||
|
#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 ;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user