Instrument Control (GPIB, Serial, VISA, IVI)

cancel
Showing results for 
Search instead for 
Did you mean: 

How LV handles sending of serial communiation bytes?

Hi!,

I have some questions regarding the manner in which LV performs serial communication. My questions are:

1) Does LV convert my Hex into Binary or do I need to feed Binary string to the write vi?

2) Do I feed the complete message frame (Device Address + Function + Register Address + Data + CRC) as one string? If yes, then should each byte be separated by space or comma? If no, then am I to write each byte separately using the write vi in a loop?

3) Does LV attach the necessary start and stop bits (as per my port config) with the string to be written? Will it do this for each field and the message?

4) Does LV ensure that the LSB is transmitted before the MSB?

Thanks and Best regards,
Gurdas


www.qagetech.com
Gurdas Sandhu, Ph.D.
ORISE Research Fellow at US EPA
0 Kudos
Message 1 of 15
(4,517 Views)
Hi Gurdas,

Start by looking at the example that can be found at

Help >>> Search Examples >>> Browse >>> Hardware Input and Output >>> Serial >>> Serial Communications.VI


Re: yopur questions:
1) Does LV convert my Hex into Binary or do I need to feed Binary string to the write vi?
Hex and binary (and strings) are just methods of dispalying data. In the example I cited, the transmit and recieve data is represented as strings. You can right-click on these control or indicators and choose "hex Display" if you want to see the data as hex. You could also type cast the string to an array of bytes if you like that more.




2) Do I feed the complete message frame (Device Address + Function + Register Address + Data + CRC) as one string? If yes, then
should each byte be separated by space or comma? If no, then am I to write each byte separately using the write vi in a loop?
Yes! Wht you send is what the serial port transmits UNLESS you have termination characters enabled for the serial port. These are manipulated in the config (see the example).


3) Does LV attach the necessary start and stop bits (as per my port config) with the string to be written? Will it do this for each field and the message?
Start and stop bits are handled by the hardware and are dependent on how the port is configured (see example).


4) Does LV ensure that the LSB is transmitted before the MSB?

Are you asking bits or bytes?
It has been years since I read data off a serial line using a scope, but I seem to remeber that the MSBit went first. THe bits were just clocked in and up-shifted with each bit cel time.

If you are asking bytes, then LV transmits in the order you deliver the data to the port. Swap Bytes and Swap Words (under Advanced >>
> Data manipulation) can be used to re-aranged things if required.

I hope this helps,

Ben
Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 2 of 15
(4,517 Views)
NOTE:

Do NOT make changes to your example!

Do a "save as" and check the "do update callers" before saving as a unique name.

THEN,

Open your new VI (saved previously) and work with that.

Ben
Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 3 of 15
(4,517 Views)
Hello Ben,

Thanks!
I am using 9600kbps, 8 bit data, no parity and 2 stop bits. No termination chars.

I need to rephrase some questions. Question numbers are in continuation.

1) I am still not clear what is sent across the serial port? The Modbus protocol talks of Hex. But they also keep talking of bits. So, if what I need to transmit is say "3BH", should I simply feed "3BH" to the write vi OR first convert this into binary (00111011)and then write?

2) Lets assume the message consists of 8 Bytes. Say "010410000001350A" in hex. How do I write this? One hex digit at a time OR one byte at a time OR one complete string with each byte separated by space OR something else?

3) and 4) seem to be answered.

5) How do I ensure I read only the latest
transmitted message?

6) Should my buffer size be equal to total number of bits in a message? Should I add start and stop bits when deciding buffer size?

7) Is there some way to trigger my read whenever the buffer is full? If I do this together with a tightly controlled buffer size, I might read only latest data.

😎 What happens to the data I have read? Does it get deleted from the buffer?

I guess most of my questions are kinda fundamental. I have read just about every piece of NI literature on the website but these questions remain unanswered.

Rgds,
Gurdas
Gurdas Sandhu, Ph.D.
ORISE Research Fellow at US EPA
0 Kudos
Message 4 of 15
(4,517 Views)
1) I am still not clear what is sent across the serial port? The Modbus protocol talks of Hex. But they also keep talking of bits. So, if what I need to transmit is say "3BH", should I simply feed "3BH" to the write vi OR first convert this into binary (00111011)and then write?
Go back to the example.
Right click on the string control and select "display Hex".
Enter 3B
right click again, slect normal display. You will now see a ";". Just wo different ways of displaying the same data.


2) Lets assume the message consists of 8 Bytes. Say "010410000001350A" in hex. How do I write this? One hex digit at a time OR one byte at a time OR one complete string with each byte separated by space OR something else?
Back to my example.
Diplay hex.

