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

Problem with a delay before a getc() function
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
Mustang1945



Joined: 07 Jul 2015
Posts: 31
Location: Ecuador

View user's profile Send private message

Problem with a delay before a getc() function
PostPosted: Tue Jul 07, 2015 10:35 am     Reply with quote

Hi, i am from Ecuador, South America, i am working on a project but i have a strange problem here:

Does not work because i have a delay before getc() and kbhit().

#include <16F877A.h>
#include <string.h>
#include <stdlib.h>

#FUSES NOWDT //No Watch Dog Timer
#FUSES XT
#FUSES NOPUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOCPD

#use delay(clock=4000000)

#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,bits=8,parity=n,ERRORS)


void main()
{
char a;
set_tris_b(0b00000000);

while(true)
{

output_b(0b00001000); //this on and off sequence makes the program
delay_ms(1000); //not work....but why????
output_b(0b00000000); //if i delete this sequence all is ok,but i need to
delay_ms(1000); //include this on and off led


if(kbhit()==1)
{
a=getc();

if(a=='a')
{
output_b(0b00000001);
delay_ms(1000);
}

else if(a=='b')
{
output_b(0b00000010);
delay_ms(1000);
}

else if(a=='c')
{
output_b(0b00000100);
delay_ms(1000);
}
}

else
{
output_b(0b00001000);//when the program not work only this is executed
}

}
}
drolleman



Joined: 03 Feb 2011
Posts: 116

View user's profile Send private message

PostPosted: Tue Jul 07, 2015 11:33 am     Reply with quote

Depending on your compiler version, it used to only allow a max of delay_ms(256); i'm not sure when the 65535 became legal.

drolleman
Ttelmah



Joined: 11 Mar 2010
Posts: 19451

View user's profile Send private message

PostPosted: Tue Jul 07, 2015 1:34 pm     Reply with quote

His UART has overflowed.

Data has been received while waiting.
kbhit does not return 'TRUE' when the UART is locked (overrun error).
getc will clear this error, but won't be called.
However if you test 'RS232_ERRORS' you can call getc to clear the problem.

Replace the line:

if(kbhit()==1)

with:

if(kbhit() || (bit_test(RS232_ERRORS,1)))
Mustang1945



Joined: 07 Jul 2015
Posts: 31
Location: Ecuador

View user's profile Send private message

PostPosted: Tue Jul 07, 2015 10:06 pm     Reply with quote

Thanks for your answers
Ttelmah... i tried to do that but nothing happens, remember that i am already using ERRORS.

drolleman...I use a delay of 100 ms and works better...
but my project has changed a little.
Now i must use get_string and not getc, because i am trying to get a string, but kbhit() and ERRORS doesn't work with get_string.

With this program works fine, but if i uncomment the red lines, doesn't work.
kbhit() always is 0, i think its because now i am trying to get a string and not just a character and if i add ERRORS not work.

#include <16F877A.h>
#include <string.h>
#include <stdlib.h>

#FUSES NOWDT //No Watch Dog Timer
#FUSES XT
#FUSES NOPUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOCPD

#use delay(clock=4000000)

#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,bits=8,parity=n)//,ERRORS)

#include <INPUT.C>

void main()
{
char string[11];
signed int8 i;
char password[11]="SPITFIRE\r\n";

set_tris_b(0b00000000);
output_b(0b00000000);
while(true)
{


//if(kbhit() || (bit_test(RS232_ERRORS,1)))
//{



output_b(0b00010000);
delay_ms(1000); //the objective is that the program accept this
output_b(0b00000000); //delays, but how?...i cant use kbhit to know for
delay_ms(1000); //new data and cant use error to prevent the
//buffer overflow



/**
i have been a long time in this problem and my program works fine without the delays, but i need to put delays, thats the problem, and i have seen some examples about compare strings using rs232 but all
them don't have delays,if you could show me an example ....thanks*/

get_string(string,11);
i=strncmp(string, password,8);

if(i==0)
{
output_b(0b00000001);
delay_ms(1000);
}

else if(i==1)
{
output_b(0b00000010);
delay_ms(1000);
}

else if(i==-1)
{
output_b(0b00000100);
delay_ms(1000);
}

//}
else
{
output_b(0b00001000);
delay_ms(1000);
}

}
}
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Wed Jul 08, 2015 12:30 am     Reply with quote

