INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
RS485 Modbus lesen und Ladegerät regeln
22.06.2017, 19:02
Beitrag #9
RE: RS485 Modbus lesen und Ladegerät regeln
Hi,
also das Shield ist doch ganz gut ausgestattet. Du kannst die RX und TX Signale getrennt auf die Port's 0 bis 7 Jumpern. Hier bietet sich dann an per Softwareseriel auf die Port's mit den Nummern höher als 1 auszuweichen um die Kommunikation zum PC nicht zu stören. Damit wäre dann die Hardware mal erledigt.
Für das Modbus Protokoll benötigst dann wohl die passende Library dazu um Softwaremäßig die Sache zu regeln. Die Zwei RS485 Anschlußklemmen dürften wohl identische Signale führen. Leider hat ELV zu dem Shield keine Unterlagen auf der Webseite parat Angry - da würde ich denen mal eine Mail schicken Big Grin
lgbk

1+1 = 10 Angel ...und ich bin hier nicht der Suchmaschinen-Ersatz Dodgy...nur mal so als genereller Tipp..
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
22.06.2017, 19:39 (Dieser Beitrag wurde zuletzt bearbeitet: 22.06.2017 19:42 von Stromsparer.)
Beitrag #10
RE: RS485 Modbus lesen und Ladegerät regeln
Ich glaube Hardwareseitig habe ich alles richtig, wenn ich dei Abfrage intervalle ändere, ändert sich auch das blinken der RX Led auf dem Shield.
Leider bekomme ich nur Quadrate im SerialMonitor.

Code:
/**
*  Modbus master example 1:
*  The purpose of this example is to query an array of data
*  from an external Modbus slave device.
*  The link media can be USB or RS232.
*
*  Recommended Modbus slave:
*  diagslave http://www.modbusdriver.com/diagslave.html
*
*  In a Linux box, run
*  "./diagslave /dev/ttyUSB0 -b 19200 -d 8 -s 1 -p none -m rtu -a 1"
*     This is:
*         serial port /dev/ttyUSB0 at 19200 baud 8N1
*        RTU mode and address @1
*/

#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16];
uint8_t u8state;

/**
*  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
*/
Modbus master(0,0,2); // this is master and RS-485

/**
* This is an structe which contains a query to an slave device
*/
modbus_t telegram;

unsigned long u32wait;

void setup() {
  master.begin( 9600 ); // baud-rate at 9600
  master.setTimeOut( 2000 ); // if there is no answer in 2000 ms, roll over
  u32wait = millis() + 1000;
  u8state = 0;
}

void loop() {
  switch( u8state ) {
  case 0:
    if (millis() > u32wait) u8state++; // wait state
    break;
  case 1:
    telegram.u8id = 1; // slave address
    telegram.u8fct = 3; // function code (this one is registers read)
    telegram.u16RegAdd = 1; // start address in slave
    telegram.u16CoilsNo = 4; // number of elements (coils or registers) to read
    telegram.au16reg = au16data; // pointer to a memory array in the Arduino

    master.query( telegram ); // send query (only once)
    u8state++;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 100;
    }
    break;
  }
}

und hier die ModbusRTU.h

Code:
/**
* @file     ModbusRtu.h
* @version     1.21
* @date        2016.02.21
* @author     Samuel Marco i Armengol
* @contact     sammarcoarmengol@gmail.com
* @contribution Helium6072
*
* @description
*  Arduino library for communicating with Modbus devices
*  over RS232/USB/485 via RTU protocol.
*
*  Further information:
*  http://modbus.org/
*  http://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
*
* @license
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; version
*  2.1 of the License.
*
*  This library 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
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*
* @defgroup setup Modbus Object Instantiation/Initialization
* @defgroup loop Modbus Object Management
* @defgroup buffer Modbus Buffer Management
* @defgroup discrete Modbus Function Codes for Discrete Coils/Inputs
* @defgroup register Modbus Function Codes for Holding/Input Registers
*
*/

#include <inttypes.h>
#include "Arduino.h"
#include "Print.h"
#include <SoftwareSerial.h>

