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 support@ccsinfo.com

Timing the duration of an 11 byte data packet.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
htdata
Guest







Timing the duration of an 11 byte data packet.
PostPosted: Fri Jun 27, 2003 4:41 am     Reply with quote

My application receives 11 bytes of data over an RS485 link. The RS485 chip is connected to the hardware UART of a 16F874. The receiving code waits for a kbhit() event and then sits in a loop waiting for the 11 bytes being sent to it.

My problem is that sometimes the code is not ready and does not receive the first byte. Because the first byte is missed, the code does not receive all 11 bytes until the next packet is sent. This obviously causes me some problems.

I was thinking of using a timer to make sure that all 11 bytes of the packet arrive close enough together to have come from the same packet. If they do not then it can be assumed that a byte was dropped somewhere so the packet can be ignored.

Can anyone help me with some code that will measure the duration from the start of the first byte to the end of the last byte to make sure that they arrive in time? Does this seem like a sensible way of solving my problem? Should I use interupt driven serial IO instead? If so perhaps someone could offer me some thoughts on how that could be accomplished as I have no real experience of interupt driven programming at this time.

Many thanks,

Jason James.
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515592
R.J.Hamlett
Guest







Re: Timing the duration of an 11 byte data packet.
PostPosted: Fri Jun 27, 2003 7:45 am     Reply with quote

:=My application receives 11 bytes of data over an RS485 link. The RS485 chip is connected to the hardware UART of a 16F874. The receiving code waits for a kbhit() event and then sits in a loop waiting for the 11 bytes being sent to it.
:=
:=My problem is that sometimes the code is not ready and does not receive the first byte. Because the first byte is missed, the code does not receive all 11 bytes until the next packet is sent. This obviously causes me some problems.
:=
:=I was thinking of using a timer to make sure that all 11 bytes of the packet arrive close enough together to have come from the same packet. If they do not then it can be assumed that a byte was dropped somewhere so the packet can be ignored.
:=
:=Can anyone help me with some code that will measure the duration from the start of the first byte to the end of the last byte to make sure that they arrive in time? Does this seem like a sensible way of solving my problem? Should I use interupt driven serial IO instead? If so perhaps someone could offer me some thoughts on how that could be accomplished as I have no real experience of interupt driven programming at this time.
:=
:=Many thanks,
:=
:=Jason James.
Polling the kbhit line, should be fine, provided the 'loop' time, plus the time taken to retrieve the first byte, is allways less than one byte time.
Is there any way to 'distinguish' the first byte?. If not, then the protocol becomes 'non recovering', without resorting to a timer.
You don't say, what the clock rate of the chip. or baud rate involved are. These make a massive difference to how 'easy' this is.
Realistically, you would be far better taking advantage of interrupt driven I/O (I think you suspect this)...

On this basis, something like:
In the 'global' defines at the start:
int8 packet[11];
int8 counter=0;
int8 tick;
#bit CREN=0x18.4
#bit OERR=0x18.1
#byte RCREG=0x1A
#bit RCIF=0xC.5

void clear_buffer(void) {
int dummy;
//Here, if RCIF is set, something is wrong (since the chip
//should have gone to the interrupt handler. Also if OERR
//is set, the same is true.
if (RCIF || OERR) {
disable_interrupts(RCIF); //Shouldn't be needed...
CREN=0;
dummy=RCREG;
dummy=RCREG;
dummy=RCREG;
CREN=1;
}
}

#INT_RDA
void serial_char(void) {
int temp;
if (OERR) {
//If the code gets here, data has been lost
CREN=0;
temp=RCREG;
temp=RCREG;
temp=RCREG;
CREN=1;
return;
}
//Here a normal character has been received
if (counter<11) packet[counter++]=RCREG;
//Throw away characters, if the main code has not handled
//the packet
else temp=RCREG;
}

#INT_RTCC
void ticker(void) {
if (tick) --tick;
}

In main:

setup_timer0(RTCC_DIV_256 | RTCC_INTERNAL);
//With this, timer0, will interrupt, every clock/262144)

clear_buffer();
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);

Then to wait for a packet

