I have code as below For arduino UNo . I am trying to implement modbus slave RTU for arduino.Problem i am facing i can upload code. But i am not getting any response from salve Device
I am using Qmodbus software i am getting 2 type error
1) Slave through exception , INVALID crc implemented.
2)I/o error, Didnt receive any data from slave
Code: Select all
#define MAX_BUFFER 64
typedef struct {
uint8_t u8id; /*!< slave address between 1 and 247. 0 means broadcast */
uint8_t u8fct; /*!< function code: 1, 2, 3, 4, 5, 6, 15 or 16 */
uint16_t u16RegAdd; /*!< address of the first register to access at slave/s */
uint16_t u16CoilsNo; /*!< number of coils or registers to access */
uint16_t *au16reg; /*!< pointer to memory image in master */
}
modbus_t;
enum {
RESPONSE_SIZE = 6,
EXCEPTION_SIZE = 3,
CHECKSUM_SIZE = 2
};
enum MESSAGE {
ID = 0,
FUNC,
ADD_HI,
ADD_LO,
NB_HI,
NB_LO,
BYTE_CNT
};
enum MB_FC {
MB_FC_NONE = 0, /*!< null operator */
MB_FC_READ_COILS = 1, /*!< FCT=1 -> read coils or digital outputs */
MB_FC_READ_DISCRETE_INPUT = 2, /*!< FCT=2 -> read digital inputs */
MB_FC_READ_REGISTERS = 3, /*!< FCT=3 -> read registers or analog outputs */
MB_FC_READ_INPUT_REGISTER = 4, /*!< FCT=4 -> read analog inputs */
MB_FC_WRITE_COIL = 5, /*!< FCT=5 -> write single coil or output */
MB_FC_WRITE_REGISTER = 6, /*!< FCT=6 -> write single register */
MB_FC_WRITE_MULTIPLE_COILS = 15, /*!< FCT=15 -> write multiple coils or outputs */
MB_FC_WRITE_MULTIPLE_REGISTERS = 16 /*!< FCT=16 -> write multiple registers */
};
enum COM_STATES {
COM_IDLE = 0,
COM_WAITING = 1
};
enum ERR_LIST {
ERR_NOT_MASTER = -1,
ERR_POLLING = -2,
ERR_BUFF_OVERFLOW = -3,
ERR_BAD_CRC = -4,
ERR_EXCEPTION = -5
};
enum {
NO_REPLY = 255, /*!< */
EXC_FUNC_CODE = 1, /*!< Function code not available */
EXC_ADDR_RANGE = 2, /*!< Address beyond available space for Modbus registers */
EXC_REGS_QUANT = 3, /*!< Coils or registers number beyond the available space */
EXC_EXECUTE = 4 /*!< */
};
const unsigned char fctsupported[] = {
MB_FC_READ_COILS,
MB_FC_READ_DISCRETE_INPUT,
MB_FC_READ_REGISTERS,
MB_FC_READ_INPUT_REGISTER,
MB_FC_WRITE_COIL,
MB_FC_WRITE_REGISTER,
MB_FC_WRITE_MULTIPLE_COILS,
MB_FC_WRITE_MULTIPLE_REGISTERS
};
#define T35 5
class Modbus {
private:
HardwareSerial *port; //!< Pointer to Serial class object
uint8_t u8id; //!<0=master, 1..247=slave number
uint8_t u8serno; //!<serial port: 0-Serial, 1..3-Serial1..Serial3
uint8_t u8txenpin; //!<flow control pin: 0=USB or RS-232 mode, >0=RS-485 mode
uint8_t u8state;
uint8_t au8Buffer[MAX_BUFFER];
uint8_t u8BufferSize;
uint8_t u8lastRec;
uint16_t *au16regs;
uint16_t u16InCnt, u16OutCnt, u16errCnt;
uint16_t u16timeOut;
uint32_t u32time, u32timeOut;
uint8_t u8regsize;
void init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
void sendTxBuffer(); // transmit buffer to serial port
int8_t getRxBuffer(); // get serial buffer contents
uint16_t calcCRC(uint8_t u8length); // get CRC from au8Buffer until u8length
uint8_t validateAnswer();
uint8_t validateRequest(); // validate master request
void get_FC1(); // *** only master ***
void get_FC3(); // *** only master ***
int8_t process_FC1( uint16_t *regs, uint8_t u8size ); //!< *** only slave ***
int8_t process_FC3( uint16_t *regs, uint8_t u8size ); //!< *** only slave ***
int8_t process_FC5( uint16_t *regs, uint8_t u8size ); //!< *** only slave ***
int8_t process_FC6( uint16_t *regs, uint8_t u8size ); //!< *** only slave ***
int8_t process_FC15( uint16_t *regs, uint8_t u8size ); //!< *** only slave ***
int8_t process_FC16( uint16_t *regs, uint8_t u8size ); //!< *** only slave ***
void buildException( uint8_t u8exception ); // build exception message
public:
Modbus(); // !< Default Constructor
Modbus(uint8_t u8id, uint8_t u8serno); // !< Constructor
Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin); // !< Full Constructor
void begin(long u32speed);
void begin();
void setTimeOut( uint16_t u16timeout); //!< write communication watch-dog timer
uint16_t getTimeOut(); //!< get communication watch-dog timer value
boolean getTimeOutState(); //!< get communication watch-dog timer state
int8_t query( modbus_t telegram ); //!< only for master
int8_t poll(); //!< cyclic poll for master
int8_t poll( uint16_t *regs, uint8_t u8size ); //!< cyclic poll for slave
uint16_t getInCnt(); //!< number of incoming messages
uint16_t getOutCnt(); //!< number of outcoming messages
uint16_t getErrCnt(); //!< error counter
uint8_t getID(); //!< get slave ID between 1 and 247
uint8_t getState();
uint8_t getLastError(); //!< get last error message
void setID( uint8_t u8id ); //!< write new ID for the slave
void end(); //!< finish any communication and release serial communication port
};
Modbus::Modbus() {
init(0, 0, 0);
}
Modbus::Modbus(uint8_t u8id, uint8_t u8serno) {
init(u8id, u8serno, 0);
}
Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin) {
init(u8id, u8serno, u8txenpin);
}
void Modbus::begin(long u32speed) {
switch ( u8serno ) {
#if defined(UBRR1H)
case 1:
port = &Serial1;
break;
#endif
#if defined(UBRR2H)
case 2:
port = &Serial2;
break;
#endif
#if defined(UBRR3H)
case 3:
port = &Serial3;
break;
#endif
case 0:
default:
port = &Serial;
break;
}
// port->begin(u32speed, u8config);
port->begin(u32speed);
if (u8txenpin > 1) { // pin 0 & pin 1 are reserved for RX/TX
// return RS485 transceiver to transmit mode
pinMode(u8txenpin, OUTPUT);
digitalWrite(u8txenpin, LOW);
}
port->flush();
u8lastRec = u8BufferSize = 0;
u16InCnt = u16OutCnt = u16errCnt = 0;
}
void Modbus::begin() {
begin(19200);
}
void Modbus::setID( uint8_t u8id) {
if (( u8id != 0) && (u8id <= 247)) {
this->u8id = u8id;
}
}
uint8_t Modbus::getID() {
return this->u8id;
}
void Modbus::setTimeOut( uint16_t u16timeOut) {
this->u16timeOut = u16timeOut;
}
boolean Modbus::getTimeOutState() {
return (millis() > u32timeOut);
}
uint16_t Modbus::getInCnt() {
return u16InCnt;
}
uint16_t Modbus::getOutCnt() {
return u16OutCnt;
}
uint16_t Modbus::getErrCnt() {
return u16errCnt;
}
uint8_t Modbus::getState() {
return u8state;
}
int8_t Modbus::query( modbus_t telegram ) {
uint8_t u8regsno, u8bytesno;
if (u8id != 0) return -2;
if (u8state != COM_IDLE) return -1;
if ((telegram.u8id == 0) || (telegram.u8id > 247)) return -3;
au16regs = telegram.au16reg;
// telegram header
au8Buffer[ ID ] = telegram.u8id;
au8Buffer[ FUNC ] = telegram.u8fct;
au8Buffer[ ADD_HI ] = highByte(telegram.u16RegAdd );
au8Buffer[ ADD_LO ] = lowByte( telegram.u16RegAdd );
switch ( telegram.u8fct ) {
case MB_FC_READ_COILS:
case MB_FC_READ_DISCRETE_INPUT:
case MB_FC_READ_REGISTERS:
case MB_FC_READ_INPUT_REGISTER:
au8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
au8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
u8BufferSize = 6;
break;
case MB_FC_WRITE_COIL:
au8Buffer[ NB_HI ] = ((au16regs[0] > 0) ? 0xff : 0);
au8Buffer[ NB_LO ] = 0;
u8BufferSize = 6;
break;
case MB_FC_WRITE_REGISTER:
au8Buffer[ NB_HI ] = highByte(au16regs[0]);
au8Buffer[ NB_LO ] = lowByte(au16regs[0]);
u8BufferSize = 6;
break;
case MB_FC_WRITE_MULTIPLE_COILS:
u8regsno = telegram.u16CoilsNo / 16;
u8bytesno = u8regsno * 2;
if ((telegram.u16CoilsNo % 16) != 0) {
u8bytesno++;
u8regsno++;
}
au8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
au8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
au8Buffer[ NB_LO + 1 ] = u8bytesno;
u8BufferSize = 7;
u8regsno = u8bytesno = 0; // now auxiliary registers
for (uint16_t i = 0; i < telegram.u16CoilsNo; i++) {
}
break;
case MB_FC_WRITE_MULTIPLE_REGISTERS:
au8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
au8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
au8Buffer[ NB_LO + 1 ] = (uint8_t) ( telegram.u16CoilsNo * 2 );
u8BufferSize = 7;
for (uint16_t i = 0; i < telegram.u16CoilsNo; i++) {
au8Buffer[ u8BufferSize ] = highByte( au16regs[ i ] );
u8BufferSize++;
au8Buffer[ u8BufferSize ] = lowByte( au16regs[ i ] );
u8BufferSize++;
}
break;
}
sendTxBuffer();
u8state = COM_WAITING;
return 0;
}
int8_t Modbus::poll() {
// check if there is any incoming frame
uint8_t u8current = port->available();
if (millis() > u32timeOut) {
u8state = COM_IDLE;
u16errCnt++;
return 0;
}
if (u8current == 0) return 0;
// check T35 after frame end or still no frame end
if (u8current != u8lastRec) {
u8lastRec = u8current;
u32time = millis() + T35;
return 0;
}
if (millis() < u32time) return 0;
// transfer Serial buffer frame to auBuffer
u8lastRec = 0;
int8_t i8state = getRxBuffer();
if (i8state < 7) {
u8state = COM_IDLE;
u16errCnt++;
return i8state;
}
// validate message: id, CRC, FCT, exception
uint8_t u8exception = validateAnswer();
if (u8exception != 0) {
u8state = COM_IDLE;
return u8exception;
}
// process answer
switch ( au8Buffer[ FUNC ] ) {
case MB_FC_READ_COILS:
case MB_FC_READ_DISCRETE_INPUT:
// call get_FC1 to transfer the incoming message to au16regs buffer
get_FC1( );
break;
case MB_FC_READ_INPUT_REGISTER:
case MB_FC_READ_REGISTERS :
// call get_FC3 to transfer the incoming message to au16regs buffer
get_FC3( );
break;
case MB_FC_WRITE_COIL:
case MB_FC_WRITE_REGISTER :
case MB_FC_WRITE_MULTIPLE_COILS:
case MB_FC_WRITE_MULTIPLE_REGISTERS :
// nothing to do
break;
default:
break;
}
u8state = COM_IDLE;
return u8BufferSize;
}
int8_t Modbus::poll( uint16_t *regs, uint8_t u8size ) {
au16regs = regs;
u8regsize = u8size;
// check if there is any incoming frame
uint8_t u8current = port->available();
if (u8current == 0) return 0;
// check T35 after frame end or still no frame end
if (u8current != u8lastRec) {
u8lastRec = u8current;
u32time = millis() + T35;
return 0;
}
if (millis() < u32time) return 0;
u8lastRec = 0;
int8_t i8state = getRxBuffer();
if (i8state < 7) return i8state;
// check slave id
if (au8Buffer[ ID ] != u8id) return 0;
// validate message: CRC, FCT, address and size
uint8_t u8exception = validateRequest();
if (u8exception > 0) {
if (u8exception != NO_REPLY) {
buildException( u8exception );
sendTxBuffer();
}
return u8exception;
}
u32timeOut = millis() + long(u16timeOut);
// process message
switch ( au8Buffer[ FUNC ] ) {
case MB_FC_READ_COILS:
case MB_FC_READ_DISCRETE_INPUT:
return process_FC1( regs, u8size );
break;
case MB_FC_READ_INPUT_REGISTER:
case MB_FC_READ_REGISTERS :
return process_FC3( regs, u8size );
break;
case MB_FC_WRITE_COIL:
return process_FC5( regs, u8size );
break;
case MB_FC_WRITE_REGISTER :
return process_FC6( regs, u8size );
break;
case MB_FC_WRITE_MULTIPLE_COILS:
return process_FC15( regs, u8size );
break;
case MB_FC_WRITE_MULTIPLE_REGISTERS :
return process_FC16( regs, u8size );
break;
default:
break;
}
}
/* _____PRIVATE FUNCTIONS_____________________________________________________ */
void Modbus::init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin) {
this->u8id = u8id;
this->u8serno = (u8serno > 3) ? 0 : u8serno;
this->u8txenpin = u8txenpin;
this->u16timeOut = 1000;
}
int8_t Modbus::getRxBuffer() {
boolean bBuffOverflow = false;
if (u8txenpin > 1) digitalWrite( u8txenpin, LOW );
u8BufferSize = 0;
while ( port->available() ) {
au8Buffer[ u8BufferSize ] = port->read();
u8BufferSize ++;
if (u8BufferSize >= MAX_BUFFER) bBuffOverflow = true;
}
u16InCnt++;
if (bBuffOverflow) {
u16errCnt++;
return ERR_BUFF_OVERFLOW;
}
return u8BufferSize;
}
void Modbus::sendTxBuffer() {
uint8_t i = 0;
// append CRC to message
uint16_t u16crc = calcCRC( u8BufferSize );
au8Buffer[ u8BufferSize ] = u16crc >> 8;
u8BufferSize++;
au8Buffer[ u8BufferSize ] = u16crc & 0x00ff;
u8BufferSize++;
// set RS485 transceiver to transmit mode
if (u8txenpin > 1) {
switch ( u8serno ) {
#if defined(UBRR1H)
case 1:
UCSR1A = UCSR1A | (1 << TXC1);
break;
#endif
#if defined(UBRR2H)
case 2:
UCSR2A = UCSR2A | (1 << TXC2);
break;
#endif
#if defined(UBRR3H)
case 3:
UCSR3A = UCSR3A | (1 << TXC3);
break;
#endif
case 0:
default:
UCSR0A = UCSR0A | (1 << TXC0);
break;
}
digitalWrite( u8txenpin, HIGH );
}
// transfer buffer to serial line
port->write( au8Buffer, u8BufferSize );
// keep RS485 transceiver in transmit mode as long as sending
if (u8txenpin > 1) {
switch ( u8serno ) {
#if defined(UBRR1H)
case 1:
while (!(UCSR1A & (1 << TXC1)));
break;
#endif
#if defined(UBRR2H)
case 2:
while (!(UCSR2A & (1 << TXC2)));
break;
#endif
#if defined(UBRR3H)
case 3:
while (!(UCSR3A & (1 << TXC3)));
break;
#endif
case 0:
default:
while (!(UCSR0A & (1 << TXC0)));
break;
}
// return RS485 transceiver to receive mode
digitalWrite( u8txenpin, LOW );
}
port->flush();
u8BufferSize = 0;
// set time-out for master
u32timeOut = millis() + (unsigned long) u16timeOut;
// increase message counter
u16OutCnt++;
}
/**
* @brief
* This method calculates CRC
*
* @return uint16_t calculated CRC value for the message
* @ingroup buffer
*/
uint16_t Modbus::calcCRC(uint8_t u8length) {
unsigned int temp, temp2, flag;
temp = 0xFFFF;
for (unsigned char i = 0; i < u8length; i++) {
temp = temp ^ au8Buffer[i];
for (unsigned char j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp >>= 1;
if (flag)
temp ^= 0xA001;
}
}
// Reverse byte order.
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;
// the returned value is already swapped
// crcLo byte is first & crcHi byte is last
return temp;
}
uint8_t Modbus::validateRequest() {
// check message crc vs calculated crc
uint16_t u16MsgCRC =
((au8Buffer[u8BufferSize - 2] << 8)
| au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
if ( calcCRC( u8BufferSize - 2 ) != u16MsgCRC ) {
u16errCnt ++;
return NO_REPLY;
}
// check fct code
boolean isSupported = false;
for (uint8_t i = 0; i < sizeof( fctsupported ); i++) {
if (fctsupported[i] == au8Buffer[FUNC]) {
isSupported = 1;
break;
}
}
if (!isSupported) {
u16errCnt ++;
return EXC_FUNC_CODE;
}
// check start address & nb range
uint16_t u16regs = 0;
uint8_t u8regs;
switch ( au8Buffer[ FUNC ] ) {
case MB_FC_READ_COILS:
case MB_FC_READ_DISCRETE_INPUT:
case MB_FC_WRITE_MULTIPLE_COILS:
u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]) / 16;
u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]) / 16;
u8regs = (uint8_t) u16regs;
if (u8regs > u8regsize) return EXC_ADDR_RANGE;
break;
case MB_FC_WRITE_COIL:
u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]) / 16;
u8regs = (uint8_t) u16regs;
if (u8regs > u8regsize) return EXC_ADDR_RANGE;
break;
case MB_FC_WRITE_REGISTER :
u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
u8regs = (uint8_t) u16regs;
if (u8regs > u8regsize) return EXC_ADDR_RANGE;
break;
case MB_FC_READ_REGISTERS :
case MB_FC_READ_INPUT_REGISTER :
case MB_FC_WRITE_MULTIPLE_REGISTERS :
u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
u8regs = (uint8_t) u16regs;
if (u8regs > u8regsize) return EXC_ADDR_RANGE;
break;
}
return 0; // OK, no exception code thrown
}
uint8_t Modbus::validateAnswer() {
// check message crc vs calculated crc
uint16_t u16MsgCRC =
((au8Buffer[u8BufferSize - 2] << 8)
| au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
if ( calcCRC( u8BufferSize - 2 ) != u16MsgCRC ) {
u16errCnt ++;
return NO_REPLY;
}
// check exception
if ((au8Buffer[ FUNC ] & 0x80) != 0) {
u16errCnt ++;
return ERR_EXCEPTION;
}
// check fct code
boolean isSupported = false;
for (uint8_t i = 0; i < sizeof( fctsupported ); i++) {
if (fctsupported[i] == au8Buffer[FUNC]) {
isSupported = 1;
break;
}
}
if (!isSupported) {
u16errCnt ++;
return EXC_FUNC_CODE;
}
return 0; // OK, no exception code thrown
}
void Modbus::buildException( uint8_t u8exception ) {
uint8_t u8func = au8Buffer[ FUNC ]; // get the original FUNC code
au8Buffer[ ID ] = u8id;
au8Buffer[ FUNC ] = u8func + 0x80;
au8Buffer[ 2 ] = u8exception;
u8BufferSize = EXCEPTION_SIZE;
}
void Modbus::get_FC1() {
uint8_t u8byte, i;
u8byte = 0;
// check the answer length
boolean bEvenOdd =
( au8Buffer[ ADD_HI ] % 2 == 0) ?
false :
true;
uint8_t u8WordsNo =
( !bEvenOdd ) ?
au8Buffer[ ADD_HI ] / 2 :
au8Buffer[ ADD_HI ] / 2 + 1;
for (i = 0; i < u8WordsNo; i++) {
au16regs[ i ] = word(
au8Buffer[ u8byte ],
au8Buffer[ u8byte + 1 ]);
u8byte += 2;
}
// cut last byte
if (bEvenOdd) {
au16regs[ u8WordsNo - 1 ] &= 0xff00;
}
}
void Modbus::get_FC3() {
uint8_t u8byte, i;
u8byte = 3;
for (i = 0; i < au8Buffer[ 2 ] / 2; i++) {
au16regs[ i ] = word(
au8Buffer[ u8byte ],
au8Buffer[ u8byte + 1 ]);
u8byte += 2;
}
}
int8_t Modbus::process_FC1( uint16_t *regs, uint8_t u8size ) {
uint8_t u8currentRegister, u8currentBit, u8bytesno, u8bitsno;
uint8_t u8CopyBufferSize;
uint16_t u16currentCoil, u16coil;
// get the first and last coil from the message
uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
// put the number of bytes in the outcoming message
u8bytesno = (uint8_t) (u16Coilno / 8);
if (u16Coilno % 8 != 0) u8bytesno ++;
au8Buffer[ ADD_HI ] = u8bytesno;
u8BufferSize = ADD_LO;
// read each coil from the register map and put its value inside the outcoming message
u8bitsno = 0;
for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++) {
u16coil = u16StartCoil + u16currentCoil;
u8currentRegister = (uint8_t) (u16coil / 16);
u8currentBit = (uint8_t) (u16coil % 16);
bitWrite(
au8Buffer[ u8BufferSize ],
u8bitsno,
bitRead( regs[ u8currentRegister ], u8currentBit ) );
u8bitsno ++;
if (u8bitsno > 7) {
u8bitsno = 0;
u8BufferSize++;
}
}
// send outcoming message
if (u16Coilno % 8 != 0) u8BufferSize ++;
u8CopyBufferSize = u8BufferSize +2;
sendTxBuffer();
return u8CopyBufferSize;
}
int8_t Modbus::process_FC3( uint16_t *regs, uint8_t u8size ) {
uint8_t u8StartAdd = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
uint8_t u8regsno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
uint8_t u8CopyBufferSize;
uint8_t i;
au8Buffer[ 2 ] = u8regsno * 2;
u8BufferSize = 3;
for (i = u8StartAdd; i < u8StartAdd + u8regsno; i++) {
au8Buffer[ u8BufferSize ] = highByte(regs[i]);
u8BufferSize++;
au8Buffer[ u8BufferSize ] = lowByte(regs[i]);
u8BufferSize++;
}
u8CopyBufferSize = u8BufferSize +2;
sendTxBuffer();
return u8CopyBufferSize;
}
int8_t Modbus::process_FC5( uint16_t *regs, uint8_t u8size ) {
uint8_t u8currentRegister, u8currentBit;
uint8_t u8CopyBufferSize;
uint16_t u16coil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
// point to the register and its bit
u8currentRegister = (uint8_t) (u16coil / 16);
u8currentBit = (uint8_t) (u16coil % 16);
// write to coil
bitWrite(
regs[ u8currentRegister ],
u8currentBit,
au8Buffer[ NB_HI ] == 0xff );
// send answer to master
u8BufferSize = 6;
u8CopyBufferSize = u8BufferSize +2;
sendTxBuffer();
return u8CopyBufferSize;
}
int8_t Modbus::process_FC6( uint16_t *regs, uint8_t u8size ) {
uint8_t u8add = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
uint8_t u8CopyBufferSize;
uint16_t u16val = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
regs[ u8add ] = u16val;
// keep the same header
u8BufferSize = RESPONSE_SIZE;
u8CopyBufferSize = u8BufferSize +2;
sendTxBuffer();
return u8CopyBufferSize;
}
int8_t Modbus::process_FC15( uint16_t *regs, uint8_t u8size ) {
uint8_t u8currentRegister, u8currentBit, u8frameByte, u8bitsno;
uint8_t u8CopyBufferSize;
uint16_t u16currentCoil, u16coil;
boolean bTemp;
// get the first and last coil from the message
uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
// read each coil from the register map and put its value inside the outcoming message
u8bitsno = 0;
u8frameByte = 7;
for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++) {
u16coil = u16StartCoil + u16currentCoil;
u8currentRegister = (uint8_t) (u16coil / 16);
u8currentBit = (uint8_t) (u16coil % 16);
bTemp = bitRead(
au8Buffer[ u8frameByte ],
u8bitsno );
bitWrite(
regs[ u8currentRegister ],
u8currentBit,
bTemp );
u8bitsno ++;
if (u8bitsno > 7) {
u8bitsno = 0;
u8frameByte++;
}
}
// send outcoming message
// it's just a copy of the incomping frame until 6th byte
u8BufferSize = 6;
u8CopyBufferSize = u8BufferSize +2;
sendTxBuffer();
return u8CopyBufferSize;
}
int8_t Modbus::process_FC16( uint16_t *regs, uint8_t u8size ) {
uint8_t u8func = au8Buffer[ FUNC ]; // get the original FUNC code
uint8_t u8StartAdd = au8Buffer[ ADD_HI ] << 8 | au8Buffer[ ADD_LO ];
uint8_t u8regsno = au8Buffer[ NB_HI ] << 8 | au8Buffer[ NB_LO ];
uint8_t u8CopyBufferSize;
uint8_t i;
uint16_t temp;
// build header
au8Buffer[ NB_HI ] = 0;
au8Buffer[ NB_LO ] = u8regsno;
u8BufferSize = RESPONSE_SIZE;
// write registers
for (i = 0; i < u8regsno; i++) {
temp = word(
au8Buffer[ (BYTE_CNT + 1) + i * 2 ],
au8Buffer[ (BYTE_CNT + 2) + i * 2 ]);
regs[ u8StartAdd + i ] = temp;
}
u8CopyBufferSize = u8BufferSize +2;
sendTxBuffer();
return u8CopyBufferSize;
}
Code: Select all
/**
* Modbus object declaration
* u8id : node id = 0 for master, = 1..247 for slave
* u8serno : serial port (use 0 for Serial)
* u8txenpin : 0 for RS-232 and USB-FTDI
* or any pin number > 1 for RS-485
*
* pin maping:
* 2 - digital input
* 3 - digital input
* 4 - digital input
* 5 - digital input
* 6 - digital output
* 7 - digital output
* 8 - digital output
* 9 - digital output
* 10 - analog output
* 11 - analog output
* 14 - analog input
* 15 - analog input
*/
#define ID 1
/*static float ARDUINO_ANALOG_SCALING = 0.00488758;
static float Ydegree;
static int Sensor_Value;
float Yvoltage;
*/
Modbus slave(ID, 0, 0);
boolean led;
int8_t state = 0;
unsigned long tempus;
// data array for modbus network sharing
uint16_t au16data[9];
float latitude=13.08;
void setup() {
pinMode(13, OUTPUT);
slave.begin( 19200 );
tempus = millis() + 100;
digitalWrite(13, HIGH );
}
void loop() {
state = slave.poll( au16data,10 );
if (state > 4) {
tempus = millis() + 50;
digitalWrite(13, HIGH);
}
if (millis() > tempus) digitalWrite(13, LOW );
au16data[4] = analogRead(0);
// au16data[5] = analogRead(1);
au16data[6] = slave.getInCnt();
au16data[7] = slave.getOutCnt();
au16data[8] = slave.getErrCnt();
}