/**
* @struct modbus_t
* @brief
* Master query structure:
* This includes all the necessary fields to make the Master generate a Modbus query.
* A Master may keep several of these structures and send them cyclically or
* use them according to program needs.
*/
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
* @brief
* Indexes to telegram frame positions
*/
enum MESSAGE
{
    ID                             = 0, //!< ID field
    FUNC, //!< Function code position
    ADD_HI, //!< Address high byte
    ADD_LO, //!< Address low byte
    NB_HI, //!< Number of coils or registers high byte
    NB_LO, //!< Number of coils or registers low byte
    BYTE_CNT  //!< byte counter
};

/**
* @enum MB_FC
* @brief
* Modbus function codes summary.
* These are the implement function codes either for Master or for Slave.
*
* @see also fctsupported
* @see also modbus_t
*/
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,
    EXC_ADDR_RANGE = 2,
    EXC_REGS_QUANT = 3,
    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
#define  MAX_BUFFER  64    //!< maximum size for the communication buffer in bytes

/**
* @class Modbus
* @brief
* Arduino class library for communicating with Modbus devices over
* USB/RS232/485 (via RTU protocol).
*/
class Modbus
{
private:
    HardwareSerial *port; //!< Pointer to Serial class object
    SoftwareSerial *softPort; //!< Pointer to SoftwareSerial class object
    uint8_t u8id; //!< 0=master, 1..247=slave number
    uint8_t u8serno; //!< serial port: 0-Serial, 1..3-Serial1..Serial3; 4: use software serial
    uint8_t u8txenpin; //!< flow control pin: 0=USB or RS-232 mode, >0=RS-485 mode
    uint8_t u8state;
    uint8_t u8lastError;
    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 init(uint8_t u8id);
    void sendTxBuffer();
    int8_t getRxBuffer();
    uint16_t calcCRC(uint8_t u8length);
    uint8_t validateAnswer();
    uint8_t validateRequest();
    void get_FC1();
    void get_FC3();
    int8_t process_FC1( uint16_t *regs, uint8_t u8size );
    int8_t process_FC3( uint16_t *regs, uint8_t u8size );
    int8_t process_FC5( uint16_t *regs, uint8_t u8size );
    int8_t process_FC6( uint16_t *regs, uint8_t u8size );
    int8_t process_FC15( uint16_t *regs, uint8_t u8size );
    int8_t process_FC16( uint16_t *regs, uint8_t u8size );
    void buildException( uint8_t u8exception ); // build exception message

public:
    Modbus();
    Modbus(uint8_t u8id, uint8_t u8serno);
    Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
    Modbus(uint8_t u8id);
    void begin(long u32speed);
    void begin(SoftwareSerial *sPort, long u32speed);
    void begin(long u32speed, uint8_t u8config);
    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
};

/* _____PUBLIC FUNCTIONS_____________________________________________________ */

/**
* @brief
* Default Constructor for Master through Serial
*
* @ingroup setup
*/
Modbus::Modbus()
{
    init(0, 0, 2);
}

/**
* @brief
* Full constructor for a Master/Slave through USB/RS232C
*
* @param u8id   node address 0=master, 1..247=slave
* @param u8serno  serial port used 0..3
* @ingroup setup
* @overload Modbus::Modbus(uint8_t u8id, uint8_t u8serno)
* @overload Modbus::Modbus(uint8_t u8id)
* @overload Modbus::Modbus()
*/
Modbus::Modbus(uint8_t u8id, uint8_t u8serno)
{
    init(u8id, u8serno, 0);
}

/**
* @brief
* Full constructor for a Master/Slave through USB/RS232C/RS485
* It needs a pin for flow control only for RS485 mode
*
* @param u8id   node address 0=master, 1..247=slave
* @param u8serno  serial port used 0..3
* @param u8txenpin pin for txen RS-485 (=0 means USB/RS232C mode)
* @ingroup setup
* @overload Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin)
* @overload Modbus::Modbus(uint8_t u8id)
* @overload Modbus::Modbus()
*/
Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin)
{
    init(u8id, u8serno, u8txenpin);
}

