problem decoding serial port data w/ VDT2
jipi
I'm having troubles trying to read out data from a temperature measuring and logging device called "Voltcraft 306" via the serial port RS-232. I managed to establish the connection on COM1 and communicate, i.e. send a command "K" asking for the device number and receiving "306". The problem I have now, is getting the data of interest, namely the actual temperature: I'm sending a command "A" and expect an answer consisting of 10 encoded bytes. Now, how can I decode them?!
For example i get "Àª≤v¿ˇ≤v"
My igor code is like this (string or binary readout deliver the same result):
Function rs_init() // Initialize serial port
VDT2/P=COM1 baud=9600,stopbits=1,databits=8,parity=0,in=0,echo=0,buffer=4096
VDTOpenPort2 COM1 //Opens the named port, preparing it for use
VDTOperationsPort2 COM1 //Designates a port as the port to use for command line operations
VDT2 KillIO //Clear serial port
Print "COM1 initialized"
End
Function rs_send(cmd) // sends a command to the device
String cmd
VDT2 KillIO // clear port prior to use
VDTWrite2 /O=3 cmd + "\r\n" // send the command
End
Function/S rs_readstr() // reads out the string response frome the device
String response
//VDTRead2 /O=1/T="\r\n" response
VDTRead2 /N=10 /O=3 /T="\r\n" response // max 10 characters readout; timeout set to 3s
print "answer from device: " + response
return response
End
Function/S rs_readbin() // reads out the binary response frome the device
String response
VDTReadBinary2 /TYPE=(0x10) /S=10 /O=3 response
print response
return response
End
Function/S rs_query(cmd) // send cmd and return the response
String cmd
rs_send(cmd)
return rs_readstr()
End
VDT2/P=COM1 baud=9600,stopbits=1,databits=8,parity=0,in=0,echo=0,buffer=4096
VDTOpenPort2 COM1 //Opens the named port, preparing it for use
VDTOperationsPort2 COM1 //Designates a port as the port to use for command line operations
VDT2 KillIO //Clear serial port
Print "COM1 initialized"
End
Function rs_send(cmd) // sends a command to the device
String cmd
VDT2 KillIO // clear port prior to use
VDTWrite2 /O=3 cmd + "\r\n" // send the command
End
Function/S rs_readstr() // reads out the string response frome the device
String response
//VDTRead2 /O=1/T="\r\n" response
VDTRead2 /N=10 /O=3 /T="\r\n" response // max 10 characters readout; timeout set to 3s
print "answer from device: " + response
return response
End
Function/S rs_readbin() // reads out the binary response frome the device
String response
VDTReadBinary2 /TYPE=(0x10) /S=10 /O=3 response
print response
return response
End
Function/S rs_query(cmd) // send cmd and return the response
String cmd
rs_send(cmd)
return rs_readstr()
End
Thank you very much for your help!
Below you can see what the "A" command is supposed to deliver, taken out of the datasheet:
Command A:
1st BYTE:
The first byte is the start byte, its value is 2.
2nd BYTE:
bit7 Temperature Unit: 1->°C 0->°F
bit6 Battery Condition: 1->Low Battery 0->Battery normal
bit5 Hold: 1->Hold 0->not Hold
bit4 -- no use --
bit3 TIME/Temperature Data in Bytes 6-9: 1->Indicates the LCD is displaying time
bit2/bit1 MAX/MIN Mode
0 0 normal mode
0 1 MAXIMUN mode
1 0 MINIMUN mode
1 1 calculate MAX/MIN in background mode .
bit0 REC (1->recording mode, 0->not recording)
3rd BYTE:
bit0: T1 1->T1 is OL, 0->not OL (1)
bit1: T1 sign 1->T1 value is minus, 0-> value is plus.
bit2: T1 1->4th byte and 5th byte represent #### , 0->4th byte and 5th byte represent ###.#
bit3: T2 1->T2 is OL, 0->not OL (1)
bit4: T2 sign 1-> value is minus, 0-> value is plus.
bit5: T2 1->8th byte and 9th byte represent #### , 0->8th byte and 9th byte represent ###.#
bit6: 1->Memory is full. 0->Memory is not full.
bit7: 1->Auto power off enabled. 0->Auto power off disabled.
4th BYTE:
first two BCD code of T1 value.
5th BYTE:
last two BCD code of T1 value
6th BYTE:
If bit3 of 2nd BYTE =0 : first two BCD code of T1-T2 value.
If bit3 of 2nd BYTE =1 : two BCD code of month.
7th BYTE:
If bit3 of 2nd BYTE =0 : last two BCD code of T1-T2 value.
If bit3 of 2nd BYTE =1 : two BCD code of day.
8th BYTE:
If bit3 of 2nd BYTE =0 : first two BCD code of T2 value.
If bit3 of 2nd BYTE =1 : two BCD code of hour.
9th BYTE:
If bit3 of 2nd BYTE =0 : last two BCD code of T2 value.
If bit3 of 2nd BYTE =1 : two BCD code of minute.
10th BYTE:
end byte, its value is 3, 1st and 10th are used to check frame error.
String response // 10 byte response from instrument
Variable bit6Mask = 2^6 // Used for bit testing
Variable first = char2num(response[0]) & 0xFF
if (first != 2)
Print "Error: First byte expected to be 2"
return -1
endif
Variable second = char2num(response[1]) & 0xFF
if (second & bit6Mask)
Print "Low battery"
else
Print "Normal battery"
endif
return 0 // Success
End
November 8, 2012 at 11:44 am - Permalink
My remaining problem is now the temperature values themselves: They are - according to the manual - BCD coded (=binary coded decimal) and I just can't figure out how to decode them into decimals. The should be as follows:
4th BYTE: first two BCD code of T1 value 5th BYTE: last two BCD code of T1 value
So I'm expecting a value like ###.# °C as the other bytes tell me. I did an example measurement where I found that
4th BYTE: "11011101"
5th BYTE: "10101110"
should be -07.20 °C
I thought I have to split it up like this: "1101 1101 1010 1110" and then convert each 4bits into one digit. Am I wrong with this? Because the "1101" 4-bits are eleven in my calculation (1+2+0+8) , what can't be right in a decimal system ;)
I really hope you can help me again, greetings from munich!
November 30, 2012 at 11:21 am - Permalink
This is correct so that means that your byte values are incorrect. I don't have an answer for that.
I would start by printing each of the byte values you read in hex:
Compare what you get to the documentation for the meaning of the byte values. If all of your other byte values make sense then you can presume that you are reading the data correctly and you then might ask the instrument manufacturer why these don't.
If the other byte values don't make sense then there is something wrong with the way you are reading the bytes or with the way you are extracting them from the Igor string, if that is how you are doing it.
Once you get the correct bytes, here is how you can convert from BCD to binary:
Variable fourthByte = 0x07
Variable fifthByte = 0x20
Variable value, digit
digit = (fourthByte & 0xF0) / 16 // Zero
value = digit
digit = (fourthByte & 0x0F) // Seven
value = 10* value + digit
digit = (fifthByte & 0xF0) / 16 // Two
value = 10* value + digit
digit = (fifthByte & 0x0F) // Zero
value = 10* value + digit
Print value
End
November 30, 2012 at 11:46 am - Permalink