Enter the "010410000001350A".
THat is what will be transmitted.


3) and 4) seem to be answered.


5) How do I ensure I read only the latest transmitted message?
On the VISA serial palette thera is a flush buffer VI.
Also you could use a property node to determine how many bytes are waiting and then read that many. This will empty the buffer.
THen you can proceed.


6) Should my buffer size be equal to total number of bits in a message? Should I add start and stop bits when deciding buffer size?
Your buffer size is in bytes. The start and stop bits are stripped by the hardware. They are only used to frame the data bits while in transit.


7) Is there some way to trigger my read whenever the buffer is full? If I do this together with a tightly controlled buffer size, I might read only latest data.
If you purge your recieve buffer then you can just say read X bytes. When the data arives, your code will get that many bytes.


😎 What happens to the data I have read?
Does it get deleted from the buffer?
Yes. It exist only in the wire until you are done working with it.

Ben
Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 5 of 15
(4,517 Views)
Hello,

Here are answers to your questions:

1) and 2). All data is stored as 1s and 0s, how you choose to display the data in LabVIEW has no affect on what is sent. The string you define (the ASCII characters) is the string that will be sent regardless of whether you represent it in hex or the usual character display. For example, if you write "I love the serial port!" then the bytes corresponding to the characters in that string are send and can be read just as they were sent (you will need to include a termination character, either manually such as typing the enter key to use a linefeed [which is the usual default termination character], or programmatically by concatenating such a character at the end of your string. In general, a serial read function will complete when one of three things happen, whichever occurs first:

a. you receive a termination character and use of termination characters is enabled (regardless of how many bytes you specify to read)
b. you receive the number of bytes specified to read from the port
c. neither a. nor b. above occurs before the timeout period specified in the VISA Configure Serial Port VI.

3). The use of start and stop bits can be configured using the VISA Configure Serial Port VI, but their application is abstracted away from the user in LabVIEW; you don't have to worry about them, simply write and read strings as you'd like!

4). Serial transmission is performed LSB first.

That should set you in the right direction. As a first program, I would recommend simply using the VISA Configure Serial Port VI, VISA Write, VISA Read, and VISA Close in series in that order (connect the VISA resource reference and the error clusters), where in the configure VI you can specify a COM port as the VISA resource and the VI's default behavior is to use the linefeed termination character. Use a string control as the input to the VISA Write function and be sure to put a linefeed at the end of the string you write by typing enter. Then specify some large number of bytes to read, say 100, for the read function since the termination character you enter in your string will cause the read function to finish before waiting for 100 bytes. Use an indicator to indicate the read buffer (the string that the read function returns, which will be exactly what your wrote when you complete the direction in the next sentence). Then all you need to do is connect pins 2 and 3 of your DB 9 connector (these are the receive and transmit pins respectively) to write to and read from the same serial port (say COM1, which you specify in the configure VI). You will be all set to perform the what is known as a loopback test, and you will simply write to and then read from the same serial port.

Hope this helps!

JLS
Best,
JLS
Sixclear
Message 6 of 15
(4,519 Views)
JLS, Thanks!

Further to your answers:

1) OK

Do termination characters come into picture for both read and write? If my device does not send termination chars, then I guess they are no use while reading. Right?

2) Lets say my complete message frame (Device Address + Function + Register Address + Data + CRC) is "01 04 1000 0001 350A". Do I send it as "010410000001350A" OR "01" and then "04" ... (i.e. mutliple writing in a loop) OR some other way. In other words, if each byte(s) corresponds to some part of the message (like in my example 1000 means register address) then should all bytes be fused together or separated by something. I am refering to Modbus messaging here.

3) OK

4) Say I feed the hex string "0A" to my write vi. Will it be sent as "0A" with LCB before MSB for "0" and "A".
OR
will it be sent as "A0" with LSB before MSB for "A" and "0"?

5) My device is continuously firing bytes to my NI serial board. Say each message contains 8 bytes which I need to decode to make sense. My buffer is set to 64 bytes.
a) Does the data stay in the buffer until I read it? I understand it might get overwritten if not read before the end of buffer is reached.

b) My read vi is set to read 8 bytes. BUT, my program activates read.vi only once in a while. In this case, how do I read only the latest bytes? If I flush before I read, there might be nothing to read in the buffer because the device has not transmitted anything in that split second between flush and read.

c) How does the buffer receive bytes from the device? Say, for a 8 byte message, do all 8 bytes come in at a single shot? Or do they come in 1 byte at a time?

i) If they come in 8 bytes at a time, then is each 8 byte message separated by something in the buffer?