/**
* @brief
* Constructor for a Master/Slave through USB/RS232C via software serial
* This constructor only specifies u8id (node address) and should be only
* used if you want to use software serial instead of hardware serial.
* If you use this constructor you have to begin ModBus object by
* using "void Modbus::begin(SoftwareSerial *softPort, long u32speed)".
*
* @param u8id   node address 0=master, 1..247=slave
* @ingroup setup
* @overload Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin)
* @overload Modbus::Modbus(uint8_t u8id, uint8_t u8serno)
* @overload Modbus::Modbus()
*/
Modbus::Modbus(uint8_t u8id)
{
    init(u8id);
}

/**
* @brief
* Initialize class object.
*
* Sets up the serial port using specified baud rate.
* Call once class has been instantiated, typically within setup().
*
* @see http://arduino.cc/en/Serial/Begin#.Uy4CJ6aKlHY
* @param speed   baud rate, in standard increments (300..115200)
* @ingroup setup
*/
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);
    if (u8txenpin > 1)   // pin 0 & pin 1 are reserved for RX/TX
    {
        // return RS485 transceiver to transmit mode
        pinMode(u8txenpin, OUTPUT);
        digitalWrite(u8txenpin, LOW);
    }

    while(port->read() >= 0);
    u8lastRec = u8BufferSize = 0;
    u16InCnt = u16OutCnt = u16errCnt = 0;
}

/**
* @brief
* Initialize class object.
*
* Sets up the software serial port using specified baud rate and SoftwareSerial object.
* Call once class has been instantiated, typically within setup().
*
* @param speed   *softPort, pointer to SoftwareSerial class object
* @param speed   baud rate, in standard increments (300..115200)
* @ingroup setup
*/
void Modbus::begin(SoftwareSerial *sPort, long u32speed)
{

    softPort=sPort;

    softPort->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);
    }

    while(softPort->read() >= 0);
    u8lastRec = u8BufferSize = 0;
    u16InCnt = u16OutCnt = u16errCnt = 0;
}

/**
* @brief
* Initialize class object.
*
* Sets up the serial port using specified baud rate.
* Call once class has been instantiated, typically within setup().
*
* @see http://arduino.cc/en/Serial/Begin#.Uy4CJ6aKlHY
* @param speed   baud rate, in standard increments (300..115200)
* @param config  data frame settings (data length, parity and stop bits)
* @ingroup setup
*/
void Modbus::begin(long u32speed,uint8_t u8config)
{

    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);
    if (u8txenpin > 1)   // pin 0 & pin 1 are reserved for RX/TX
    {
        // return RS485 transceiver to transmit mode
        pinMode(u8txenpin, OUTPUT);
        digitalWrite(u8txenpin, LOW);
    }

    while(port->read() >= 0);
    u8lastRec = u8BufferSize = 0;
    u16InCnt = u16OutCnt = u16errCnt = 0;
}

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

/**
* @brief
* Method to write a new slave ID address
*
* @param     u8id    new slave address between 1 and 247
* @ingroup setup
*/
void Modbus::setID( uint8_t u8id)
{
    if (( u8id != 0) && (u8id <= 247))
    {
        this->u8id = u8id;
    }
}

/**
* @brief
* Method to read current slave ID address
*
* @return u8id    current slave address between 1 and 247
* @ingroup setup
*/
uint8_t Modbus::getID()
{
    return this->u8id;
}

/**
* @brief
* Initialize time-out parameter
*
* Call once class has been instantiated, typically within setup().
* The time-out timer is reset each time that there is a successful communication
* between Master and Slave. It works for both.
*
* @param time-out value (ms)
* @ingroup setup
*/
void Modbus::setTimeOut( uint16_t u16timeOut)
{
    this->u16timeOut = u16timeOut;
}

/**
* @brief
* Return communication Watchdog state.
* It could be usefull to reset outputs if the watchdog is fired.
*
* @return TRUE if millis() > u32timeOut
* @ingroup loop
*/
boolean Modbus::getTimeOutState()
{
    return (millis() > u32timeOut);
}

