CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Sending blocks of data over RS-232
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
edhaslam



Joined: 15 Jul 2005
Posts: 89
Location: UK

View user's profile Send private message

Sending blocks of data over RS-232
PostPosted: Wed Jul 27, 2005 6:38 am     Reply with quote

Hi all,

I'm currently designing a simple data logger that stores ADC values in external RAM. I intend to have a switch on a port that signifies the start of the downloading of data from memory over the hardware USART (PIC16F877A) to a PC where the data will be displayed in a VB program.

Can anyone offer any tips/sample code for transmitting blocks of data over the serial port. It's something I've never done before and wondered if there were any standard ways of doing it?

Thanks in advance,
Ed
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jul 27, 2005 7:28 am     Reply with quote

The most common protocol that I can think of is xmodem. Lots of information and program examples can be found on the internet so I won't go into that any deeper here.

In case you want to transmit the data as multiple files and/or you want to include a file name, than have a look at the ymodem protocol.
mcafzap



Joined: 07 Sep 2003
Posts: 46
Location: Manchester, UK

View user's profile Send private message

PostPosted: Wed Jul 27, 2005 9:01 am     Reply with quote

For a really simple 'protocol' just send the data when it's requested by the receiving program. If you always send the same number of bytes, there's no need to indicate the end, just guard against waiting forever.

Steve
edhaslam



Joined: 15 Jul 2005
Posts: 89
Location: UK

View user's profile Send private message

PostPosted: Wed Jul 27, 2005 9:31 am     Reply with quote

mcafzap wrote:
For a really simple 'protocol' just send the data when it's requested by the receiving program. If you always send the same number of bytes, there's no need to indicate the end, just guard against waiting forever.

Steve


ckielstra> Thanks i'll look into those protocols

mcafzap> This is more along the lines of what I was thinking, something slightly simpler.

Perhaps I could send a known-length string of characters to signify the start of transmission that my vb code waits for, followed by blocks of 1024 bytes of data, or something similar? Perhaps get the vb code to send a charcter back to signify it's ready, then send the data? As I said, I'm new to this area of programming...
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Wed Jul 27, 2005 11:59 am     Reply with quote

I posted an example in the code libaray that sends packets of data. I would suggest that the PC start the transfer and forget about the switch. When the PC request a range of data the PIC responds with that range of data.

This is a specification for MODBUS protocol.
http://home.houston.rr.com/neutone/Modbus%20Application%20Protocol%20v1.pdf

This is an example of some code that meets some of that specification
http://home.houston.rr.com/neutone/serial.c

You dont really need a CRC on the packets but the master/slave aproach should work for you.
edhaslam



Joined: 15 Jul 2005
Posts: 89
Location: UK

View user's profile Send private message

PostPosted: Wed Jul 27, 2005 3:48 pm     Reply with quote

Many thanks Neutone Smile
Bill Boucher



Joined: 04 Feb 2005
Posts: 34
Location: Chatham,ON,CA

View user's profile Send private message Send e-mail Visit poster's website

oops never mind
PostPosted: Mon Aug 01, 2005 4:33 pm     Reply with quote

oops never mind

Last edited by Bill Boucher on Mon Aug 01, 2005 4:37 pm; edited 1 time in total
Bill Boucher



Joined: 04 Feb 2005
Posts: 34
Location: Chatham,ON,CA

View user's profile Send private message Send e-mail Visit poster's website

Re: Sending blocks of data over RS-232
PostPosted: Mon Aug 01, 2005 4:35 pm     Reply with quote

I have designed, built, and programmed many systems using RS-232 and RS-485 multi-drop networks of up to 1000+ devices all connected to a single PC serial port. In short, you get what you pay for, so if you design your communication method without any error detection schemes, then you run the risk of reading corrupted data from your logger. I like to use a master/slave system that uses structured packets. The PC is the master and the logger is the slave. I create a "command set" that both devices understand and "poll" the slave at intervals. For example, the PC can ask the logger if it has data, if it is full, if certain inputs are high or low, what is the voltage of a set of inputs, and so forth. Then the logger would answer that question specifically. Someone mentioned the usefullness of transferring "blocks" of data one at a time. The PC application would ask for page 1, then page 2, and so forth until all are transferred. Someone else mentioned "little need for CRC" in the packets. While the implementation of 16-bit CRC checks may seem like a lot of work at first, it actually isn't all that hard and it goes a very long way to ensuring that your master's commands are received correctly by the slave and that the data received from the slave is accurate.

