Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Trying to convert a byte array to a number

Options
  • 08-04-2010 3:42pm
    #1
    Registered Users Posts: 1,825 ✭✭✭


    I have a project I am working on that requires retrieving data from a modbus compatible device.

    I have managed to send a request and receive a result but it's the conversion that I am having trouble with. I get this set of byte arrays:

    48 48 177 57
    48 48 48 51
    48 48 48 177
    48 48 48 178
    48 48 177 57
    48 48 48 180
    48 48 48 53
    48 48 48 54

    and I know that the numbers equate to:
    25
    3
    1
    2
    25
    4
    5
    6

    But I can't for the life of me figure out how to convert from 48 48 48 51 to 3!

    This is my first time playing with converting bytes to integers so I am completely lost and anything I can find seems to give me totally different numbers so I think I must be missing something extremely stupid!

    Any help much appreciated


Comments

  • Registered Users Posts: 1,916 ✭✭✭ronivek


    Well it looks like they're ASCII representations; but that would make a number of the values nonsensical; i.e. 48 is a '0' in ASCII but 177 is a whitespace type symbol.

    Do you have any specific documentation relating to the protocol being used? How are you reading the data?


  • Registered Users Posts: 1,825 ✭✭✭Gambler


    Here's what the manual has to say on the subject:
    The read frame to be sent to the controller is the following:

    Start delimiter: " : "
    Slave address: 0x04
    Read command: 0x03
    Data address: 0x00 00 FF xx
    xx is a number between 0x00 and 0x2F inclusive, corresponding to the address of the first data item
    to be read less 1.
    Number of bytes: 0xnn
    This is the number of data items to be read. Each value is made up of two bytes.
    Checksum: 0xcc
    This is the complementary sum increased by 1, of the bytes between the slave address and the
    number of bytes.
    End delimiter: " CR " " LF "

    The controller response is structured as follows:

    Start delimiter: " : "
    Slave address: 0x04
    Read command: 0x03
    Number of bytes: 0xnn
    Data read: 0xd1H d1L d2H ... dnnL
    There are 0xnn bytes to be read.
    Checksum: 0xcc
    This is the complementary sum increased by 1, of the bytes between the slave address and the last
    of the data items to be read.
    End delimiter: " CR " " LF "

    Example:

    Read 5 16-bit data items from address 17:
    Hexadecimal frame before ASCII coding:
    " : " 04 03 00 00 FF 10 0A E0 " CR " " LF "

    Hexadecimal frame after ASCII coding:
    3A 30 34 30 33 30 30 30 30 46 46 31 30 30 41 45 30 0D 0A

    The response will be if the five values equal 0:
    3A 30 34 30 33 30 41 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 45 46 0D 0A
    Now that I look at it 48 is the Decimal for 30 in Hex so maybe I should translate my original input for the number 25 to this?:

    30 30 B1 39

    Still not sure how that is supposed to work out to be honest.. Each block has a range of -32767 to 32767 if that makes any difference..


  • Closed Accounts Posts: 7,145 ✭✭✭DonkeyStyle \o/


    Uhm, ok... think I've got something.
    If you break those numbers down to binary, you've got:
    00110000  00110000  10110001  00111001 = 25
    00110000  00110000  00110000  00110011 = 3
    00110000  00110000  00110000  10110001 = 1
    00110000  00110000  00110000  10110010 = 2
    00110000  00110000  00110000  10110100 = 4
    00110000  00110000  00110000  00110101 = 5
    00110000  00110000  00110000  00110110 = 6
    
    If you look at the last 4 bits of each line, they add up to the right number... except for 25, which needs a 5th bit to make the number 25.
    I've been scratching my head to figure out where this bit comes from, so here's how I think it looks... 8 bits, the most significant bit is a parity bit marked in blue... the bold bits join together to form 8 bits that sum to the result number.
    [edit] Actually... they probably all join up... in 16 bits, giving you unsigned 65,535 or a range equal to -32767 to 32767 as you said.
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]1[/COLOR]011 [B]0001[/B]  [COLOR="Blue"]0[/COLOR]011 [B]1001[/B] = 25
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]0[/COLOR]011 [B]0011[/B] = 3
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]1[/COLOR]011 [B]0001[/B] = 1
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]1[/COLOR]011 [B]0010[/B] = 2
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]1[/COLOR]011 [B]0100[/B] = 4
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]0[/COLOR]011 [B]0101[/B] = 5
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]0[/COLOR]011 [B]0110[/B] = 6
    
    Can't figure out what the 0011 part is... but it seems to repeat regardless.
    Maybe I'm way off I dunno :D


  • Registered Users Posts: 1,825 ✭✭✭Gambler


    Oh an I am getting the data with this code using the Serialport Datareceived event:
    For i As Integer = 1 To Me.SerialPort1.BytesToRead

    Outputstring = Outputstring & Me.SerialPort1.ReadByte & " "

    Next
    This gives me this output:
    "58 48 180 48 51 177 48 48 48 48 177 48 48 48 178 48 48 48 51 48 48 48 180 48 48 48 53 48 48 48 54 48 48 48 65 48 48 48 57 195 177 141 10 "
    And when I dig through it I have figured out that the relevant sections (and the numbers they represent) are:
    48 48 48 177 - 1
    48 48 48 178 - 2
    48 48 48 51 - 3
    48 48 48 180 - 4
    48 48 48 53 - 5
    48 48 48 54 - 6
    48 48 48 65 - 10
    48 48 48 57 - 9


  • Registered Users Posts: 1,825 ✭✭✭Gambler


    Uhm, ok... think I've got something.
    If you break those numbers down to binary, you've got:
    00110000  00110000  10110001  00111001 = 25
    00110000  00110000  00110000  00110011 = 3
    00110000  00110000  00110000  10110001 = 1
    00110000  00110000  00110000  10110010 = 2
    00110000  00110000  00110000  10110100 = 4
    00110000  00110000  00110000  00110101 = 5
    00110000  00110000  00110000  00110110 = 6
    
    If you look at the last 4 bits of each line, they add up to the right number... except for 25, which needs a 5th bit to make the number 25.
    I've been scratching my head to figure out where this bit comes from, so here's how I think it looks... 8 bits, the most significant bit is a parity bit marked in blue... the bold bits join together to form 8 bits that sum to the result number.
    [edit] Actually... they probably all join up... in 16 bits, giving you unsigned 65,535 or a range equal to -32767 to 32767 as you said.
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]1[/COLOR]011 [B]0001[/B]  [COLOR="Blue"]0[/COLOR]011 [B]1001[/B] = 25
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]0[/COLOR]011 [B]0011[/B] = 3
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]1[/COLOR]011 [B]0001[/B] = 1
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]1[/COLOR]011 [B]0010[/B] = 2
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]1[/COLOR]011 [B]0100[/B] = 4
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]0[/COLOR]011 [B]0101[/B] = 5
    [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 0000  [COLOR="Blue"]0[/COLOR]011 [B]0000[/B]  [COLOR="Blue"]0[/COLOR]011 [B]0110[/B] = 6
    
    Can't figure out what the 0011 part is... but it seems to repeat regardless.
    Maybe I'm way off I dunno :D

    Ahhh ok, so I need to convert via Binary then? Will have a play with that now :) Thanks!


  • Advertisement
  • Closed Accounts Posts: 7,145 ✭✭✭DonkeyStyle \o/


    Gambler wrote: »
    Ahhh ok, so I need to convert via Binary then? Will have a play with that now :) Thanks!
    Well it seems to make sense in binary... and I think what I've come up with is consistent based on the known numbers... but I could be missing something else... it seems like a promising enough starting point though.


  • Registered Users Posts: 1,825 ✭✭✭Gambler


    OK, I get the basics of binary (.i.e. 11001 = 25 because 1 + 8 + 16 = 25, At least I hope I got that bit right!!) but I'm having trouble getting my head around this part of your post:
    I've been scratching my head to figure out where this bit comes from, so here's how I think it looks... 8 bits, the most significant bit is a parity bit marked in blue... the bold bits join together to form 8 bits that sum to the result number.
    [edit] Actually... they probably all join up... in 16 bits, giving you unsigned 65,535 or a range equal to -32767 to 32767 as you said.
    I'm not sure how the numbers give me 16 bits with the range equal to -32767 to 32767. Again I am sure I'm missing something basic here..


  • Closed Accounts Posts: 7,145 ✭✭✭DonkeyStyle \o/


    Gambler wrote: »
    I'm not sure how the numbers give me 16 bits with the range equal to -32767 to 32767. Again I am sure I'm missing something basic here..
    00110000 00110000 10110001 00111001 = 25
    0000 0000 0001 1001 = 25
    0000000000011001 = 25
    If you keep working your way up that last number from right to left, the numbers each bit represents keeps rising... if all 16 of these bits were 1's, the total number would be 65,535.
    With this length of binary, you can express any number between 0 and 65,535.
    But if you wanted to represent a negative value, say -5,000 you have to change the range, because there are only 65k possible numbers and if you start from 0, you can't say -5,000, the positive numbers you can represent have to shrink so the range becomes -32,767 to 0 and 0 to 32,767.
    The sign bit is usually the most significant bit, (left most in this case).
    Since that left-most bit is worth 32,768 and is now gone, it can't be added to the rest to make 65535, so you get left with (15 bits) that 32,767 figure which you can make positive or negative using the 16th bit.

    What I don't get is why the initial bytes break in two like that... maybe it's that 0x03 read command... which is also carrying a parity bit?! Just a theory anyway.

    Phew, all this computer hacking is making me thirsty, think I'll order a tab. :pac:


  • Registered Users Posts: 1,825 ✭✭✭Gambler


    Ahhhhhhhhh now I get what you are saying.. Will have a play with it and see what sort of results I get now :)


  • Registered Users Posts: 1,825 ✭✭✭Gambler


    Thanks for the help, I've written a quick test function and it looks like this will work perfectly! I just need to do a couple of tests on a range of numbers between 0 and 32K but I think I've got it sorted now :D


  • Advertisement
  • Closed Accounts Posts: 7,145 ✭✭✭DonkeyStyle \o/


    *nerd high-five* :pac:


  • Moderators, Category Moderators, Entertainment Moderators, Sports Moderators Posts: 22,584 CMod ✭✭✭✭Steve


    Gambler wrote: »
    For i As Integer = 1 To Me.SerialPort1.BytesToRead
    
      Outputstring = Outputstring & Me.SerialPort1.ReadByte & " "
    
    Next                      
    
    As you're dealing with binary data, reading it in to a string probably isn't the best way to handle it - VB will try to interpret the values into characters.

    Why not read the data directly into a byte array and therefore have direct control over it?

    Something like:
    Dim Mydata As New List(Of Byte)
            For i As Integer = 1 To Me.SerialPort1.BytesToRead
                Mydata.Add(Me.SerialPort1.ReadByte)
            Next
            For Each tmpByte As Byte In Mydata
                'process the data
            Next
    


Advertisement