/**
* @brief
* Get input messages counter value
* This can be useful to diagnose communication
*
* @return input messages counter
* @ingroup buffer
*/
uint16_t Modbus::getInCnt()
{
    return u16InCnt;
}

/**
* @brief
* Get transmitted messages counter value
* This can be useful to diagnose communication
*
* @return transmitted messages counter
* @ingroup buffer
*/
uint16_t Modbus::getOutCnt()
{
    return u16OutCnt;
}

/**
* @brief
* Get errors counter value
* This can be useful to diagnose communication
*
* @return errors counter
* @ingroup buffer
*/
uint16_t Modbus::getErrCnt()
{
    return u16errCnt;
}

/**
* Get modbus master state
*
* @return = 0 IDLE, = 1 WAITING FOR ANSWER
* @ingroup buffer
*/
uint8_t Modbus::getState()
{
    return u8state;
}

/**
* Get the last error in the protocol processor
*
* @returnreturn   NO_REPLY = 255      Time-out
* @return   EXC_FUNC_CODE = 1   Function code not available
* @return   EXC_ADDR_RANGE = 2  Address beyond available space for Modbus registers
* @return   EXC_REGS_QUANT = 3  Coils or registers number beyond the available space
* @ingroup buffer
*/
uint8_t Modbus::getLastError()
{
    return u8lastError;
}

/**
* @brief
* *** Only Modbus Master ***
* Generate a query to an slave with a modbus_t telegram structure
* The Master must be in COM_IDLE mode. After it, its state would be COM_WAITING.
* This method has to be called only in loop() section.
*
* @see modbus_t
* @param modbus_t  modbus telegram structure (id, fct, ...)
* @ingroup loop
* @todo finish function 15
*/
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: // TODO: implement "sending 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;
}

/**
* @brief *** Only for Modbus Master ***
* This method checks if there is any incoming answer if pending.
* If there is no answer, it would change Master state to COM_IDLE.
* This method must be called only at loop section.
* Avoid any delay() function.
*
* Any incoming data would be redirected to au16regs pointer,
* as defined in its modbus_t query telegram.
*
* @params    nothing
* @return errors counter
* @ingroup loop
*/
int8_t Modbus::poll()
{
    // check if there is any incoming frame
    uint8_t u8current;
    if(u8serno<4)
        u8current = port->available();
    else
        u8current = softPort->available();

    if (millis() > u32timeOut)
    {
        u8state = COM_IDLE;
        u8lastError = NO_REPLY;
        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;
}

/**
* @brief
* *** Only for Modbus Slave ***
* This method checks if there is any incoming query
* Afterwards, it would shoot a validation routine plus a register query
* Avoid any delay() function !!!!
* After a successful frame between the Master and the Slave, the time-out timer is reset.
*
* @param *regs  register table for communication exchange
* @param u8size  size of the register table
* @return 0 if no query, 1..4 if communication error, >4 if correct query processed
* @ingroup loop
*/
int8_t Modbus::poll( uint16_t *regs, uint8_t u8size )
{

    au16regs = regs;
    u8regsize = u8size;
    uint8_t u8current;


    // check if there is any incoming frame
    if(u8serno<4)
        u8current = port->available();
    else
        u8current = softPort->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();
    u8lastError = i8state;
    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();
        }
        u8lastError = u8exception;
        return u8exception;
    }

    u32timeOut = millis() + long(u16timeOut);
    u8lastError = 0;

    // 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;
    }
    return i8state;
}