ii) If they come in 1 byte at a time, then is there a possibility I might read my 8 bytes such that they contain some bytes from the previous transmit and some from the recent?



I've been struggling to get my serial device to respond for 1 week now. I connected my PC to the serial board on my PXI chassis. I ran a write vi on PC and read vi on PXI chassis (system COM port on both ends). It worked. But only to the extent that out of 20 messages sent, only 8 to 10 were read. The messages which were read were complete.

Thanks for your time.

Rgds,
Gurdas

Gurdas Sandhu, Ph.D.
ORISE Research Fellow at US EPA
0 Kudos
Message 7 of 15
(4,518 Views)
Hello,

1). Termination characters are relevant for a read function in the sense that if your instrument appends a termination character to the strings it writes, then you can terminate your read function with that character by simply reading some number of bytes, say 100. That is, if you specify reading 100 bytes and you receive a termination character on the 30th byte, your will stop reading and not read another byte for that execution of the read function (if of course you have termination characters enabled). Termination characters are relevant for write operations in that if your instrument expects a termination character when it reads the serial port, you will have to include one in your write string. This is usually just a linefeed or carriage return character, and how your instrument communicates should be documented in the manual.

2). The format of the string that your instrument expects is completely dependent upon the instrument. You should be able to find a list of the command strings in the user manual; if not simply contact the manufacturer and they should be able to provide you with that information.

3). This one seemed to be ok in your response.

4). First, it is important to note that how you choose to define the string (hex or normal ascii display) will not affect what is sent (as long as you are defining the same string. For example, the ascii character '#' is represented in memory by a single byte (8 bits) which define the number 35 (decimal), which is equivalent to hex 23 and binary 00100011. The idea behind sending data LSB first refers to sending the least significant BIT first for a given byte. For the '#' character, this means that format of the frame of data (as it is often referred to as) will have the least significant bit sent first (the 1 on the right side of the binary representation in this case). It is VERY IMPORTANT TO NOTE that you need NOT be concerned with this when writing to and reading from the serial port. The UARTs (Universal Asynchronous Receive and Transmit) will take care of actually pulling in the frames, interpreting the data portion correctly, and putting it into memory for you (actually in most UARTs it gets put into a dedicated FIFO first, but don't worry about that either). All you have to do is use the read function and you will read in bytes just as they were sent!!! Now that we have clarified that a bit, let me answer the other part of your question which was effectively which byte gets sent first if you write a string of bytes. Suppose I write the string "I love the serial port!" to COM1 and read it into COM1 also (this can be done be performing a loopback test; simply connect pins 2 and 3 on the DB9 standard serial connector... these are the receive and transmit pins respectively). If I were to read only 1 byte, I would read in the 'I' byte. If I did not close the serial port, but read again 1 byte, I would read in the space character shown after the 'I' character. Basically, the first letter you type in your write string will be the first letter received when read back in by whatever port you are connected to. If initially you read 10 bytes, you would simply read the first 10 bytes of the string; in the above example this would be the string "I love the" where the white space characters are counted.

5). I think all of the items in question 5 can be addressed with the following:

If you are continuously being sent data, and receiving at your serial port, then you can continuously read that port and you will be returned the oldest data in the buffer. If you would like, you can read 1 byte at a time and you will always get 1 byte; if it makes sense to read 4 bytes at a time, you can do that. Essentially, the number of bytes you read from the buffer is arbitrary, and once the data has been read from the buffer by the read function it is no longer there. The example I gave above talked about reading 1 byte at a time and shows this idea. If you perform a read multiple times you will simply read data from the buffer in the order in which it was written to the buffer (ie. you will read starting from the beginning of the string). If multiple writes occur, the consecutive writes will simply add to the buffer, effectively concatenating consecutive writes to the end of what is already in the buffer. There will not be any separating characters unless those character are actually written into the write-string. There are some finer issues with how fast the read function will return with data dependent upon the read FIFO size on the UART (which can be set in software for most modern UARTs), but this will only affect read function return times on the order of a few milliseconds... you should not have to worry about this at all (it has to do with how many bytes are stored into UART FIFO memory before it interrupts the processor on your machine and actaully transfers those bytes into memory where your read function has access to reading them... the buffer referred to previously in this message has referred to the memory your read function reads from, and not the FIFOs mentioned here)!!! In general, you can put your read function in a loop, and continuously read data from memory, where again you will read the data in the order it was sent (see the above example).
Best,
JLS
Sixclear
0 Kudos
Message 8 of 15
(4,518 Views)
JLS, many thanks for your descriptive answer.

1,3, 4, 5a and 5ci) OK

