Modbus protocol Implimentation
ajit.nayak87
Posts: 76
Dear all,
I am trying to impliment modbus protcol with Arduino. Here i am attaching my code and software iused . Below error i am getting for code. From slave i am not getting any response. Let me know how to solve this issue
I am trying to impliment modbus protcol with Arduino. Here i am attaching my code and software iused . Below error i am getting for code. From slave i am not getting any response. Let me know how to solve this issue
#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; }
/** * 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, 9 ); if (state > 4) { tempus = millis() + 50; digitalWrite(13, HIGH); } if (millis() > tempus) digitalWrite(13, LOW ); // get digital inputs -> au16data[0] bitWrite( au16data[0], 0, digitalRead( 2 )); bitWrite( au16data[0], 1, digitalRead( 3 )); bitWrite( au16data[0], 2, digitalRead( 4 )); bitWrite( au16data[0], 3, digitalRead( 5 )); // set digital outputs -> au16data[1] digitalWrite( 6, bitRead( au16data[1], 0 )); digitalWrite( 7, bitRead( au16data[1], 1 )); digitalWrite( 8, bitRead( au16data[1], 2 )); digitalWrite( 9, bitRead( au16data[1], 3 )); // set analog outputs analogWrite( 10, au16data[2] ); analogWrite( 11, au16data[3] ); // read analog inputs au16data[4] = analogRead( A0 ); au16data[5] = analogRead( A1 ); au16data[6] = slave.getInCnt(); au16data[7] = slave.getOutCnt(); au16data[8] = slave.getErrCnt(); }
Comments
Parallax does not produce or sell any Arduinos.
You will find better answers on some Arduino forums...
Enjoy
Mike
Nothing here about wanting to run Arduino code on a Propeller. If that were the case, the OP would likely just be wanting to run Modbus via GCC on a Propeller.
Porting Modbus code twice seems a pedantic exercise. Besides Modbus seems alive and well and proprietary. (It likely would frown on an open-source hack on anything).
The request is to hack the slave which is a Modbus device of some sort.