/* _____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;
}

void Modbus::init(uint8_t u8id)
{
    this->u8id = u8id;
    this->u8serno = 4;
    this->u8txenpin = 0;
    this->u16timeOut = 1000;
}

/**
* @brief
* This method moves Serial buffer data to the Modbus au8Buffer.
*
* @return buffer size if OK, ERR_BUFF_OVERFLOW if u8BufferSize >= MAX_BUFFER
* @ingroup buffer
*/
int8_t Modbus::getRxBuffer()
{
    boolean bBuffOverflow = false;

    if (u8txenpin > 1) digitalWrite( u8txenpin, LOW );

    u8BufferSize = 0;
    if(u8serno<4)
        while ( port->available() )
        {
            au8Buffer[ u8BufferSize ] = port->read();
            u8BufferSize ++;

            if (u8BufferSize >= MAX_BUFFER) bBuffOverflow = true;
        }
    else
        while ( softPort->available() )
        {
            au8Buffer[ u8BufferSize ] = softPort->read();
            u8BufferSize ++;

            if (u8BufferSize >= MAX_BUFFER) bBuffOverflow = true;
        }
    u16InCnt++;

    if (bBuffOverflow)
    {
        u16errCnt++;
        return ERR_BUFF_OVERFLOW;
    }
    return u8BufferSize;
}

/**
* @brief
* This method transmits au8Buffer to Serial line.
* Only if u8txenpin != 0, there is a flow handling in order to keep
* the RS485 transceiver in output state as long as the message is being sent.
* This is done with UCSRxA register.
* The CRC is appended to the buffer before starting to send it.
*
* @param nothing
* @return nothing
* @ingroup buffer
*/
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
    if(u8serno<4)
        port->write( au8Buffer, u8BufferSize );
    else
        softPort->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 );
    }
    if(u8serno<4)
        while(port->read() >= 0);
    else
        while(softPort->read() >= 0);

    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;
}

/**
* @brief
* This method validates slave incoming messages
*
* @return 0 if OK, EXCEPTION if anything fails
* @ingroup buffer
*/
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
}

/**
* @brief
* This method validates master incoming messages
*
* @return 0 if OK, EXCEPTION if anything fails
* @ingroup buffer
*/
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
}

/**
* @brief
* This method builds an exception message
*
* @ingroup buffer
*/
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;
}

/**
* This method processes functions 1 & 2 (for master)
* This method puts the slave answer into master data buffer
*
* @ingroup register
* TODO: finish its implementation
*/
void Modbus::get_FC1()
{
    uint8_t u8byte, i;
    u8byte = 0;

    //  for (i=0; i< au8Buffer[ 2 ] /2; i++) {
    //    au16regs[ i ] = word(
    //    au8Buffer[ u8byte ],
    //    au8Buffer[ u8byte +1 ]);
    //    u8byte += 2;
    //  }
}

/**
* This method processes functions 3 & 4 (for master)
* This method puts the slave answer into master data buffer
*
* @ingroup register
*/
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;
    }
}

/**
* @brief
* This method processes functions 1 & 2
* This method reads a bit array and transfers it to the master
*
* @return u8BufferSize Response to master length
* @ingroup discrete
*/
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;
}

/**
* @brief
* This method processes functions 3 & 4
* This method reads a word array and transfers it to the master
*
* @return u8BufferSize Response to master length
* @ingroup register
*/
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;
}

/**
* @brief
* This method processes function 5
* This method writes a value assigned by the master to a single bit
*
* @return u8BufferSize Response to master length
* @ingroup discrete
*/
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;
}

/**
* @brief
* This method processes function 6
* This method writes a value assigned by the master to a single word
*
* @return u8BufferSize Response to master length
* @ingroup register
*/
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;
}

/**
* @brief
* This method processes function 15
* This method writes a bit array assigned by the master
*
* @return u8BufferSize Response to master length
* @ingroup discrete
*/
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;
}

/**
* @brief
* This method processes function 16
* This method writes a word array assigned by the master
*
* @return u8BufferSize Response to master length
* @ingroup register
*/
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;
}
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
22.06.2017, 19:58
Beitrag #11
RE: RS485 Modbus lesen und Ladegerät regeln
Gib doch mal am Anfang im Setup einfach "Start\n" auf den Seriellen Monitor, um zu cheken, ob die Baudrate stimmt.
Wenn die stimmt und die blöden Zeichen kommen vom Modbus, dann gib sie mal HEX oder BIN aus. Evtl. siehst Du da etwas.

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
22.06.2017, 20:11
Beitrag #12
RE: RS485 Modbus lesen und Ladegerät regeln
(22.06.2017 19:58)Tommy56 schrieb:  Gib doch mal am Anfang im Setup einfach "Start\n" auf den Seriellen Monitor, um zu cheken, ob die Baudrate stimmt.
Wenn die stimmt und die blöden Zeichen kommen vom Modbus, dann gib sie mal HEX oder BIN aus. Evtl. siehst Du da etwas.

