Decoding serial port data

Dear sirs,
A bit of a tricky one this (for me anyway).

I am reading data from a weather station through the serial port which is arriving as a string of characters.

I need to be able to decode this data but have no idea where to start as there is no official instructions.  I managed to dig up some help but I have no idea what the heck they are talking about, hence my post.

Their instructions are:

Data is sent simplex from the weather station via an RS 232 interface to the PC

The frame format is as follows, the length being implied by the Code value:
Start Start Code Channel Data Checksum

Start 0xFF
Code 0x00 - 0x0F
Channel 0x00 in most cases, but with specific uses as follows:

The first hex digit indicates the battery status (where relevant). The second hex digit indicates the channel number (where relevant).

For the Clock Minute message this byte indicates the number of minutes.

Add all bytes arithmetically, including the Code byte but excluding the Start bytes and the Checksum byte. Subtract 2 and take the bottom 7 bits to get the correct checksum.

Number Formats
Numbers are represented in BCD, except for ambient pressure which is in binary. The digits come in a variety of orders. The topmost quartet is set to 0x8 for a negative number (temperature, wind chill). For example:

0x18 - 18 as an hour (6 PM)
0x1703 - 31.7 degrees as a temperature
0x3582 -23.5 degrees as a temperature
0x8015 -15 degrees as a wind chill.

Does anyone have any idea what they are talking about?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

To decode the data, you need to do the following:

1. Locate the beginning of a frame by reading bytes until you encounter the bytes 0xFF 0xFF.
2. The next byte is the code byte, which can take values between 0x00 and 0x0F. I understand this represents the type of data sent in the frame, which also implies the frame length. You should have a list of frame types, and their corresponding lengths.
3. You read the channel byte (I don't know how you will be using it).
4. Read data byte(s) (I assume you already know the data length from the code byte).

Data should be parsed as follows:

All values (except for ambient pressure) are represented in BCD format. Converting BCD to decimal is quite easy; if the data is contained in a single byte (as in the case of the hour byte in the example you posted), each hexadecimal digit represents a corresponding decimal digit (values cannot exceed 9). For example:

0x18 is decoded to the decimal value 18

Values contained in two bytes as in temp. and wind chill are converted to decimal by first swapping the data bytes, and then converting the first digit to a sign (0 means +, while 8 means -). For example:

To convert 0x1703 to a temperature value, first swap the bytes. Now we have 0x0317. Next, remove the zero on the left (the value is positive), and place a decimal point where appropriate (I guess here you have only one decimal place). The value becomes 31.7 degrees :-)

To convert 0x3582, you again swap the bytes. Now you have 0x8235, which stands for -23.5.

Finally, to convert ambient pressure values, you simply read the data into an integer (or any numeric variable that will hold the value read), and then directly use it. Bytes read this way will be correctly converted to the corresponding decimal value.


  Nayer Naguib

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Sorry, forgot about the checksum. You add the values of all frame bytes (excluding the two Start bytes and, *of course*, the checksum byte, which we are still calculating!) and store the sum in a variable. Next, you subtract 2 from the sum. Next, AND the result with 0x7F (to exclude the eighth bytes as instructed), and compare the value with the checksum byte received (to check the integrity of the data received). If both values match, then you have received the data correctly.
Now you are ready to read a new frame :-)


  Nayer Naguib
watersidedesignsAuthor Commented:
Thanks Nayer for your quick response.

Please forgive me as I am very very new to coms  :)

First I presume that to get the hex you can use hex(asc(character)) so when i am looking for a start of frame i am looking for two chr(255)'s together?

Is that right ?
Exactly! However, if you are reading characters, and you want to check for Start bytes using Chr(255), then you cannot compare this to the hexadecinal value returned by Hex(255), nor to the value returned by something like Hex(Asc(Chr(255))). You need to directly compare Chr(255) to the value of the character read from the input data stream.

Chr(x) returns the character corresponding to the number x from the ASCII table. However, Hex(x) returns the hexadecimal representation of number x.
Example: Chr(65)="A", while Hex(65)=41


  Nayer Naguib
watersidedesignsAuthor Commented:
That's really helped.  Thanks Nayer
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.