Shop OBEX P1 Docs P2 Docs Learn Events
Modbus — Parallax Forums

Modbus

Jon KeinathJon Keinath Posts: 146
edited 2006-03-31 15:19 in General Discussion
Has anyone been able to connect the Javelin (or BASIC Stamp) to a Modbus network (Javelin to Modicon 984 is my goal)? I just want to ask before I attempt it on my own. I don't want to reinvent the wheel if somebody already has.

Thanks,
Jon

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-29 14:53
    I have not seen such a class or bs2 program.
    I do have a modbus specification reference
    http://forums.parallax.com/attachment.php?attachmentid=37327

    regards peter
    ·
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-29 15:58
    Here is a c++ example (open with notedpad) that at least shows how to calculate crc
    and extract data from modbus messages.
    regards peter
  • Jon KeinathJon Keinath Posts: 146
    edited 2006-03-29 18:07
    Thanks Peter,

    I have a question on the CRC routine,
    C++Code (note i's converted to ii's for forum):
    INPUTS:
            buf   -> Array containing message to be sent to controller.
            start -> Start of loop in crc counter, usually 0.
            cnt   -> Amount of bytes in message being sent to controller.
    OUTPUTS:
            temp  -> Return crc byte for message.
    COMMENTS:
            This routine receives the data message to be sent down to the controller
    int crc(char buf[noparse][[/noparse]], int start, int cnt)
      {
      int ii,j;
      int temp, temp2, flag;
      temp=0xFFFF;
      for (ii=start; ii<cnt; ii++){
        temp=temp ^ buf[noparse][[/noparse]ii];
        for (j=1; j<=8; j++){
          flag=temp & 0x0001;
          temp=temp >> 1;
        if (flag) temp=temp ^ 0xA001;
        }
       }
       //Reverse byte order
       temp2=temp >> 8;
       temp= (temp << 8) | temp2;
       return(temp);
      */
    
    

    My converted Javelin Code:
    static int temp,flag,temp2; 
    ...  
    public static int crc(int buf[noparse][[/noparse]],int start)
        {
        for (int ii = start;ii<data.length;i++)
          {
          temp = temp ^ buf[noparse][[/noparse]ii];
          for (int j=1;j<=8;j++)
            {
            flag=temp&0x0001;
            temp=temp>>1;
            if (flag)
              {
              temp=temp^0xA001;
              }
            }
          }
        temp2 = temp >> 8;
        temp = (temp << 8) | temp2;
        return (temp);
        }
    }
    


    In my code the if (flag) gives me an error (not boolean), and having never used C++, I don't know how C++ Evaluates an if statement that has an int for an argument.
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-29 18:37
    In C and C++ a non-zero value equals true, a zero value equals false.

    So C++ if (value) { }
    becomes java if (value != 0) { }

    also, if (!value) { }

    becomes if (value == 0) { }



    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-29 18:49
    Few remarks,
    you use an int array where the original code uses char array (param buf)
    also for reversing the bits, I suggest you use >>> instead of >>
    The >> does sign extend (leaves b15 intact) whereas >>> clears b15
    I believe the c++ >> acts like >>>

    You don't pass the number of bytes in buf that make up the message,
    so the buf size must always equal messagesize.·That works only if
    all messages are equal size.

    regards peter




    Post Edited (Peter Verkaik) : 3/29/2006 6:52:48 PM GMT
  • Jon KeinathJon Keinath Posts: 146
    edited 2006-03-30 03:14
    Thank you so much for your help Peter.

    I have been able to get the CRC to calculate, and a simple query and return of the coils 00001 --> 00100
    I will definitely post the finished code when I get it all completed.



    Thanks Again
    -Jon
  • Jon KeinathJon Keinath Posts: 146
    edited 2006-03-31 02:41
    I have been able to get everything to work so far, except for the force coil on command.

    I think it has something to do with having to send a 0xFF, it either messes up my CRC calculator or ends up sending a 0xFFFF, which throws the byte count off. I assume this is the problem because I get no data reply or action from the modicon. Also a print out or debug value of my char buffer shows 0xFFFF when it should show 0xFF. I know they are both -1, but they are definitely not the same unsigned.

    I could do a force multiple coils after reading the previous state of coils and changing the one i want to change and then re-outputting it, but this seems rather difficult. Especially if I am just missing something in trying to send an 0xFF.

    I am attaching my code if anyone wants to take a look at it and offer suggestions.
    Modbus is the object and ModbusTest is my driver to test it.

    Thanks for your time,
    -Jon Keinath
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-31 04:04
    I think the (byte)buf[noparse][[/noparse]i] messes up your crc.
    Try this

    · //Calculate and the CRC.
    · private static int crc(char buf[noparse]/noparse,int start,int length)
    ··· {
    ··· temp=(short)0xFFFF;
    ··· for (int i = 0;i<length;i++)
    ····· {
    ····· temp = temp ^ (buf[noparse][[/noparse]i]&0xFF);
    ····· for (int j=1;j<=8;j++)
    ······· {
    ······· flag=temp & 0x0001;
    ······· temp=temp>>>1;
    ······· if (flag !=0)
    ········· {
    ········· temp = temp^(short)0xA001;
    ········· }
    ······· }
    ····· }
    ··· temp2 = temp >>> 8;
    ··· temp = (temp << 8) | temp2;
    ··· return (temp);
    ··· }

    regards peter
    ·
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-31 05:20
    I updated your files a little.
    You defined some methods static but that is not necessary.
    Also you defined character arrays inside send(), that leads to
    outofmemory error if send() is called frequently.
    I added an address parameter to the public methods.

    regards peter

    Post Edited (Peter Verkaik) : 3/31/2006 5:36:35 AM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-31 05:30
    In your test class

    ····· case 'c':
    ······· System.out.println("Register Number:?");
    ······· Terminal.getString(line,6); //read up to 6 chars from terminal
    ······· junk = Format.bscanf(line,0," %d",intin); //read int value skipping any leading whitespace
    ······· System.out.println("Register Value:?");
    ······· Terminal.getString(line,6); //read up to 6 chars from terminal
    ······· Format.bscanf(line,0," %d",intin); //read int value skipping any leading whitespace
    ······· M.setReg(0x01,junk,intin[noparse][[/noparse]0]);

    junk is not the entered register number but the number of bytes bscanf scanned.

    I think you need this

    ····· case 'c':
    ······· System.out.println("Register Number:?");
    ······· Terminal.getString(line,6); //read up to 6 chars from terminal
    ········Format.bscanf(line,0," %d",intin); //read int value skipping any leading whitespace
    ······· junk = intin[noparse][[/noparse]0];
    ······· System.out.println("Register Value:?");
    ······· Terminal.getString(line,6); //read up to 6 chars from terminal
    ······· Format.bscanf(line,0," %d",intin); //read int value skipping any leading whitespace
    ······· M.setReg(0x01,junk,intin[noparse][[/noparse]0]);

    regards peter



    Post Edited (Peter Verkaik) : 3/31/2006 5:37:34 AM GMT
  • Jon KeinathJon Keinath Posts: 146
    edited 2006-03-31 14:12
    Thanks again for all your help, it works great now.

    -Jon
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-03-31 15:19
    I converted your class into a package
    (stamp.protocol.modbus)
    and also passed the modbus device address to the constructor.
    That is the best way to define a modbus device.
    Modbus devices are now just accessed by name, no need to
    pass device address to any method.

    What you need to check is the reply you receive.
    You use
    · while (rx.byteAvailable())

    but what if the last byte is delayed for some reason?
    Check for reply completeness by counting the number
    of bytes received (if that is known for any command)
    or check for end of message marker.
    I have not studied the modbus protocol but since it
    is an acknowledge protocol there·must be a way
    for you to tell if a reply is completely received.
    While not completely received, you should wait
    until some timeout value. That will turn your class
    into a foolproof class.

    regards peter






    Post Edited (Peter Verkaik) : 3/31/2006 3:23:16 PM GMT
Sign In or Register to comment.