Gruß Tommy

Wo/wie kann ich Hex /Bin einstellen?

Gruß
Thomas
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
22.06.2017, 20:26
Beitrag #13
RE: RS485 Modbus lesen und Ladegerät regeln
(22.06.2017 20:11)Stromsparer schrieb:  
(22.06.2017 19:58)Tommy56 schrieb:  Gib doch mal am Anfang im Setup einfach "Start\n" auf den Seriellen Monitor, um zu cheken, ob die Baudrate stimmt.
Wenn die stimmt und die blöden Zeichen kommen vom Modbus, dann gib sie mal HEX oder BIN aus. Evtl. siehst Du da etwas.

Gruß Tommy

Wo/wie kann ich Hex /Bin einstellen?

Gruß
Thomas
Serial.print(wert,HEX); oder anstelle von HEX BIN

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
23.06.2017, 14:08
Beitrag #14
RE: RS485 Modbus lesen und Ladegerät regeln
Ups,

da bin ich als Anfänger wohl doch etwas zu sorglos an die Sache gegangen.
Hatte einfach nur den Serila Monitor geöffnet, und dachte ich bekomme jetzt alles zu sehen was über den Modbus rüberkommt.

Ok, dann muss ich jetzt Serial.print(wert,HEX); und als wert gebe ich dann "telegram.u16CoilsNo"? oder was muss ich da einsetzen?

Gruß
Thomas
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
23.06.2017, 14:29
Beitrag #15
RE: RS485 Modbus lesen und Ladegerät regeln
Du musst als wert das einsetzen, was Du vorher ausgegeben hast, als Du die Kästchen gesehen hast.
Ich sehe in Deinem Loop nichts, wo Du Daten vom Modbus empfängst. Soll das so sein? Weil Daten, die Du sendest musst Du ja nicht anzeigen, die hast Du ja selbst gefüllt. Wo eigentlich?

Du hast im Loop die Zustände 0 = warten, 1 = senden und 2 = pollen, ob was da ist. Wenn da was da ist, wertest Du es aber anscheinend nicht aus. Oder habe ich da was übersehen?

Ich habe von Modbus keine Ahnung, ich brauche es ja auch nicht, aber in Deinem Loop kommt mir doch einiges seltsam vor.

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  POP 3 Mails lesen Agotto 1 255 19.02.2017 14:44
Letzter Beitrag: rkuehle
  RS485 Kollisionserkennung BennIY 0 365 08.09.2016 00:33
Letzter Beitrag: BennIY
  Ins eeprom schreiben/lesen anwo 10 2.365 07.02.2016 20:05
Letzter Beitrag: rpt007
  Pro Mini ADC Kanal 8 lesen Bitklopfer 8 862 30.12.2015 20:27
Letzter Beitrag: Bitklopfer
  Modbus Siemens Sinamics V20 Diggsn 3 866 17.09.2015 11:41
Letzter Beitrag: Scherheinz
  Variablen Typ double, char, long aus ext. EEPROM lesen SternGucker 8 1.894 02.04.2015 08:10
Letzter Beitrag: SternGucker
  Adafruit - Neopixel - wie Helligkeit regeln? MaHa1976 8 3.190 26.03.2015 20:26
Letzter Beitrag: MaHa1976
  Daten von File auf SD Card (formatiert) schreiben+lesen u.a.m. HaWe 19 4.992 16.02.2015 19:50
Letzter Beitrag: HaWe
  Serielle Schnittstelle lesen - merkwürdiges Problem Waishon 6 2.307 16.12.2014 08:47
Letzter Beitrag: Corvus
  Flash: schnelles Speichern und Lesen "großer" 1-2-dim Arrays und Structures? HaWe 37 7.030 30.11.2014 18:40
Letzter Beitrag: HaWe

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste