Skip to content

Commit

Permalink
Fix #17 Pass Stream object to ModbusMaster
Browse files Browse the repository at this point in the history
- BREAK: This is a breaking change to the interface. ModbusMaster now takes a
  serial object which has been initialized with the appropriate baud rate.
  Any Stream object may be used, including SoftwareSerial.
- As a byproduct of these changes, the library should now be able to be used
  on other architectures besides AVR and SAM.
  • Loading branch information
4-20ma committed May 24, 2015
1 parent 799a8ef commit 9e611e3
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 121 deletions.
107 changes: 13 additions & 94 deletions ModbusMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,120 +33,39 @@ Arduino library for communicating with Modbus slaves over RS232/485 (via RTU pro


/* _____GLOBAL VARIABLES_____________________________________________________ */
#if defined(ARDUINO_ARCH_AVR)
HardwareSerial* MBSerial = &Serial; ///< Pointer to Serial class object
#elif defined(ARDUINO_ARCH_SAM)
UARTClass* MBSerial = &Serial; ///< Pointer to Serial class object
#else
#error "This library only supports boards with an AVR or SAM processor. Please open an issue at https://github.com/4-20ma/ModbusMaster/issues and indicate which processor/platform you're using."
#endif


/* _____PUBLIC FUNCTIONS_____________________________________________________ */
/**
Constructor.
Creates class object using default serial port 0, Modbus slave ID 1.
Creates class object; initialize it using ModbusMaster::begin().
@ingroup setup
*/
ModbusMaster::ModbusMaster(void)
{
_u8SerialPort = 0;
_u8MBSlave = 1;
}


/**
Constructor.
Creates class object using default serial port 0, specified Modbus slave ID.
@overload void ModbusMaster::ModbusMaster(uint8_t u8MBSlave)
@param u8MBSlave Modbus slave ID (1..255)
@ingroup setup
*/
ModbusMaster::ModbusMaster(uint8_t u8MBSlave)
{
_u8SerialPort = 0;
_u8MBSlave = u8MBSlave;
}


/**
Constructor.
Creates class object using specified serial port, Modbus slave ID.
@overload void ModbusMaster::ModbusMaster(uint8_t u8SerialPort, uint8_t u8MBSlave)
@param u8SerialPort serial port (Serial, Serial1..Serial3)
@param u8MBSlave Modbus slave ID (1..255)
@ingroup setup
*/
ModbusMaster::ModbusMaster(uint8_t u8SerialPort, uint8_t u8MBSlave)
{
_u8SerialPort = (u8SerialPort > 3) ? 0 : u8SerialPort;
_u8MBSlave = u8MBSlave;
}


/**
Initialize class object.
Sets up the serial port using default 19200 baud rate.
Call once class has been instantiated, typically within setup().
@ingroup setup
*/
void ModbusMaster::begin(void)
{
begin(19200);
}


/**
Initialize class object.
Sets up the serial port using specified baud rate.
Assigns the Modbus slave ID and serial port.
Call once class has been instantiated, typically within setup().
@overload ModbusMaster::begin(uint16_t u16BaudRate)
@param u16BaudRate baud rate, in standard increments (300..115200)
@param slave Modbus slave ID (1..255)
@param &serial reference to serial port object (Serial, Serial1, ... Serial3)
@ingroup setup
*/
void ModbusMaster::begin(uint16_t u16BaudRate)
void ModbusMaster::begin(uint8_t slave, Stream &serial)
{
// txBuffer = (uint16_t*) calloc(ku8MaxBufferSize, sizeof(uint16_t));
_u8MBSlave = slave;
_serial = &serial;
_u8TransmitBufferIndex = 0;
u16TransmitBufferLength = 0;

switch(_u8SerialPort)
{
#if defined(UBRR1H)
case 1:
MBSerial = &Serial1;
break;
#endif

#if defined(UBRR2H)
case 2:
MBSerial = &Serial2;
break;
#endif

#if defined(UBRR3H)
case 3:
MBSerial = &Serial3;
break;
#endif

case 0:
default:
MBSerial = &Serial;
break;
}

MBSerial->begin(u16BaudRate);
#if __MODBUSMASTER_DEBUG__
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
Expand Down Expand Up @@ -750,31 +669,31 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
u8ModbusADU[u8ModbusADUSize] = 0;

// flush receive buffer before transmitting request
while (MBSerial->read() != -1);
while (_serial->read() != -1);

// transmit request
for (i = 0; i < u8ModbusADUSize; i++)
{
#if defined(ARDUINO) && ARDUINO >= 100
MBSerial->write(u8ModbusADU[i]);
_serial->write(u8ModbusADU[i]);
#else
MBSerial->print(u8ModbusADU[i], BYTE);
_serial->print(u8ModbusADU[i], BYTE);
#endif
}

u8ModbusADUSize = 0;
MBSerial->flush(); // flush transmit buffer
_serial->flush(); // flush transmit buffer

// loop until we run out of time or bytes, or an error occurs
u32StartTime = millis();
while (u8BytesLeft && !u8MBStatus)
{
if (MBSerial->available())
if (_serial->available())
{
#if __MODBUSMASTER_DEBUG__
digitalWrite(4, true);
#endif
u8ModbusADU[u8ModbusADUSize++] = MBSerial->read();
u8ModbusADU[u8ModbusADUSize++] = _serial->read();
u8BytesLeft--;
#if __MODBUSMASTER_DEBUG__
digitalWrite(4, false);
Expand Down
10 changes: 3 additions & 7 deletions ModbusMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,8 @@ class ModbusMaster
{
public:
ModbusMaster();
ModbusMaster(uint8_t);
ModbusMaster(uint8_t, uint8_t);

void begin();
void begin(uint16_t);
void begin(uint8_t, Stream &serial);
void idle(void (*)());

// Modbus exception codes
Expand Down Expand Up @@ -224,9 +221,8 @@ class ModbusMaster
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()
Stream* _serial; ///< reference to serial port object
uint8_t _u8MBSlave; ///< Modbus slave (1..255) 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
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,24 @@ The library contains a few sketches that demonstrate use of the ModbusMaster lib
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>
Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net>
*/

#include <ModbusMaster.h>


// instantiate ModbusMaster object as slave ID 2
// defaults to serial port 0 since no port was specified
ModbusMaster node(2);
// instantiate ModbusMaster object
ModbusMaster node;


void setup()
{
// initialize Modbus communication baud rate
node.begin(19200);
// use Serial (port 0); initialize Modbus communication baud rate
Serial.begin(19200);

// communicate with Modbus slave ID 2 over Serial (port 0)
node.begin(2, Serial);
}


Expand Down
15 changes: 8 additions & 7 deletions examples/Basic/Basic.pde
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,24 @@
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>
Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net>
*/

#include <ModbusMaster.h>


// instantiate ModbusMaster object as slave ID 2
// defaults to serial port 0 since no port was specified
ModbusMaster node(2);
// instantiate ModbusMaster object
ModbusMaster node;


void setup()
{
// initialize Modbus communication baud rate
node.begin(19200);
// use Serial (port 0); initialize Modbus communication baud rate
Serial.begin(19200);

// communicate with Modbus slave ID 2 over Serial (port 0)
node.begin(2, Serial);
}


Expand Down Expand Up @@ -66,4 +68,3 @@ void loop()
}
}
}

13 changes: 8 additions & 5 deletions examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
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>
Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net>
*/

Expand All @@ -46,14 +46,17 @@
#define NANO_AI(n) (0x0000 + 2 * n) ///< returns nanoLC analog input address


// instantiate ModbusMaster object, serial port 0, Modbus slave ID 1
ModbusMaster nanoLC(0, 1);
// instantiate ModbusMaster object
ModbusMaster nanoLC;


void setup()
{
// initialize Modbus communication baud rate
nanoLC.begin(19200);
// use Serial (port 0); initialize Modbus communication baud rate
Serial.begin(19200);

// communicate with Modbus slave ID 1 over Serial (port 0)
nanoLC.begin(1, Serial);
}


Expand Down
1 change: 0 additions & 1 deletion keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#######################################

ModbusMaster KEYWORD1
MBSerial KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ sentence=Enlighten your Arduino to be a Modbus master.
paragraph=Enables communication with Modbus slaves over RS232/485 (via RTU protocol). Requires an RS232/485 transceiver.
category=Communication
url=https://github.com/4-20ma/ModbusMaster
architectures=avr,sam
architectures=*

0 comments on commit 9e611e3

Please sign in to comment.