In VB6, the mscomm control operates in "text" or "binary" mode. "Text" mode uses strings. The other mode uses arrays. I have found "binary" mode much more reliable so I always have my programs converting strings to an array before Tx'ing and converting received arrays back into strings upon reception. Yes, it's a pain but runs flawlessly. Moving on, I use a structured packet for all communications. I use a "unique" value above 127 (of the 256 possible states from 0 to 255 for 8-bit data) to represent a packet begin marker (PB) and another for a packet end marker (PE). All other binary data is converted into ascii text "hex" characters. Binary data includes the "command value", any required address data, any attached data, and the 16 bit CRC checksum. Converting binary data into ascii-hex characters doubles the number of bytes required to send the data, but by using unique packet markers and a 16-bit CRC value, you can adjust the packet length to the optimum for each specific command in the set and you can rest assured that packets are "intact" before processing them.

Be aware that you can send any binary byte in "text" mode using the mscomm control in VB. Practically everyone does this for their first few projects. You just have to set "null discard" to false or the control will drop binary zero. You also have to set "parity replace" to nothing. The fact that the "mode" is called "text" means nothing really since it doesn't restrict you to the ascii set of values or anything like that. It more refers to the way input and output data is handled as strings or "text".

Here's a useful tip... make your packets short, like no more than the PC's UART hardware FIFO size. The 16550 has a 16 byte FIFO. The 16650 and 16750 have 32 byte FIFO's. If your packets are longer than the FIFO size, you run the risk of overflowing the input buffer before Windows has time to come along and empty. Setting the "receive buffer size" in VB to something like 1024 doesn't help. We're talking hardware here. It might help to actually set the size to something really small like 4 or 8 bytes because then Windows will become alerted before the buffer is actually full. I still wouldn't count on Windows being fast enough to clear the input buffer in all cases. If Windows doesn't empty the buffer in time, bytes coming in after the buffer is filled are lost. This results in lost bytes or one might say "a dropped packet". I simply use a 32-byte hardware FIFO and I make my packets no longer than 32 bytes. This way, the master clears the input FIFO, then asks for something by sending a command and the input FIFO has enough space to hold the entire response regardless of the Windows situation. Systems I've created in this manner run flawlessly and virtually never drop a packet. The CRC checks done on all packets ensure reliable execution of commands and data. Using unique values for packet markers means that data cannot be misinterpreted as a marker and vice-versa. Checking for correct structure such as packet length, marker values, valid values for commands and data (i.e. values in the command position will have a known range, and all ascii-hex characters must be '0' through '9' and 'A' through 'F'), etc. all combine to boost reliability to nearly 100% over practically any length of cable and without regard to timing issues imposed by the OS.

You should start with something very simple such as using the mscomm controls "text" mode and sending binary data literally over a short connection. Creat a very simple command set such as specific values representing "say hi" and "send data". Once that's working well, add code to produce unique packet markers and convert the data to ascii-hex. When that's working, add error checks such as CRC16. Just take it one step at a time. Later, you can copy & paste your entire comm system from one project to another so the more you put into it, the more benefit you'll get out of it in the long run.

For my systems, a packet might be structured to look like this:
PB, Command1, Command0, Data3, Data2, Data1, Data0, CRC3, CRC2, CRC1, CRC0, PE

Where PB = A0h, PE = A9h, and Command1='0' and Command0='5' and when combined represent 05h, and Data4 through Data0 characters '0123' represent a 16-bit value 0123h or two 8-bit values 01h and 23h, and CRC4 through CRC16 characters combine to represent the 16-bit CRC checksum value for the entire packet (not including the 4 CRC16 character bytes).

Such packets can be of a specific length for each unique command defined in your command set but they do not have to be because the CRC16 is a very reliable way to check it and the CRC16 calculation works on any length of packet greater than a few bytes.

Just for interest, many DMM's and other existing devices such as plotters, scopes, etc. use "structured packets" where binary data is first converted to ascii-hex characters for transmission. Some devices add CRC checks, some don't. Some simply duplicate critical data by sending it more than once within the same packet or by asking for the same data to be returned more than once and comparing them. The CRC16 method is still way better and saves a lot of coding in the long run and it verifies all data, not just some of it.

Someone suggested eliminating the "hardware switch or button" used to upload the data. I agree. Although it is doable, it's not required. Your PC application can poll the logger at intervals and purge it of its data automatically if it gets too full. Otherwise, you'll likely be sitting at the PC and mouse-clicking the "upload data" button in which case the PC master sends a command or series of commands to retrieve the logger data. It is unlikely that it would be useful to set up the PC app to be ready to receive first and then go hit the button or switch on the logger to get it to go ahead. It is possible like I said, but I think you'd find it impractical since you can control everything the slave device does from the PC master application itself.

edhaslam wrote:
Hi all,

I'm currently designing a simple data logger that stores ADC values in external RAM. I intend to have a switch on a port that signifies the start of the downloading of data from memory over the hardware USART (PIC16F877A) to a PC where the data will be displayed in a VB program.