//You will have to work out this value, from your clock
//rate, and expected packet time.
tick=40;
while (counter<11 && tick) ;
if (counter==11) {
//Here there is a data packet in packet[0]..[10]
//use the data, then call 'clear_buffer', and reset
//'tick' before waiting for the next packet
}
else {
//Here the 'tick' has counted out, implying a problem

}

This should give you some ideas.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515597
htdata
Guest







Re: Timing the duration of an 11 byte data packet.
PostPosted: Fri Jun 27, 2003 8:57 am     Reply with quote

:=:=My application receives 11 bytes of data over an RS485 link. The RS485 chip is connected to the hardware UART of a 16F874. The receiving code waits for a kbhit() event and then sits in a loop waiting for the 11 bytes being sent to it.
:=:=
:=:=My problem is that sometimes the code is not ready and does not receive the first byte. Because the first byte is missed, the code does not receive all 11 bytes until the next packet is sent. This obviously causes me some problems.
:=:=
:=:=I was thinking of using a timer to make sure that all 11 bytes of the packet arrive close enough together to have come from the same packet. If they do not then it can be assumed that a byte was dropped somewhere so the packet can be ignored.
:=:=
:=:=Can anyone help me with some code that will measure the duration from the start of the first byte to the end of the last byte to make sure that they arrive in time? Does this seem like a sensible way of solving my problem? Should I use interupt driven serial IO instead? If so perhaps someone could offer me some thoughts on how that could be accomplished as I have no real experience of interupt driven programming at this time.
:=:=
:=:=Many thanks,
:=:=
:=:=Jason James.
:=Polling the kbhit line, should be fine, provided the 'loop' time, plus the time taken to retrieve the first byte, is allways less than one byte time.
:=Is there any way to 'distinguish' the first byte?. If not, then the protocol becomes 'non recovering', without resorting to a timer.
:=You don't say, what the clock rate of the chip. or baud rate involved are. These make a massive difference to how 'easy' this is.
:=Realistically, you would be far better taking advantage of interrupt driven I/O (I think you suspect this)...
:=
:=On this basis, something like:
:=In the 'global' defines at the start:
:=int8 packet[11];
:=int8 counter=0;
:=int8 tick;
:=#bit CREN=0x18.4
:=#bit OERR=0x18.1
:=#byte RCREG=0x1A
:=#bit RCIF=0xC.5
:=
:=void clear_buffer(void) {
:= int dummy;
:= //Here, if RCIF is set, something is wrong (since the chip
:= //should have gone to the interrupt handler. Also if OERR
:= //is set, the same is true.
:= if (RCIF || OERR) {
:= disable_interrupts(RCIF); //Shouldn't be needed...
:= CREN=0;
:= dummy=RCREG;
:= dummy=RCREG;
:= dummy=RCREG;
:= CREN=1;
:= }
:=}
:=
:=#INT_RDA
:=void serial_char(void) {
:= int temp;
:= if (OERR) {
:= //If the code gets here, data has been lost
:= CREN=0;
:= temp=RCREG;
:= temp=RCREG;
:= temp=RCREG;
:= CREN=1;
:= return;
:= }
:= //Here a normal character has been received
:= if (counter<11) packet[counter++]=RCREG;
:= //Throw away characters, if the main code has not handled
:= //the packet
:= else temp=RCREG;
:=}
:=
:=#INT_RTCC
:=void ticker(void) {
:= if (tick) --tick;
:=}
:=
:=In main:
:=
:= setup_timer0(RTCC_DIV_256 | RTCC_INTERNAL);
:= //With this, timer0, will interrupt, every clock/262144)
:=
:= clear_buffer();
:= enable_interrupts(INT_RDA);
:= enable_interrupts(GLOBAL);
:=
:=Then to wait for a packet
:=
:= //You will have to work out this value, from your clock
:= //rate, and expected packet time.
:= tick=40;
:= while (counter<11 && tick) ;
:= if (counter==11) {
:= //Here there is a data packet in packet[0]..[10]
:= //use the data, then call 'clear_buffer', and reset
:= //'tick' before waiting for the next packet
:= }
:= else {
:= //Here the 'tick' has counted out, implying a problem
:=
:= }
:=
:=This should give you some ideas.
:=
:=Best Wishes

Thanks for the help. Much of this seems a litle over my head right now. I will have to digest it for a while and see what I come up with. The processor is running at 4MHz and the data is being sent at 4800 baud.

