View previous topic :: View next topic |
Author |
Message |
id31
Joined: 19 Dec 2014 Posts: 16
|
Problem to get strings with getc |
Posted: Thu Feb 02, 2017 5:42 am |
|
|
Hi all,
I'm using PIC18f8722.
I try to get a string in UART. The Uart pins is not the hw pins (PINS D2, D7).
My method is to getc(STREAM) every char to an array of chars. the program call getc only after kbhit(STREAM).
when I use the same methods for numbers (hex) it works well.
when I use fprintf() the data is going well to my PC.
Example:
Code: |
if (kbhit(stream_name)
x[i]=getc(stream_name);
|
BUT when I'm using to get an array of chars i got garbage..
1. when i send long string after couple of garbage chars i got the correct data.
2. when i use getc() without kbhit() it works well.
Do you have an idea what is wrong and how to do it right? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Thu Feb 02, 2017 5:57 am |
|
|
EVERY time you use the hardware UART you MUST add 'errors' to the uses rs232(...options...), EVERY time.
Since you didn't post your code, I will assume 'errors' is not in the list.
It is required into order for the compiler to add a bit of code to keep the UART from 'locking up' after 2-3 characters are received.
Also you should look at the ex_sisr.c example program, as ANY serial input should be done in an ISR ( Interrupt Service Routine). This allows the pIC to do a LOT more than just wait for 'something' to come in.
Jay |
|
|
id31
Joined: 19 Dec 2014 Posts: 16
|
|
Posted: Thu Feb 02, 2017 6:01 am |
|
|
Hi, thank you for the quick reply.
As i wrote before - the uart is not HW so i use kbhit() instead of int_rda.
when i configured the uart i added errors. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Thu Feb 02, 2017 6:27 am |
|
|
oops... gues I need TRIfocals.....sigh,getting old ...
OK have to ask why can't you use the HW UART?
You should post your serial ISR so we can see. All ISRs must be small and fast, NO fancy math, no prints, no delays.....
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Thu Feb 02, 2017 6:39 am |
|
|
Problem is time.
Understand that 'kbhit' will only return true, once the character has already started. So using kbhit, you will be late actually starting to receive the character. Use the option 'SAMPLE_EARLY' in your #use rs232 setup. This tells the getc code to not wait half a bit time after being called.
Also understand that using software serial, you can only send or receive at any time. If data arrives while you are sending, it will be lost. |
|
|
id31
Joined: 19 Dec 2014 Posts: 16
|
|
Posted: Thu Feb 02, 2017 6:52 am |
|
|
The other UARTs is for other communication serials (I have 3 "ports").
I tried "SAMPLE EARLY" but it didn't help.
still I got the start of the string wrong and after correct.
the method is:
char a[100]={0};
run_timer4(); //I have a function that when interrupt it set timeout=TRUE
for (int i=0;i<100;i++)
{
while ((!kbhit(UART_STREAM) && (!timout))
{
a[i]=getc(UART_STREAM);
}
} |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Thu Feb 02, 2017 7:05 am |
|
|
You need fgetc() for streams.
Also, understand that your timing must be very tight and you shouldn't use interrupts while receiving data. Interrupts can corrupt the data stream when doing SW uart. There is an option to DISABLE_INTS in the #use rs232() directive that is specifically for SW uarts. |
|
|
id31
Joined: 19 Dec 2014 Posts: 16
|
|
Posted: Thu Feb 02, 2017 7:44 am |
|
|
I used fgetc() - didn't change the results..
I enable "DISABLE_INTS" - still the same..
:( |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Thu Feb 02, 2017 7:50 am |
|
|
Your new logic is testing the wrong way round. You are calling the getc, when kbhit is not true:
Code: |
char a[100]={0};
run_timer4(); //I have a function that when interrupt it set timeout=TRUE
for (int i=0;i<100;i++)
{
while ((!kbhit(UART_STREAM) && (!timout))
; //wait for either a timeout or a character
if (timout) //
break; //exit if a timeout
a[i]=getc(UART_STREAM); //otherwise get character
}
|
|
|
|
id31
Joined: 19 Dec 2014 Posts: 16
|
|
Posted: Thu Feb 02, 2017 8:27 am |
|
|
OK!
it solved.
first of all - thank you for the quick replies!
YOU WERE RIGHT ALL THE TIME - the problem is time.
it was my fault not to paste the exact code..
the exact code is
char a[100];
if (kbhit(UART_STREAM))
{
for (int i=0;i<100;i++)
{
a[i]=0;
}
run_timer4(); //I have a function that when interrupt it set timeout=TRUE
for (int i=0;i<100;i++)
{
while ((!kbhit(UART_STREAM) && (!timout))
{
a[i]=getc(UART_STREAM);
}
}
}
}
the bolded text (init the array) took too much time. so I init at when declared (as i wrote i did.. ) and it solved!
so - thank you and im sorry, i learned for the next time.
I have 2 more questions please:
1. I have 2MHz crystal - so why the init of the array took so much time?
2. Why did you advise me to use fgetc and not getc? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Thu Feb 02, 2017 11:48 am |
|
|
id31 wrote: |
I have 2 more questions please:
1. I have 2MHz crystal - so why the init of the array took so much time?
2. Why did you advise me to use fgetc and not getc? |
#2 first: The compiler officially supports fgetc for streams, not getc. Using unsupported things (even if they work) is a bad idea.
#1
2MHZ crystal = 500kHz instruction clock => 2us instruction time. You are looping through 100 elements. Assuming around 10 instructions per assignment/loop test/loop increment:
2us * 100 elements * 10 instructions = 2ms
If you are operating anything 9600 baud or faster, then you can miss edge transitions in a software UART. Reception with a software UART is very tricky to get right in complicated designs. I would offer that you reconsider your design and see if one of the other UART connections is more suited to SW uart and make this one HW if possible. If a connection only transmits, for example, it is a better candidate for SW uart. Or if you know the exact time a response comes and the exact size of the data, then it is a better candidate. Anything that lets you avoid taking up time doing other things. Also consider bumping up the speed of your clock. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Thu Feb 02, 2017 12:51 pm |
|
|
It's also worth asking 'why'.
Just clear the array before you start waiting for the character.
Understand that with the software UART, when you see 'kbhit' you are already inside the character being received, and you have less than half a bit time to actually start reading the data.
There is actually no point in clearing the array anyway. Just write a null when you exit (last character or timeout). The rest of the array is being filled with the characters as they are received. |
|
|
|