I have 2 ideas for you:
1. I see that your main loop keeps running (testing for new char etc.) and you need to toggle PIN_B4 . How about handling the pin with a timer (that works in the background) ?
2. Another option, similar to #1 is to add a 100us delay in the loop. This way you will not miss new chars, and you can use a counter to measure time (each loop takes slightly more than 100us, and after 10000 loops you know that 1 seconds passed and toggle PIN_B4)
Ttelmah



Joined: 11 Mar 2010
Posts: 19451

View user's profile Send private message

PostPosted: Wed Jul 08, 2015 2:46 am     Reply with quote

No.

You need ERRORS in the #use RS232, _and_ to be testing RS232_ERRORS. Both.

'ERRORS' tells the compiler to add code to getc, to clear the error condition.

Problem is that because you do not call 'getc', if there is an error, the clearing code in getc will never be called.....

The bit test, tells the compiler if there is an error, to call the getc anyway. This then clears the error.
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Wed Jul 08, 2015 1:33 pm     Reply with quote

Ttelmah, your answer made me think again about the open issue I have in another thread: http://www.ccsinfo.com/forum/viewtopic.php?t=53846
This is with a PIC24. Could be that there is an error happening, no interrupt to catch the error and therefore the receive mechanism is 'jammed' ?
I do have
Code:
#use RS232(STREAM=R232, BAUD=9600, UART4, ERRORS)


???
Ttelmah



Joined: 11 Mar 2010
Posts: 19451

View user's profile Send private message

PostPosted: Wed Jul 08, 2015 1:48 pm     Reply with quote

Yes.

The way the code works, is that a routine is added to getc to clear the error. Obviously getc has to be called for this to happen.
In the older PIC's if you use an interrupt driven handler, then normally getc will be called. If however (as this poster), you test with 'if kbhit()', this does not return true when there is an overrun, so getc does not get called.
On the newer PIC's with bigger buffers, it is common to include a kbhit in the handler (to deal with the situation where multiple characters are in the buffer), and this will prevent the getc being reached (unless you are careful and use a 'do..while', so getc is always called once).
The receive interrupt should be called for the overrun character, but for you, I'd say the safest way would be to enable the overrun error interrupt, and then just read characters till the buffer is empty.

I actually tested the code posted here. You can hang the UART, if you send a number of characters and then use kbhit with the buffer overrun.
Then testing RS232_ERRORS, allows getc to be called.

The alternative for him would be:
Code:

   if(kbhit())
   {
       //code

   }
   else
   {
      if (bit_test(RS232_ERRORS,1))
         //do one dummy getc here
   }
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Wed Jul 08, 2015 2:03 pm     Reply with quote

I'm trying to keep up but it's not easy :-)
There is no kbhit() in my code. The ISR is:
Code:

#INT_RDA4
void rs232isr() {
   tmp=fgetc(R232);
   
   if(rs232RxPtr<RS232_RX_BUFSIZ) rs232RxBuf[rs232RxPtr++]=tmp;
}   

as I said before, my debug code shows that the ISR stops getting called after some time.
Ttelmah



Joined: 11 Mar 2010
Posts: 19451

View user's profile Send private message

PostPosted: Wed Jul 08, 2015 2:48 pm     Reply with quote

There should be.....

Code:

#INT_RDA4
void rs232isr()
{
   do
   {
       tmp=fgetc(R232); 
       if(rs232RxPtr<RS232_RX_BUFSIZ) rs232RxBuf[rs232RxPtr++]=tmp;
   } while (kbhit(R232);
}


when you get the interrupt, you can have from one to eight characters waiting. You need to read them all.
Mustang1945



Joined: 07 Jul 2015
Posts: 31
Location: Ecuador

View user's profile Send private message

PostPosted: Wed Jul 08, 2015 8:19 pm     Reply with quote

Ttelmah wrote:
No.

You need ERRORS in the #use RS232, _and_ to be testing RS232_ERRORS. Both.

'ERRORS' tells the compiler to add code to getc, to clear the error condition.

Problem is that because you do not call 'getc', if there is an error, the clearing code in getc will never be called.....

The bit test, tells the compiler if there is an error, to call the getc anyway. This then clears the error.


hi Ttelmah i understand you and i have been using both :
#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,bits=8,parity=n,ERRORS)
if(kbhit() || (bit_test(RS232_ERRORS,1)))




and now i tried this code (like you said):



receptor:


#include <16F877A.h>
#include <string.h>
#include <stdlib.h>

#FUSES NOWDT //No Watch Dog Timer
#FUSES XT
#FUSES NOPUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOCPD

#use delay(clock=4000000)

#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,bits=8,parity=n,ERRORS)

#include <INPUT.C>

void main()
{
char string[11];
signed int8 i;
char password[13]="SPITFIRE\r\n";


set_tris_b(0b00000000);
output_b(0b00000000);
while(true)
{

output_b(0b00010000);
delay_ms(1000);
output_b(0b00000000);
delay_ms(1000);


if(kbhit())

{

get_string(string,11);
i=strncmp(string, password,8);

if(i==0)
{
output_b(0b00000001);
delay_ms(1000);
}

else if(i==1)
{
output_b(0b00000010);
delay_ms(1000);
}

else if(i==-1)
{
output_b(0b00000100);
delay_ms(1000);
}

else
{
output_b(0b00000000);
delay_ms(1000);
}

}

else if (bit_test(RS232_ERRORS,1))
{
getc();
}

}
}

in the two ways the program "works" because it accepts the delay of the on and off led, but something strange happens...

.....i compare the strings and strncmp gives me 1,and after few seconds gives me -1, that means that both strings are not equals

BUT... if i comment:

ERRORS
KBHIT()
bit_test(RS232_ERRORS,1)

AND

output_b(0b00010000);
delay_ms(1000);
output_b(0b00000000);
delay_ms(1000);

.....i compare again the same strings and strncmp gives me 0, that means that both strings are equals

WHY?????????????


transmisor:
#include <16F887.h>
#FUSES XT

#use delay(clock=4000000)

#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,ERRORS,bits=8,parity=n)

void main()
{
while(true)
{
printf("SPITFIRE\r\n");
}
}
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Thu Jul 09, 2015 12:03 am     Reply with quote

Quote:
when you get the interrupt, you can have from one to eight characters waiting. You need to read them all.

I'll try that. Thanks.
Ttelmah



Joined: 11 Mar 2010
Posts: 19451

View user's profile Send private message

PostPosted: Thu Jul 09, 2015 12:52 am     Reply with quote

Would do....

Thing is that what is happening is you are getting an overflow during the delays (and possibly during the other delays later). Now when you get an overflow, the character that overflowed is lost. The extra code allows the program to recover from the overflow, but the character is still lost. So the strings will have characters missing....

There are multiple ways round this, but the easiest (assuming you have a recent compiler), is:
Code:

#use rs232(baud=9600, UART1,bits=8,parity=n,ERRORS,RECEIVE_BUFFER=16)

Now several comments apply:

1) Use the code buttons when posting code!....
2) Much safer and easier just to specify UART1, than the pins.
3) This adds a 16 character interrupt driven receive buffer to the code.
Now provided no more than 16 characters arrive in any of the delays, this should be fine.

However 'caveats'. The supplied buffer throws away 'new' data if it overflows.

If you have an older compiler, or would prefer a more sensible 'throw away the oldest' buffer handling, then use the buffer code in EX_SISR.c. Use bkbhit, instead of kbhit with this, and edit 'get_string' to use bgetc and bkbhit.
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Thu Jul 09, 2015 3:32 am     Reply with quote

the Transmit program sends SPITFIRE endlessly. This will send almost 1000 characters during the delay_ms(1000) (at 9600 baud). Buffer is not enough for that, characters lost, overflow, no sync etc.
Ttelmah



Joined: 11 Mar 2010
Posts: 19451

View user's profile Send private message

PostPosted: Thu Jul 09, 2015 3:51 am     Reply with quote

Aargh....


I hadn't looked at the transmitter (didn't even realise it was there).
Not only in the start delays, but in the delays when the code has identified the string as well.

Overkill!....

No more than once per second, would be reasonable (this was what I assumed hence enough space to store 'Spitfire' once and a few characters spare).
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