What are the different variables and constants you have defined at the start of your code? What do they represent in the working of the code.

I hope you don't mind helping me out. Thanks for the information and suggestions so far.

Regards,

Jason James.
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515599
R.J.Hamlett
Guest







Re: Timing the duration of an 11 byte data packet.
PostPosted: Fri Jun 27, 2003 11:02 am     Reply with quote

:=:=:=My application receives 11 bytes of data over an RS485 link. The RS485 chip is connected to the hardware UART of a 16F874. The receiving code waits for a kbhit() event and then sits in a loop waiting for the 11 bytes being sent to it.
:=:=:=
:=:=:=My problem is that sometimes the code is not ready and does not receive the first byte. Because the first byte is missed, the code does not receive all 11 bytes until the next packet is sent. This obviously causes me some problems.
:=:=:=
:=:=:=I was thinking of using a timer to make sure that all 11 bytes of the packet arrive close enough together to have come from the same packet. If they do not then it can be assumed that a byte was dropped somewhere so the packet can be ignored.
:=:=:=
:=:=:=Can anyone help me with some code that will measure the duration from the start of the first byte to the end of the last byte to make sure that they arrive in time? Does this seem like a sensible way of solving my problem? Should I use interupt driven serial IO instead? If so perhaps someone could offer me some thoughts on how that could be accomplished as I have no real experience of interupt driven programming at this time.
:=:=:=
:=:=:=Many thanks,
:=:=:=
:=:=:=Jason James.
:=:=Polling the kbhit line, should be fine, provided the 'loop' time, plus the time taken to retrieve the first byte, is allways less than one byte time.
:=:=Is there any way to 'distinguish' the first byte?. If not, then the protocol becomes 'non recovering', without resorting to a timer.
:=:=You don't say, what the clock rate of the chip. or baud rate involved are. These make a massive difference to how 'easy' this is.
:=:=Realistically, you would be far better taking advantage of interrupt driven I/O (I think you suspect this)...
:=:=
:=:=On this basis, something like:
:=:=In the 'global' defines at the start:
:=:=int8 packet[11];
:=:=int8 counter=0;
:=:=int8 tick;
Try looking at the chips data sheet. :-)

:=:=#bit CREN=0x18.4
This enables/disables 'continuous receive' on the UART. It is normally enabled, but you can use this to clear the overrun error, by clearing this, then setting it again.

:=:=#bit OERR=0x18.1
This is the bit saying that there has been an overrun error (data has been received, but not handled in time).

:=:=#byte RCREG=0x1A
This is the actual UART data receive register.

:=:=#bit RCIF=0xC.5
This is the flag to say that a serial interrupt should happen. Hence if it is set in the main code (where interrupts are enabled), something radical has gone wrong!...

:=:=
:=:=void clear_buffer(void) {
:=:= int dummy;
:=:= //Here, if RCIF is set, something is wrong (since the chip
:=:= //should have gone to the interrupt handler. Also if OERR
:=:= //is set, the same is true.
:=:= if (RCIF || OERR) {
:=:= disable_interrupts(RCIF); //Shouldn't be needed...
:=:= CREN=0;
:=:= dummy=RCREG;
:=:= dummy=RCREG;
:=:= dummy=RCREG;
:=:= CREN=1;
:=:= }
:=:=}
:=:=
:=:=#INT_RDA
:=:=void serial_char(void) {
:=:= int temp;
:=:= if (OERR) {
:=:= //If the code gets here, data has been lost
:=:= CREN=0;
:=:= temp=RCREG;
:=:= temp=RCREG;
:=:= temp=RCREG;
:=:= CREN=1;
:=:= return;
:=:= }
:=:= //Here a normal character has been received
:=:= if (counter<11) packet[counter++]=RCREG;
:=:= //Throw away characters, if the main code has not handled
:=:= //the packet
:=:= else temp=RCREG;
:=:=}
:=:=
:=:=#INT_RTCC
:=:=void ticker(void) {
:=:= if (tick) --tick;
:=:=}
:=:=
:=:=In main:
:=:=
:=:= setup_timer0(RTCC_DIV_256 | RTCC_INTERNAL);
:=:= //With this, timer0, will interrupt, every clock/262144)
:=:=
:=:= clear_buffer();
:=:= enable_interrupts(INT_RDA);
:=:= enable_interrupts(GLOBAL);
:=:=
:=:=Then to wait for a packet
:=:=
:=:= //You will have to work out this value, from your clock
:=:= //rate, and expected packet time.
:=:= tick=40;
:=:= while (counter<11 && tick) ;
:=:= if (counter==11) {
:=:= //Here there is a data packet in packet[0]..[10]
:=:= //use the data, then call 'clear_buffer', and reset
:=:= //'tick' before waiting for the next packet
:=:= }
:=:= else {
:=:= //Here the 'tick' has counted out, implying a problem
:=:=
:=:= }
:=:=
:=:=This should give you some ideas.
:=:=
:=:=Best Wishes
:=
:=Thanks for the help. Much of this seems a litle over my head right now. I will have to digest it for a while and see what I come up with. The processor is running at 4MHz and the data is being sent at 4800 baud.

