|
|
View previous topic :: View next topic |
Author |
Message |
Mustang1945
Joined: 07 Jul 2015 Posts: 31 Location: Ecuador
|
Problem with a delay before a getc() function |
Posted: Tue Jul 07, 2015 10:35 am |
|
|
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
|
|
Posted: Tue Jul 07, 2015 11:33 am |
|
|
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: 19553
|
|
Posted: Tue Jul 07, 2015 1:34 pm |
|
|
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
|
|
Posted: Tue Jul 07, 2015 10:06 pm |
|
|
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
|
|
Posted: Wed Jul 08, 2015 12:30 am |
|
|
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: 19553
|
|
Posted: Wed Jul 08, 2015 2:46 am |
|
|
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
|
|
Posted: Wed Jul 08, 2015 1:33 pm |
|
|
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: 19553
|
|
Posted: Wed Jul 08, 2015 1:48 pm |
|
|
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
|
|
Posted: Wed Jul 08, 2015 2:03 pm |
|
|
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: 19553
|
|
Posted: Wed Jul 08, 2015 2:48 pm |
|
|
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
|
|
Posted: Wed Jul 08, 2015 8:19 pm |
|
|
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
|
|
Posted: Thu Jul 09, 2015 12:03 am |
|
|
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: 19553
|
|
Posted: Thu Jul 09, 2015 12:52 am |
|
|
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
|
|
Posted: Thu Jul 09, 2015 3:32 am |
|
|
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: 19553
|
|
Posted: Thu Jul 09, 2015 3:51 am |
|
|
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). |
|
|
|
|
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
|