Can anyone offer any tips/sample code for transmitting blocks of data over the serial port. It's something I've never done before and wondered if there were any standard ways of doing it?

Thanks in advance,
Ed
edhaslam



Joined: 15 Jul 2005
Posts: 89
Location: UK

View user's profile Send private message

Re: Sending blocks of data over RS-232
PostPosted: Tue Aug 02, 2005 1:50 am     Reply with quote

Many thanks for that very useful post Bill - it gives me something to aim for now. You are right though, the best thing to do is to start of with some simple examples and work my way up from there.

Regards,
Ed

Bill Boucher wrote:
I have designed, built, and programmed many systems using RS-232 and RS-485 multi-drop networks of up to 1000+ devices all connected to a single PC serial port. In short, you get what you pay for, so if you design your communication method without any error detection schemes, then you run the risk of reading corrupted data from your logger. I like to use a master/slave system that uses structured packets. The PC is the master and the logger is the slave. I create a "command set" that both devices understand and "poll" the slave at intervals. For example, the PC can ask the logger if it has data, if it is full, if certain inputs are high or low, what is the voltage of a set of inputs, and so forth. Then the logger would answer that question specifically. Someone mentioned the usefullness of transferring "blocks" of data one at a time. The PC application would ask for page 1, then page 2, and so forth until all are transferred. Someone else mentioned "little need for CRC" in the packets. While the implementation of 16-bit CRC checks may seem like a lot of work at first, it actually isn't all that hard and it goes a very long way to ensuring that your master's commands are received correctly by the slave and that the data received from the slave is accurate.

In VB6, the mscomm control operates in "text" or "binary" mode. "Text" mode uses strings. The other mode uses arrays. I have found "binary" mode much more reliable so I always have my programs converting strings to an array before Tx'ing and converting received arrays back into strings upon reception. Yes, it's a pain but runs flawlessly. Moving on, I use a structured packet for all communications. I use a "unique" value above 127 (of the 256 possible states from 0 to 255 for 8-bit data) to represent a packet begin marker (PB) and another for a packet end marker (PE). All other binary data is converted into ascii text "hex" characters. Binary data includes the "command value", any required address data, any attached data, and the 16 bit CRC checksum. Converting binary data into ascii-hex characters doubles the number of bytes required to send the data, but by using unique packet markers and a 16-bit CRC value, you can adjust the packet length to the optimum for each specific command in the set and you can rest assured that packets are "intact" before processing them.

Be aware that you can send any binary byte in "text" mode using the mscomm control in VB. Practically everyone does this for their first few projects. You just have to set "null discard" to false or the control will drop binary zero. You also have to set "parity replace" to nothing. The fact that the "mode" is called "text" means nothing really since it doesn't restrict you to the ascii set of values or anything like that. It more refers to the way input and output data is handled as strings or "text".

Here's a useful tip... make your packets short, like no more than the PC's UART hardware FIFO size. The 16550 has a 16 byte FIFO. The 16650 and 16750 have 32 byte FIFO's. If your packets are longer than the FIFO size, you run the risk of overflowing the input buffer before Windows has time to come along and empty. Setting the "receive buffer size" in VB to something like 1024 doesn't help. We're talking hardware here. It might help to actually set the size to something really small like 4 or 8 bytes because then Windows will become alerted before the buffer is actually full. I still wouldn't count on Windows being fast enough to clear the input buffer in all cases. If Windows doesn't empty the buffer in time, bytes coming in after the buffer is filled are lost. This results in lost bytes or one might say "a dropped packet". I simply use a 32-byte hardware FIFO and I make my packets no longer than 32 bytes. This way, the master clears the input FIFO, then asks for something by sending a command and the input FIFO has enough space to hold the entire response regardless of the Windows situation. Systems I've created in this manner run flawlessly and virtually never drop a packet. The CRC checks done on all packets ensure reliable execution of commands and data. Using unique values for packet markers means that data cannot be misinterpreted as a marker and vice-versa. Checking for correct structure such as packet length, marker values, valid values for commands and data (i.e. values in the command position will have a known range, and all ascii-hex characters must be '0' through '9' and 'A' through 'F'), etc. all combine to boost reliability to nearly 100% over practically any length of cable and without regard to timing issues imposed by the OS.

You should start with something very simple such as using the mscomm controls "text" mode and sending binary data literally over a short connection. Creat a very simple command set such as specific values representing "say hi" and "send data". Once that's working well, add code to produce unique packet markers and convert the data to ascii-hex. When that's working, add error checks such as CRC16. Just take it one step at a time. Later, you can copy & paste your entire comm system from one project to another so the more you put into it, the more benefit you'll get out of it in the long run.

