View previous topic :: View next topic |
Author |
Message |
vtrx
Joined: 11 Oct 2017 Posts: 142
|
UART string compare |
Posted: Mon Nov 01, 2021 2:58 pm |
|
|
I'm trying to implement a serial command read.
Code: |
char Rs_buf[25]
...
#int_rda
void rda_isr(void)
{
//aux=1;
Rs_buf[posi_rs] = getc();
posi_rs++;
if(posi_rs==RSTotal) //25 largura
{
posi_rs = 0;
if(strcmp(string,'desativando texto rolante'))
{do something;}
}
} |
I don't know how to 'assemble' a string to compare it using a buffer.
How would it be? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Nov 02, 2021 1:25 am |
|
|
The first key thing to learn, is that in C, a 'string', is an array of characters
_with a NULL terminator at the end_. You cannot and must not use a
string comparison, without adding this terminator character. So if you
wanted to work with a 25 character 'string', the buffer would need to be
26 characters long, and you would need to ensure that this 26th character
is a NULL before you do the comparison.
Second thing is a big 'caveat'. Interrupt handlers should always be kept
'quick'. Performing a 25 character string comparison inside an interrupt
handler is very poor practice, and may well cause problems. Remember while the processor is inside the handler doing this, it cannot do anything
else, so there becomes the risk of other interrupt events being missed...
This gets worse if 'do something' takes any time...
Now, there is another problem. What happens if a character is missed, or
an extra character is received?. By searching based on a count only,
if this happens there can never be a match.
Does the input data stream have anything 'marking' the start of the packet
or the end of a packet?. Ideally the routine should look for this character
and use this as the point where it starts or finishes the buffer write.
Now with the receive code then looking for the marker in the data to know
'where' it is, and writing the characters to the array, what should ideally
happen is to have a two dimensional array with space for two of the
received packets. When it gets to the end of the first packet, it sets
a flag to say 'use second buffer', and a flag for the main code to do the
search. The main routine when it sees this flag sets does the comparison
on the other buffer (so if 'use second buffer' is set it checks the first,
etc.). |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Nov 02, 2021 5:15 am |
|
|
Along with everything Mr. T has written....
the actual ISR should only capture the byte, insert into a buffer,set flag when full. MAIN(), when it sees the flag set, does the actual comparison/take action
I'll add, make the string comparisons short.
using your code ...
Instead of 'desativando texto rolante' use 'dtr'. Only 3 characters to compare not 25.
Make all the 'commands' or 'keywords', 3 characters long. less typing = less mistakes, easier to read the code,faster to compare. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Tue Nov 02, 2021 10:38 am |
|
|
I always use a state machine inside the ISR to decode an incoming string and then set a flag for main() when I get the correct one. No need for buffers (except maybe for debugging purposes), no comparing of strings at the end. It is all done on the fly. The downside is that for many different strings to decode the code can get quite long.I do very much agree that the incoming string should be as short as possible to make the program more easily readable and to avoid typos, if nothing else. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Nov 02, 2021 11:15 am |
|
|
Totally agree. The state machine approach is a much better way of
working. However the matching is done though, unless it is short the
actual action should be outside the ISR, |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Wed Nov 03, 2021 4:40 am |
|
|
Quote: | Remember while the processor is inside the handler doing this, it cannot do anything
else, so there becomes the risk of other interrupt events being missed...
Sad |
Although I am all for keeping code inside ISR's as short as possible, I was under the assumption that an interrupt that occurs while another one is being serviced, would be serviced right after the first was done.
If this is not the case I learned an important lesson today.
Paul |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Wed Nov 03, 2021 7:05 am |
|
|
While any pending interrupt will be serviced after the current routine has exited, if two of the same interrupt occur there will be one missed. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Wed Nov 03, 2021 7:29 am |
|
|
Exactly. With the UART, you have a maximum of two character times (one
buffer and one for the shift register), before things are missed.
If the 'do anything' code takes any significant time, then things will be missed, |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Wed Nov 03, 2021 7:59 am |
|
|
Ah, ok.
My misunderstanding then. I am glad things work as I initially thought; I use interrupts a lot and often, while I don't care about precise timing, I need to be sure that an interrupt IS handled, no matter what.
Paul |
|
|
vtrx
Joined: 11 Oct 2017 Posts: 142
|
|
Posted: Wed Nov 03, 2021 4:38 pm |
|
|
I'm back
Actually I need to decode some separate characters and know when I get a string of characters(51).
Code: |
#int_rda
void rda_isr(void)
{
int16 m;
char rx;
//....................
rx = getc();
if(rx==0x00)
{
...do something short.
return;
}else
if(rx==0x01)
{
...do something short.
return;
}else
if(rx==0x02)
{
...do something short.
return;
}else
if(rx==0x03) //+
{
...do something short.
return;
}else
if(rx==0x04) //-
{
...do something short.
return;
}else
if(rx==0x05) //>
{
...do something short.
return;
}else
if(rx==0x06) //<
{
...do something short.
return;
}else
//......if it's not the key character, i get the string of 51 characters.......
Rs_buf[posi_rs] = rx;
posi_rs++;
if(posi_rs==RSTotal) //51 chars
{
disable_interrupts(INT_RDA);
for(m=0;m<51;m++)
{
messagebuf[messagebufpos] = Rs_buf[m];
messagebufpos++;
}
enable_interrupts(INT_RDA);
}
//...............................
}
|
Do you guys think that if I always take the 51-character string and check if the first character is a key and if not, then using the entire string is more effective(will be more in sync?)?
Code: |
#int_rda
void rda_isr(void)
{
Rs_buf[posi_rs] = getc();
posi_rs++;
if(posi_rs==RSTotal) //51 chars
{
posi_rs = 0;
full = 1; //Main must do something
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1354
|
|
Posted: Wed Nov 03, 2021 5:27 pm |
|
|
vtrx wrote: |
Code: |
#int_rda
void rda_isr(void)
{
Rs_buf[posi_rs] = getc();
posi_rs++;
if(posi_rs==RSTotal) //51 chars
{
posi_rs = 0;
full = 1; //Main must do something
}
} |
|
for this i would recommend handling the "full" scenario in the ISR. Right now you would override previously good data and maybe corrupt by the time you service the data. I would at a minimum not copy any new data to the buffer until the main serviced it (to avoid corrupt data):
Code: |
#int_rda
void rda_isr(void)
{
if (full) {
getc(); //throw away value
}else{
Rs_buf[posi_rs] = getc();
posi_rs++;
if(posi_rs==RSTotal) //51 chars
{
posi_rs = 0;
full = 1; //Main must do something
}
}
} |
if you want to save that incoming data instead, you could use multiple buffers and swap between them as they fill (and just use a char * pointer to point to the message the main should look at next while the other buffers fill). You'd need some additional flags for that. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Wed Nov 03, 2021 5:28 pm |
|
|
What exactly do you want to parse? Can you post an example of at least two possible incoming strings that you are interested in? Are those strings equal in 50 characters, so you need to capture and parse them all? What do you mean by separate characters? You could look for that character and when it arrives, start filling a buffer and count to 51. Options are unlimited, but you asked a really general question without any details and that makes it hard to suggest a solution that would suit your needs. |
|
|
vtrx
Joined: 11 Oct 2017 Posts: 142
|
|
Posted: Wed Nov 03, 2021 5:37 pm |
|
|
PrinceNai wrote: | What exactly do you want to parse? Can you post an example of at least two possible incoming strings that you are interested in? Are those strings equal in 50 characters, so you need to capture and parse them all? What do you mean by separate characters? You could look for that character and when it arrives, start filling a buffer and count to 51. Options are unlimited, but you asked a really general question without any details and that makes it hard to suggest a solution that would suit your needs. |
Imagine, the hardware controls a TV (fictional example).
'+' Increase brightness.
'-' decreases etc.
The TV can send a text(51 char, it's actually much more).
'+' and '-' control the image, the rest is received text with fixed size. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Wed Nov 03, 2021 5:47 pm |
|
|
What you are looking for are distinct strings. Let's say "+ " sends aaaaaaaaaaaaaabbbaaaaaaaaaaaaa. "-" sends aaaaaaaaaaaccccaaaaaa. You need to filter out the distinct part of the message. In my example that would be three consecutive b's or c's. It doesn't matter how long the incoming message is. |
|
|
|