You really should be OK with this. Assuming your data is 8bit, no parity, one stop bit, then the 'byte time', is 1/480th second, which is 2083 instruction clock times. The handler as written, probably takes no more than about 50 instruction times.
At this rate, you really should be able to get the polled version to work, but the interrupt version, is a lot more elegant.

At these rates, your eleven character packet (assuming there are no gaps), will take 0.023 seconds. You should allow at least twice this for the 'timeout' variable, and probably more. The 'tick' changes every 0.065 seconds, so a tick value of only perhaps 4, will give a reasonable timeout.

:=
:=What are the different variables and constants you have defined at the start of your code? What do they represent in the working of the code.
:=
Lets, 'walk through' it. The 'setup timer' command, says that the RTCC timer, will run off a clock at 1/256th the instruction clock (which is 1/4 the incoming crystal frequency). The counter counts up from 0, to 255, and then 'wraps' back to zero. The RTCC interrupt occurs, whenever this 'wrap' takes place. Hence at 4000000/(4*256*256) times per second.
The interrupt handler, simply decrements 'tick', if it is non-zero (remember in 'C', a non-zero value is 'true').
This allows tick to be set before any operation, and if you test for it reaching zero, you get a 'timeout' effect.
Now the data is going to be stored in a buffer, which I have called 'packet'. 'counter', is used as the address to write the data into the buffer. Hence before waiting for a packet, counter must be set to zero (so the first byte will be put into the first address).
The receive data interrupt, then looks at the value of 'counter'. If it has allready got to 11, then a full packet has allready been received, and something is wrong, so the code 'throws away' the received character (to prevent overrun errors). However if it is less than 11, the character is read directly from the processor register (RCREG), writen into the buffer, and the 'counter' value is incremented. You could code this line, as:
if (counter<11) packet[counter++]=getc();

and get exactly the same result. It is purely, that I have had so many faults with the CCS functions in the past, that I prefer to go 'DIY'....
So counter, will start at zero (clear_buffer sets this), and increment by one for every character received, till it gets to 11, and then _stop_.

Now the main code, checks, counter, and the 'tick' timeout value. If counter gets to 11, then a packet has been received. At this point, you have to deal with the data (remember that you must reset the counter, or any further characters will be thrown away). So you have (assuming the next packet followed immediately), 1/480th second, to deal with the packet. However With the 'interrupt driven' approach, so long as you have copied the data from the buffer, and called the 'clear_buffer' routine, you can carry on processing the packet, while the next one is received. I suspect, this is the point, where the 'polled' routine is failing, since though 2000 clock cycles, seems a lot, some routines (arithmetic for example), can easily use this amount of time. Technically, provided you reach the 'while (counter<11 && tick)' routine, before 1/43rd sec has passed, the interrupt code will still be 'happy'.

Now there are a couple of 'odd bits' in the code (where I check OERR, and then disable CREN, and read the input register three times). Basically, if an overrun has occurred, then you have to turn the UART off, then on, to clear the error (this is the change to CREN). At this point, there can potentially be three characters in the input buffers, hence I clear these, to ensure the chip is 'ready to go'.

:=I hope you don't mind helping me out. Thanks for the information and suggestions so far.
:=
:=Regards,
:=
:=Jason James.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515610
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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