View previous topic :: View next topic |
Author |
Message |
sapy44 Guest
|
another RS232 issue |
Posted: Sun Feb 01, 2004 7:47 am |
|
|
Hello all,
I've been experiencing a problem receiving data on the HW RS232 port on the PIC16F877A. Basically I have a do-while loop that continue to receive data from the RS232 port.
The first time throgh the do-while loop works fine. But when I renter the loop the second time the getc() function seems to lock up. I ran the debugger and found that the microcode is stuck in an infinite loop checking for the data ready flag to be set on the Rs232 register.
Do I need to reinitialize the RS232 port for each cycle of the do-while loop ? Any thought's would be appreciated.
I also have a quick question about satnd alone programs. From my understaning all you have to do is remove the "#device ICD=TRUE: statement and the program should compile as a stand alone program. When i do this however my program only seems to run up to the first line of code in my main() function and then locks up. I also noticed that I can still use the ICD to execute the program even though it should have been disabled.
Thanks again for your help. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Sun Feb 01, 2004 8:22 am |
|
|
sapy44,
Post your code and the whole info needed to give us a chance to help you.
Regards,
Humberto |
|
|
sapy44
Joined: 01 Feb 2004 Posts: 19 Location: Cedar Rapids, IA
|
some sample code |
Posted: Sun Feb 01, 2004 5:20 pm |
|
|
Ok, Humberto asked for some example code so here goes.
do {
do {
opr1=getc();
opr2=getc();
} while( !(opr1 == 'M' && opr2 == 'C');
/* loops until detecting "MC" in the incoming data stream */
for(i=0;i<63;i++)
data[i]=getc();
// after detecting "MC" then collect the next 63 characters
vel = atoi(data[23]);
if (vel < 2)
stop_counter++;
if(stop_counter > 10)
done = TRUE;
} while(done); //continues looping until stop_counter reaches 10
The first time throgh the outer do-while loop the getc() functions work fine. But after rentering the outer do-while loop the second time the program hangs on the first getc() inside the nested do-while. A look at the assembly code using the debugger shows that the programm hangs because when it checks the RX data ready ready bit it's not getting set. So it just it hangs because it cannot detect that bit getting set with the incomming data.
Do I need to reinitialize the RS232 port beteween loops ? If not, then what could be the problem that causes the getc() to hang the second time through the loop? Any suggestions welcome. Thanks. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Sun Feb 01, 2004 7:34 pm |
|
|
sapy44 wrote:
Code: |
do {
do {
opr1=getc();
opr2=getc();
} while( !(opr1 == 'M' && opr2 == 'C');
/* loops until detecting "MC" in the incoming data stream */
for( i=0; i<63; i++ )
data[i]=getc();
// after detecting "MC" then collect the next 63 characters
vel = atoi(data[23]);
if (vel < 2)
stop_counter++;
if(stop_counter > 10)
done = TRUE;
} while(done); //continues looping until stop_counter reaches 10
|
Assuming the code you sent is complete, it�s not a good practice to store an incoming string waiting for two consecutive chars into a conditional loop without getting stuck by hardware buffer overruns.
A software receive buffer is a better way to achieve this and you control it toggling interrupts. In the isr() try to catch your char_ID (opr1 & opr2) and set the buffer pointer to start the storing the incoming 63 chars, when the software buffer is full just do the buffer reading in your main.
Code: |
#use rs232(baud=your_speed,xmit=PIN_C6,
rcv=PIN_C7,errors) // Include the "errors" parameter if you are using hardware UART to handle framing errors.
#define RX_SIZE 64 // buffer for serial
reception
#define opr1 'M'
#define opr2 'C'
byte rxbuffer[RX_SIZE]; // RS232 serial RX buffer
byte char_index = 0; // RS232 RX data IN index
#int_rda
void rda_isr(void)
{
byte tmpByte, tmp1;
if( !StartStoringInBuffer )
{
tmpByte = getc(); // Store incoming byte
if(opr1 == tmpByte)
{
tmp1 = tmpByte; //Copy to tmp1
}
if(opr1 == tmp1) && ( opr2 == tmpByte))
{
StartStoringInBuffer = TRUE;
char_index = 0; // Initialize index
}
}
if( StartStoringInBuffer )
{
rxbuffer[char_index] = getc();
char_index = ( char_index + 1 ) % RX_SIZE ;
if( char_index == RX_SIZE )
{
Buffer_full = TRUE;
}
}
void main()
{
int n;
while(1)
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
//your other task ...
if( Buffer_full )
{
disable_interrupts(INT_RDA);
StartStoringInBuffer = FALSE;
Buffer_full = FALSE;
//Read the buffer & your stuffs...
for( n=0; n <= RX_SIZE; n++ )
printf("%C",rxbuffer[n]);
}
}
}
|
Advice: No time to test it! just tell me your results.
Regards
Humberto |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Mon Feb 02, 2004 8:28 am |
|
|
do {
do {
opr1=getc();
opr2=getc();
} while( !(opr1 == 'M' && opr2 == 'C');
/* loops until detecting "MC" in the incoming data stream */
This seems like a very fragile way to detect the start of your message. If you miss a single character in the serial input you may never recover. Instead try:
do{
do{
if (kbhit()){
if (getch() == 'M'){
if (getch() == 'C'){
<Do Stuff>
}
}
}
This way a lost character or a single extra character due to noise will caus a loss of one or two records, but you will eventually be able to rcover. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
sapy44
Joined: 01 Feb 2004 Posts: 19 Location: Cedar Rapids, IA
|
some clarification |
Posted: Mon Feb 02, 2004 4:09 pm |
|
|
I'd like to as some more detail as to the operation of the RS232 port capture that I'm attempting. The data comming in over the RS232 is continous and periodic. Even if I don't catch the first "RM" it will repeat again in less than a second so I'm sure to catch it at some point.
I don realize now that I do need to content with hardware overflow issues, especially since data is alaways comming on over the RS232 port. Humberto's idea of using interrputs seems like a good solution. However, is the isr_rda interrupt routine defined for just the hardware UART or does it also apply to a software RS232 port ?
Also, if anyone has some idea as to why I can't get a program to run properly on it's on w/o having to use the ICD to run it please let me know. Thanks again. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Tue Feb 03, 2004 10:34 am |
|
|
sapy44 wrote:
Quote: |
However, is the isr_rda interrupt routine defined for just the hardware UART or does it also apply to a software RS232 port ?
|
When you writte code for a device that has a built in USART (like 16F877) you have to specify the XMIT=pin and RCV=pin with #USE RS232 directive, then the compiler generates the appropriate code for the situation.
If you are using the PINS that are connected internally to the SPI block , the hardware UART is used. Check your micro pin outs.
If you are using all other PINS you should generate code to bit-bang/sample the data, namelly software UART.
Remember that you must also have a #USE DELAY() before it.
#USE RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7)
Sappy44, take a time to search in this forum, there are hundred�s of samples from where you will learn about this issue.
regards,
Humberto |
|
|
|