For my systems, a packet might be structured to look like this:
PB, Command1, Command0, Data3, Data2, Data1, Data0, CRC3, CRC2, CRC1, CRC0, PE

Where PB = A0h, PE = A9h, and Command1='0' and Command0='5' and when combined represent 05h, and Data4 through Data0 characters '0123' represent a 16-bit value 0123h or two 8-bit values 01h and 23h, and CRC4 through CRC16 characters combine to represent the 16-bit CRC checksum value for the entire packet (not including the 4 CRC16 character bytes).

Such packets can be of a specific length for each unique command defined in your command set but they do not have to be because the CRC16 is a very reliable way to check it and the CRC16 calculation works on any length of packet greater than a few bytes.

Just for interest, many DMM's and other existing devices such as plotters, scopes, etc. use "structured packets" where binary data is first converted to ascii-hex characters for transmission. Some devices add CRC checks, some don't. Some simply duplicate critical data by sending it more than once within the same packet or by asking for the same data to be returned more than once and comparing them. The CRC16 method is still way better and saves a lot of coding in the long run and it verifies all data, not just some of it.

Someone suggested eliminating the "hardware switch or button" used to upload the data. I agree. Although it is doable, it's not required. Your PC application can poll the logger at intervals and purge it of its data automatically if it gets too full. Otherwise, you'll likely be sitting at the PC and mouse-clicking the "upload data" button in which case the PC master sends a command or series of commands to retrieve the logger data. It is unlikely that it would be useful to set up the PC app to be ready to receive first and then go hit the button or switch on the logger to get it to go ahead. It is possible like I said, but I think you'd find it impractical since you can control everything the slave device does from the PC master application itself.

edhaslam



Joined: 15 Jul 2005
Posts: 89
Location: UK

View user's profile Send private message

Re: Sending blocks of data over RS-232
PostPosted: Tue Aug 02, 2005 1:50 am     Reply with quote

Edit: Double post Wink
ratgod



Joined: 27 Jan 2006
Posts: 69
Location: Manchester, England

View user's profile Send private message

PostPosted: Fri Sep 21, 2007 10:54 pm     Reply with quote

I designed a protocol for my company which each packet is a fixed length, I have a start byte at the beginning followed by an address byte then the 3rd byte is a separator followed by a fixed length of data.
The packet is sent out using the printf command sending each byte as a character.

The receiving section of the code is the RS232 interrupt routine, it checks bytes into the buffer, but if it detects the start byte it resets the buffer back to the beginning and starts filling it with the new data.

when the buffer is full the 2nd part of the program checks that the start byte and the separator is in the correct place, if thats ok then it passes on to be processed.

This method has worked very successfully for us so far and is used in a few of our products.
arunb



Joined: 08 Sep 2003
Posts: 492
Location: India

View user's profile Send private message Send e-mail

RE;
PostPosted: Sat Sep 22, 2007 7:31 am     Reply with quote

edhaslam..Does your datalogger continue logging data even while it is downloading data to the PC ???

arunb
Ken Johnson



Joined: 23 Mar 2006
Posts: 197
Location: Lewisburg, WV

View user's profile Send private message

PostPosted: Sat Sep 22, 2007 8:00 am     Reply with quote

Bill's post is excellent. However, personally, I'd make the packet size fit the application, not some (likely unknown) hardware fifo size. "Dropped packets" is certainly a possibility, but I think very low probability - depends on so many things - pc horsepower, other running apps, windows update Smile etc. But, I'd go for simplicity, meaning, put what is needed into the packet.

You have some very good guidelines, now go for it!

Good luck,
Ken
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Sep 23, 2007 10:01 am     Reply with quote

Hi

Just a comment on Bill's post - we have succesfully captured serial data at 921k Baud (with large packets) although admittedly over USB with the PC acting as a virtual comm port. And we also regularly capture 115kBaud over a 'real' COM port. Windows comms drivers should handle the buffering, and with a modern PC it's doubtful a PIC can outrun a PC!

One thing we did notice - our mega-baud system's PC software was initially done in C#. and in that case 500kBaud was the limit, when we changed to Delphi (and real compiled code) we could use 921k without issue. So maybe VB would be limited to 500k also?
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Sun Sep 23, 2007 1:02 pm     Reply with quote

Quote:
initially done in C#. and in that case 500kBaud was the limit, when we changed to Delphi (and real compiled code) we could use 921k without issue. So maybe VB would be limited to 500k also?

Regarding this issue I noticed a great improvment with .NET 2.0 framework. In the .NET 1.0 and 1.1 the serial port handling was omitted, so there were not necessarily speed-optimal programming tricks or third party library patches required. The .NET 2.0 supports the serial ports natively, I noticed it is quicker and more reliable. (though I have not made actual speed comparisons, just was glad being able to use the ports without tricks.)
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group