2) I am refering particularly to Modbus. What bytes to send to my device is defined by the device manufacturer. They also specify the maximum inter-byte "quiet" period during transmission. But not the least. Does that mean my byte 1 and byte 2 can be sent as one stream of 16 bits OR do I need to forcibly insert some quiet period between them OR just inserting a space will do the job?

5b and 5cii)

Background: My actual setup involves measuring surface profile using laser sensors. The laser sensor is mounted onto a single axis stage with stepper motors and linear encoder. Laser sensor gives continuous RS422 output which I intend to read using my NI serial card. The linear encoder gives me a pulse for every 0.01mm movement of the stage (+laser sensor). My vi is programmed to read the laser data after every 5 pulses from the encoder (i.e every 50 microns).

Each message from the laser sensor is 4 bytes. Say my buffer is 128 bytes. My program cannot allow for continuous reading of the buffer for specific reasons. Now, there might be a situation that when the read vi gets activated (by the encoder pulse) there is 48 bytes of data in the buffer.

5b) How do I read only the latest 4 bytes? I cannot read all 48 and then pull the last 4 because there might not be sufficient time for this process.
NOTE: Suppose there is time to do this, and I have pulled all the data in the buffer into an array. Am I right is saying that the last four bytes (45 to 48) are the latest data (since it is FIFO) ?

5cii) This one is tricky. Continuing with the 4 bytes from sensor scheme. Lets say when my read vi got activated there were 46 bytes in the buffer. That is, only 2 bytes (out of 4) of the latest message from the sensor have reached my buffer. If I read the last four bytes what I get will be wrong data! Because it contains 2 bytes from the previous message.
Is this a possible situation? If yes, How do I handle it?

Rgds,
Gurdas

Gurdas Sandhu, Ph.D.
ORISE Research Fellow at US EPA
0 Kudos
Message 9 of 15
(4,518 Views)
Hello again,

2). I imagine the format of the string written to the device (1 or 2 bytes at a time) is dependent on that device. I would try both ways and see if one fails. If both fail, you may want to contact the manufacturer or consult the user manual to be sure of the format.


5b and 5cii). If you can use a loop, the best way to read the latest 4 bytes always and deterministically, with best serial performance (not necessarily overall performance if other programs are running) is to set the UARTs receive FIFO size to 4 (I will describe how and why to do this below) and to read 4 bytes at a time in a loop. The reason for setting the FIFO size is to cause the interrupt necessary for transferring data from the FIFO to CPU memory as soon as 4 bytes are received. This way, you will have access to 4 bytes as soon as they are available (subject only to the interrupt processing time of your machine, which you do not have a great deal of control over). The "overall" performance reference I mentioned above is only to say that decreasing the number of bytes on which such an interrupt will occur will simply cause more interrupts to occur, using more processing time per byte (than would be having this value set to 14 for example, since fewer interrupts would occur). This is not really a problem, and it is relatively common to decrease this number to get better SERIAL performance as you seem to desire. You can set the FIFO size in software on most modern UARTs. The following should get you there on an XP machine (similar on others):

1. Open the Device Manager.
2. Expand the Ports (COM & LPT) tab.
3. Right click and select properties.
4. Click the Port Settings tab.
5. Click the Advanced... button.

Here you can change the receive buffer (FIFO) size to 4. Then you can read 4 bytes at a time in a loop and you will have the latest 4 bytes of data all the time. If necessary, you can keep an accumulator value in SW to monitor the total number of bytes received over multiple reads/loop interations. That way you can essentially throw away bytes until bytes 45-48 come around, and you will not have the overhead of dealing with all 48 bytes at once when you are only interested in the last 4.

As to which bytes are the last, you are correct in that the last bytes in the buffer that will be read are the last bytes that were sent; that is, bytes are read in the order they are received. If you cannot loop and read 4 bytes at a time, you will likely have to read all 48 and simply use the last 4.

The loop method mentioned above will eliminate the idea of reading only the 2 most recent bytes, along with 2 "old" bytes. If you definitely expect a multiple of 4 bytes to be returned, then reading in 4 byte chunks will cause the read function to return only when receiving 4 bytes; the "old" 2 bytes would have been read in the previous loop iteration, and the read function would simply wait (at least until the timeout period) until it received 4 new bytes. If you cannot use this method, then depending on method used to trigger your read vi, you may only have received 46 bytes at that time. However, if you read 46 bytes you would know that because the VISA Read function returns the number of bytes read (which presumable you specified as an input to the read function anyway, since it seems as though you are not using termination characters).

Thanks, and I hope you are able to accomplish your desired functionality!

Best Regards,

JLS
Best,
JLS
Sixclear
0 Kudos
Message 10 of 15
(4,518 Views)