|
|
View previous topic :: View next topic |
Author |
Message |
ritchie
Joined: 13 Sep 2003 Posts: 87
|
serial interrupt help |
Posted: Sat Jan 17, 2004 1:47 am |
|
|
Mabuhay!
I need your help on serial interrupt, my code listed below:
Code: |
#use rs232(baud=115200,parity=n,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=RS485Com,enable=PIN_B4)
int1 glSerialRXReady = 0; // RS485 ready flag bit
int1 glSerialRXDataReady = 0; // RS485 data ready flag bit
#define RX_SIZE 64
byte rxbuffer[RX_SIZE];
byte rx_in = 0;
byte rx_out = 0;
#int_rda
void rs485_rx_isr()
{
int ch;
if (glSerialRXReady) // prevent multi-trigger of packets
{
if (kbhit(RS485Com)) // check if data is available from buffer
{
ch = fgetc(RS485Com); // get incoming byte from buffer
rxbuffer[rx_in] = ch; // place incoming byte in rxbuffer
rx_in++; // increment data IN index
rx_out++; // increment data OUT index
if (bit_test(rx_in,6)) // if rx_in larger than RX_SIZE (64)
{
rx_in = 0; // zero rx_in value
rx_out = 0; // zero rx_out value
}
}
if (!kbhit(RS485Com)) // no incoming byte from buffer
{
glSerialRXReady = 0; // prevent multi-trigger of packets
glSerialRXDataReady = 1; // set rx data ready
}
}
else fgetc(RS485Com); // prevent buffer overflow
}
main()
{
glSerialRXReady = 1;
glSerialRXDataReady = 0;
while (1)
{
if (glSerialRXDataReady)
{
.... I process my rxbuffer here ......
....
....
glSerialRXReady = 1; // capture new packets
glSerialRXDataReady = 0; // set data ready flag
}
......
......
}
}
|
I notice that I can't get the packet correctly from a computer.
For clarification, the #int_rda will only interrupt when it receive a byte ? Am I correct? if so, the rs485_rx_isr() routine will only be executed during serial interrupt?
if that would be the case I place the condition if (!kbhit(RS485Com)) in a wrong place... this condition is responsible to detect that their is no incoming byte from a computer and by this it will trigger a flag bit to process the receive packets.
I put this condition for the reason that I am receiving data from a computer of variable lenght but it will not exceeds the 64bytes buffer size allocated. In addition, the packet does not have an end of transmission character.
I need your comments on this code or any help that I could re-phrase this code such it can detect that their is no incoming data.
Thank you. |
|
|
Ttelmah Guest
|
Re: serial interrupt help |
Posted: Sat Jan 17, 2004 3:46 am |
|
|
ritchie wrote: | Mabuhay!
I need your help on serial interrupt, my code listed below:
Code: |
#use rs232(baud=115200,parity=n,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=RS485Com,enable=PIN_B4)
int1 glSerialRXReady = 0; // RS485 ready flag bit
int1 glSerialRXDataReady = 0; // RS485 data ready flag bit
#define RX_SIZE 64
byte rxbuffer[RX_SIZE];
byte rx_in = 0;
byte rx_out = 0;
#int_rda
void rs485_rx_isr()
{
int ch;
if (glSerialRXReady) // prevent multi-trigger of packets
{
if (kbhit(RS485Com)) // check if data is available from buffer
{
ch = fgetc(RS485Com); // get incoming byte from buffer
rxbuffer[rx_in] = ch; // place incoming byte in rxbuffer
rx_in++; // increment data IN index
rx_out++; // increment data OUT index
if (bit_test(rx_in,6)) // if rx_in larger than RX_SIZE (64)
{
rx_in = 0; // zero rx_in value
rx_out = 0; // zero rx_out value
}
}
if (!kbhit(RS485Com)) // no incoming byte from buffer
{
glSerialRXReady = 0; // prevent multi-trigger of packets
glSerialRXDataReady = 1; // set rx data ready
}
}
else fgetc(RS485Com); // prevent buffer overflow
}
main()
{
glSerialRXReady = 1;
glSerialRXDataReady = 0;
while (1)
{
if (glSerialRXDataReady)
{
.... I process my rxbuffer here ......
....
....
glSerialRXReady = 1; // capture new packets
glSerialRXDataReady = 0; // set data ready flag
}
......
......
}
}
|
I notice that I can't get the packet correctly from a computer.
For clarification, the #int_rda will only interrupt when it receive a byte ? Am I correct? if so, the rs485_rx_isr() routine will only be executed during serial interrupt?
if that would be the case I place the condition if (!kbhit(RS485Com)) in a wrong place... this condition is responsible to detect that their is no incoming byte from a computer and by this it will trigger a flag bit to process the receive packets.
I put this condition for the reason that I am receiving data from a computer of variable lenght but it will not exceeds the 64bytes buffer size allocated. In addition, the packet does not have an end of transmission character.
I need your comments on this code or any help that I could re-phrase this code such it can detect that their is no incoming data.
Thank you. |
Basically, you should only get an interrupt when a character is available. There is a 'caveat' though, in that the overrun error bit may be set at this time, and if so, unless cleared, the UART will stop receiving data.
The 'ERRORS' directive will clear this for you, but I prefer to go 'DIY', since I can then add other code to flag that this has happened.
Adding code like this to the 'tail' of the interrupt handler (after receiving the character), removes this problem (the defines are for an 18Fxx2, and will need to be modified for other chips).
Code: |
#bit OERR=0xFAB.1
#bit CREN=0xFAB.4
if (OERR) {
CREN=false;
CREN=true;
//Add any 'warning flag', or other handler here
}
|
Now the second comment, relates to the buffer handler itself. Normally, only the 'data in' pointer should be incremented for the addition of a character. The 'data out' pointer would only move when the character is removed. Hence the handler would look something like:
Code: |
#define RX_SIZE (64)
byte rxbuffer[RX_SIZE];
byte rx_in = 0;
byte rx_out = 0;
byte rx_free = 0;
//Note I am using a seperate 'count' here. This requires one more
//byte of storage, but speeds certain tests.
byte RSTfrom()
{
/* Get character from the RS232 RX buffer */
byte temp;
temp=rx_out;
rx_out=(++rx_out) & (RX_SIZE-1);
temp=(rxbuffer[temp]);
rx_free++;
return(temp);
}
#define LIM (2)
#define isempty(buff,free,in,out,size) (free>=size)
#define isfull(buff,free,in,out,size) (free<LIM)
#define tobuff(buff,free,in,out,size,chr) {buff[in++]=chr;\
--free;\
in=(in & (size-1));}
#int_rda
void rs485_rx_isr()
{
tobuff(rxbuffer,rx_free,rx_in,rx_out,RX_SIZE,getchar());
if (OERR) {
CREN=false;
CREN=true;
//Add any 'warning flag', or other handler here
}
}
//You can check that the buffer is empty at any time with:
isempty(rxbuffer,rx_free,rx_in,rx_out,RX_SIZE)
//or that the buffer is full at any time with:
isfull(rxbuffer,rx_free,rx_in,rx_out,RX_SIZE)
//and get a character from the buffer with:
RSTfrom()
|
Notice that the use of the seperate 'free counter', allows me to check for the buffer having filled to a 'point' (here just two characters clear), without extra arithmetic. Also that the main buffer functions, can all be used for multiple buffers, accepting all the variables concerned with the buffer, but (since they are done as 'defines'), only the variables that are needed are used for each function. I have also at times used a similar generic 'from' function, but then you have to be careful of the implications of multiple routines wanting to use the same function, if some are in interrupts (my RS232 'extraction', is done in a timer interrupt, rather than in the main code).
Best Wishes |
|
|
ritchie
Joined: 13 Sep 2003 Posts: 87
|
Re: serial interrupt help |
Posted: Sat Jan 17, 2004 6:09 am |
|
|
Mabuhay!
There is a 'caveat' though, in that the overrun error bit may be set at this time, and if so, unless cleared, the UART will stop receiving data. ----> what do you mean by this? Can you elaborate this further regarding error directive?
The 'ERRORS' directive will clear this for you, but I prefer to go 'DIY', since I can then add other code to flag that this has happened. ----> what does this mean error directive will clear this 4u?
One of my concern on the code listed above is? how can I be able to determine that the UART has no incoming character? can I use the error directive by utilizing or adding an additional flag at the error directive condition?
Need your help such that I could make it work.
Thank u. |
|
|
Ttelmah Guest
|
Re: serial interrupt help |
Posted: Sat Jan 17, 2004 11:57 am |
|
|
ritchie wrote: | Mabuhay!
There is a 'caveat' though, in that the overrun error bit may be set at this time, and if so, unless cleared, the UART will stop receiving data. ----> what do you mean by this? Can you elaborate this further regarding error directive?
The 'ERRORS' directive will clear this for you, but I prefer to go 'DIY', since I can then add other code to flag that this has happened. ----> what does this mean error directive will clear this 4u?
One of my concern on the code listed above is? how can I be able to determine that the UART has no incoming character? can I use the error directive by utilizing or adding an additional flag at the error directive condition?
Need your help such that I could make it work.
Thank u. |
The UART will allways have a character on the interrupt The problem is that if you read it, and then exit the routine, without clearing the overrun error, the interrupt will not happen again. If the overrun error is set, then it is probable that the character is corrupted. For high baud rates, you should consider something like (in a sort of 'pseudo code'):
do {
read character
if (overrun) clear error
} while (character is waiting)
This way, if a second character has been received between the interrupt being generated, and arriving inside the routine, this too will be fetched, without having to go through the massive overhead of the interrupt handler...
Best Wishes
Best Wishes |
|
|
|
|
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
|