Ich möchte den UART Datenstrom überwachen, und wenn bestimmte 7 Zeichen auf dem Bus vorkommen, dann soll etwas ausgelöst werden. Ich habe es zunächst so versucht... Ich habe einen 7 Byte großen Ringpuffer geschrieben, der jedes mal absucht, wenn ein neues Zeichen dazu gekommen ist, ob die 7 Zeichen überein stimmen: void check_rx0_buffer(void) { unsigned int c; c = uart_getc(); //hier kommt das nächste Byte an if ( c & UART_NO_DATA ){ //Peters Lib } else { rx0_buffer[6] = rx0_buffer[5]; //hier wird es in den Ringpuffer geschoben rx0_buffer[5] = rx0_buffer[4]; rx0_buffer[4] = rx0_buffer[3]; rx0_buffer[3] = rx0_buffer[2]; rx0_buffer[2] = rx0_buffer[1]; rx0_buffer[1] = rx0_buffer[0]; rx0_buffer[0] = ((uint8_t)(c)); mmi_rx0_string_analyze(); } } void mmi_rx0_string_analyze (void) { cmp_buffer[6] = 0x01; // vergleichs-array zum test einfach mal fest definiert cmp_buffer[5] = 0x02; cmp_buffer[4] = 0x03; cmp_buffer[3] = 0x04; cmp_buffer[2] = 0x05; cmp_buffer[1] = 0x06; cmp_buffer[0] = 0x07; if(memcmp(rx0_buffer, cmp_buffer, 6)) { //noch nicht die richtige Zeichenfolge erkannt } else { //die zeichen wurden erkannt } } Dieses funktioniert soweit auch, nur dauert die ganze Prozedur bei einem 8MHz Atmega128 ganze 7ms (compiliert mit AVR-GCC). Das würde bedeuten, dass er nicht bei jeden ankommenden Byte eines 9600 Baud Datenstroms rechtzeitig fertig sein würde. Das würde gerade noch ausreichen, weil ich habe ja noch den Empfangsbuffer von Peters Library, und der Datenstrom hat viele Pausen dazwischen, aber Euch Profis fällt bestimmt eine effektivere Methode ein?!? Es soll nämlich auch noch auf 10 verschiedene Zeichenketten überwacht werden, wo ich bestimmt auf 50-80ms kommen würde. Nicht erschrecken, ich bin erst vor 2 Tagen von Assembler auf C umgestiegen, deshalb ist der Code noch sehr roh :c)
http://de.wikipedia.org/wiki/Warteschlange_%28Datenstruktur%29#Implementierung_als_Ringpuffer Zu dem Problem einen String in einem anderen zu finden, wobei die Anfangsposition sich verändern kann, gucke mal in "Algorithmen in C" von Sedgkwick. Gibts, denke ich, auch online.
Ich habe gerade einen Fehler entdeckt. Die durchgeführte Messung (7ms) stimmt nicht. Ich habe natürlich 7 Bytes auf dem UART Bus abgewartet, bis ich zu ende vergleichen habe. Richtig ist: Die Buffer Schieberei dauert 50µs und der Zeichenkettenvergleich dauert auch nochmal 55µs. Ist also alles im grünen bereich. Aber Euch fällt bestimmt eine schönere Vergleichvariante ein, oder?
Zusätzlich zu den 7 gespeicherten Daten könnte man noch ein Byte spendieren, in dem der XOR-Wert aller eingetragenen Zeichen hinterlegt ist (Parity-Byte). Dieses Parity-Byte muß nicht bei jedem neuen Zeichen aus allen 7 neu berechnet werden, sondern es genügt mit dem alten hinausgeworfenen Zeichen wieder einen XOR-Wert zu bilden, um es auszutragen, ebenso mit dem neuen hinzugekommenen, um dieses einzutragen. Ebenfalls bildet man den XOR-Wert der Vergleichsfolge. Wenn ich das richtig verstehe, ändert die sich ja nicht, also muß deren Parity-Wert nur einmal bestimmt werden. Durch diesen Mehraufwand hat man jederzeit das Parity-Byte der Vergleichsfolge und das Parity-Byte der 7 Zeichen aus dem Datenstrom. Der Vorteil: es reicht als Vortest, diese beiden zu vergleichen. Erst wenn die beiden Parity-Bytes gleich sind (was nur selten vorkommen wird, genau genommen in 1/256 aller Fälle), könnte ein Treffer vorliegen, und man vergleicht dann die Zeichen Byte für Byte. Unterm Strich (vermute ich) geht das deutlich schneller.
Die Idee ist genial, somit vergleicht man bei jedem ankommenden Byte nur 2 Bytes... Jedoch könnte sich da wirklich ein Fehler einschleichen, weil: Mein Datenstrom sieht z.B. so aus: 0x35, 0x56, 0x23, 0x67, 0x50, 0x23, 0x77 oder auch 0x35, 0x56, 0x23, 0x67, 0x23, 0x50, 0x77 Wenn ich die ersten 5 Bytes schon erfolgreich durch habe kommt beim 6ten Byte bei beiden Zeichenketten der gleiche XOR Wert heraus. Beim testen des 7ten Bytes würde ich dann gar nicht mehr wissen welche Zeichenkette von beiden es war. Aber Deine Idee bleibt in meiner Sammlung als mögliche Methoden :c) Noch eine Idee?
Bei einem solchen Dreher, bei dem zufällig der gleiche XOR-Wert aus beiden Folgen kommt, käme dann der Notausgang zum Zug und es müssten (wie ich bereits erwähnte) dann doch alle 7 Bytes verglichen werden. (Natürlich kann ich nicht in einem Byte die vollständige Information von 7 Byte halten, das wäre eine tolle Kompression.) Nur wird das halt nicht sehr häufig sein (bei zufälligen Daten in weniger als 0.5% der Fälle).
Danke, Mmmh Bei Deinem Link wird der Inhalt des Ringpuffers nicht verschoben, sondern mit IN und Out Pointern gearbeitet. Das würde das Abspeichern neuer Bytes etwas verkürzen, aber nicht das vergleichen. Noch eine Idee?
Ahhh, verstehe... Am Schluss nochmal eine komplette Prüfung... Danke, Klaus. Kann man das Vergleichen vom Array irgendwie einzeilig lösen? z.B. so:? if(memcmp(rx0_buffer, (0x35, 0x56, 0x23, 0x67, 0x50, 0x23, 0x77) , 6)) oder so:? if(memcmp(rx0_buffer, "Test12" , 6))
Den Ringpuffer ständig zu rotieren, ist natürlich Verschwendung. Eine Schleife von i=0...6 und Zugriff auf das Feld über rx0_buffer(i+aktuellerOffset)%7 wäre in der Tat viel effizienter. Außerdem legst du im Moment bei jedem Vergleich das lokale Feld cmp_buffer neu an. Tut das Not?
mach das Feld mit den Vergleichswerten doch einfach static, dann wird es nur einmal bei Programmstart angelegt.
>Danke, Mmmh >Bei Deinem Link wird der Inhalt des Ringpuffers nicht verschoben, Genau so macht man das. NIEMAND verschiebt Bytes in einem Puffer. >sondern mit IN und Out Pointern gearbeitet. Das würde das Abspeichern >neuer Bytes etwas verkürzen, aber nicht das vergleichen. >Noch eine Idee? Nun, das abspeichern zu verkürzen wäre aus meiner Sicht schon ein Gewinn. Und der andere Hinweis? Schon gelesen? Noch ein Stichwort dazu: Knuth-Morris-Pratt-Algorithmus
Mmmh schrieb:
> Knuth-Morris-Pratt-Algorithmus
Hm, das ist ziemlich viel Code und lohnt sich vielleicht eher
bei längeren Texten?
>Außerdem legst du im Moment bei jedem Vergleich das lokale Feld >cmp_buffer neu an. Tut das Not? Ich werde ja 10 verschiedene Zeichenketten vergleichen. Im Moment weiss ich mir nicht anders zu helfen, als die erste Zeichekette in den cmp_buffer zu legen, vergleichen, dann die zweite Zeichenkette in den cmp_buffer zu legen und wieder vergleichen usw. Das ist hier bei dem Beispielcode noch nicht sichtbar. Deshalb aber auch meine Frage, ob man den Vergleich von 10 verschiedenen Zeichenketten einzeilig lösen kann. z.B. if(memcmp(rx0_buffer, (0x35, 0x56, 0x23, 0x67, 0x50, 0x23, 0x77) , 6))... if(memcmp(rx0_buffer, (0x35, 0x78, 0x23, 0x67, 0x23, 0x50, 0x77) , 6))... if(memcmp(rx0_buffer, (0x66, 0x56, 0x23, 0x55, 0x50, 0x23, 0x87) , 6))... if(memcmp(rx0_buffer, (0x65, 0x56, 0x33, 0x67, 0x50, 0x10, 0x05) , 6))... . . .
>mach das Feld mit den Vergleichswerten doch einfach static, dann >wird es nur einmal bei Programmstart angelegt. Ja, ich habe die Puffer am Anfang deklariert: unsigned char rx0_buffer[7]; unsigned char cmp_buffer[7]; Sie werden also nicht immer neu angelegt, sondern bei jedem Vergleich neu beschrieben. >Knuth-Morris-Pratt-Algorithmus Ja, in 6 Zeilen nur 6 Bytes zu verschieben ist schneller, als mit In und Out Pointern zu rechnen, das lohnt sich eher beim 128 Byte Puffer, wie in Peters Lib, aus der ich die Zeichen ja auch heraus hole.
Erstens: das mit memcmp macht eh keinen Sinn, weil du dafür deinen Ringpuffer ingesamt rotieren müsstest, und das ist wie mehrfach gesagt Unfug. Sinnvoller wäre es, den Vergleich selbst zu schreiben; dann kann man mit %7 in den Puffer fassen. Zweitens: mach doch einmal ein Feld mit allen deinen Vergleichsmustern, und vergleiche mal mit dem einen und mal mit dem anderen Feldelement (was dann jeweils ein Zeiger auf die 7 Zeichen ist).
Klaus Wachtler schrieb: >> Knuth-Morris-Pratt-Algorithmus > > Hm, das ist ziemlich viel Code und lohnt sich vielleicht eher > bei längeren Texten? Möglicherweise passt der Algorithmus hier nicht so gut. Das ist mir halt bei der Problembeschreibung eingefallen. Danach ist die Position des Schlüsselwortes im Zeichenstrom nicht festgelegt und es gibt keine Synchronzeichen (irgendeine Art von Protokoll). Die anderen Ideen hier gehen auch in die Richtung, das Ergebnis schon durchgeführter aber letztlich fehlgeschlagener (Teil-)Vergleiche zu speichern. Sowas in der Richtung habe ich intuitiv mit Knuth-Pratt verbunden.
Es geht hier übrigens nicht um eine Warteschlange mit variabler Länge, sondern immer um 7 Byte. Deshalb brauchst du nicht getrennt In- und Out-Pointer, es reicht ein Index. Je nach Laune kann der das letzte eingetragene Zeichen indizieren oder das nächste.
BTW: wieso werden bei deinem memcmp nur 6 Byte verglichen?
Danke Klaus, >dann kann man mit %7 in den Puffer fassen. das mit %7 kenne ich noch nicht. Kannst Du mal ein paar Einzelheiten geben? >mach doch einmal ein Feld mit allen deinen Vergleichsmustern leuchtet ein, gute Idee. Das wird aber auch ein ganz schöner Code, nur für die 10*7 Bytes? Bei 100*7 Bytes wäre das bisher die effektivste Idee.
>BTW: wieso werden bei deinem memcmp nur 6 Byte verglichen?
Weil ich nicht wusste, ob er von 0-6 oder von 1-7 zählt :c) Array geht
nur von 0-6, deklariert ist es mit rx0_buffer[7]. Beim benutzen des
rx_buffer[7] hat mit der GCC jedoch einen Fehler ausgespukt, dass der
Wert höher ist, als das definierte Array. Beim memcmp wollte ich erst
einmal kein Risiko eingehen und hätte es später durch testen erkannt, ob
er die 6 oder 7 braucht :c)
Nach Deinem Kommentar gehe ich mal von der 7 aus :c)
es gibt auch Doku zu memcmp(). Probieren ist natürlich auch ein Weg. Warte mal. ich mache ein Beispiel...
Ich habe gerade festgestellt, dass memcmp nicht alles vergleicht, sondern abbricht, wenn das erste Byte schon nicht stimmt. Somit vergleicht er eigentlich genau so schnell/effektiv, als das vergleichen des Arrays mit einem Pointer. Nur das herumschieben beim Emfang ist nicht schön. Aber mit 50µs kann ich voll leben. Ich würde nur gerne den cmp_array schöner befüllen. Im Assember konnte ich die Zeichenketten einfach in eine db schreiben: Zeichenkette 1: .db 0x35, 0x56, 0x23, 0x67, 0x50, 0x23, 0x77) Zeichenkette 2: .db 0x35, 0x78, 0x23, 0x67, 0x23, 0x50, 0x77) . . Um in C das memcmp damit zu füttern wäre ein zweidimensionales Array sinnvoll. Wie befülle ich das Array am schönsten mit diesen Werten? Mir fällt nur das ein: cmp_array[0][0] = 0x35; cmp_array[0][1] = 0x56; . . . Da gibts doch bestimmt was schöneres oder?
So würde es ohne die XOR-Geschichte aussehen (inkl. kleinem Testprogramm, 10 verschiedenen Tests und Ringpuffer ohne verschieben):
1 | #include <stdlib.h> |
2 | #include <stddef.h> |
3 | #include <stdio.h> |
4 | #include <string.h> |
5 | |
6 | |
7 | // nur zum Test: simuliert die Bytes von der UART:
|
8 | static int i = 0; |
9 | static char simulationsdaten[] = |
10 | {
|
11 | "hallo ich bin doof, aber gottseidank weiss ich es nicht, "
|
12 | "bin aber nicht der einzige."
|
13 | "Jedenfalls noch helle genug, um mein Geld ehrlich zu verdienen."
|
14 | "Noch muss ich nicht bei der FDP anheuern..."
|
15 | };
|
16 | const int nSimulationsdaten = sizeof(simulationsdaten); |
17 | |
18 | unsigned int uart_getc() |
19 | {
|
20 | |
21 | return simulationsdaten[i++%nSimulationsdaten]; |
22 | }
|
23 | const int UART_NO_DATA = 0xff00; // nie ein gültiges Zeichen, nur zum Testen |
24 | |
25 | |
26 | |
27 | // Demo, wie ich mir das vorstelle:
|
28 | |
29 | |
30 | |
31 | // Der Index, wo im Ringpuffer das NÄCHSTE Zeichen abzulegen ist:
|
32 | static int ndx_RingpufferNext = 0; |
33 | static char rx0_buffer[7] = { 0 }; |
34 | |
35 | // Die Vergleichsfolgen:
|
36 | char *cmp_buffer_arr[10] = |
37 | {
|
38 | "\x35\x56\x23\x67\x50\x23\x77", // zum Testen 0 angehängt... |
39 | "\x35\x78\x23\x67\x23\x50\x77", // zum Testen 0 angehängt... |
40 | "\x66\x56\x23\x55\x50\x23\x87", // zum Testen 0 angehängt... |
41 | "\x65\x56\x33\x67\x50\x10\x05", // zum Testen 0 angehängt... |
42 | "Jedenfa", |
43 | "nheuern", |
44 | "einzige", |
45 | "ich bin", |
46 | "es nich", |
47 | "Noch mu", |
48 | };
|
49 | |
50 | |
51 | |
52 | // vergleicht 7 Zeichen aus rx0_buffer (ab Position
|
53 | // (ndx_RingpufferNext+1) modulo 7) mit den 7 Zeichen ab cmp_buffer
|
54 | // und liefert 0, wenn nicht gleich bzw. 1, wenn gleich:
|
55 | int mmi_rx0_string_analyze ( const char *cmp_buffer ) |
56 | {
|
57 | int iZeichen; |
58 | for( iZeichen=0; iZeichen<7; ++iZeichen ) |
59 | {
|
60 | if( rx0_buffer[(ndx_RingpufferNext+iZeichen)%7]!=cmp_buffer[iZeichen] ) |
61 | {
|
62 | return 0; |
63 | }
|
64 | }
|
65 | return 1; |
66 | }
|
67 | |
68 | |
69 | |
70 | void check_rx0_buffer() |
71 | {
|
72 | unsigned int c; |
73 | c = uart_getc(); //hier kommt das nächste Byte an |
74 | if ( c & UART_NO_DATA ) |
75 | { //Peters Lib |
76 | }
|
77 | else
|
78 | {
|
79 | int iVergleich; |
80 | rx0_buffer[ndx_RingpufferNext++] = c; // c eintragen, |
81 | // ndx_RingpufferNext weiter setzen
|
82 | ndx_RingpufferNext %= 7; // ndx_RingpufferNext auf |
83 | // 0...6 begrenzen
|
84 | |
85 | for( iVergleich=0; iVergleich<10; ++iVergleich ) |
86 | {
|
87 | if( mmi_rx0_string_analyze( cmp_buffer_arr[iVergleich] ) ) |
88 | {
|
89 | printf( "Text %s gefunden\n", cmp_buffer_arr[iVergleich] ); |
90 | }
|
91 | }
|
92 | }
|
93 | }
|
94 | |
95 | |
96 | |
97 | int main( int nargs, char **args ) |
98 | {
|
99 | int iGelesen; |
100 | for( iGelesen=0; iGelesen<nSimulationsdaten; ++iGelesen ) |
101 | {
|
102 | check_rx0_buffer(); |
103 | }
|
104 | return 0; |
105 | }
|
Das %7 berechnet aus einem Wert dessen Divisionsrest beim Teilen durch 7. D.h. der Wert in den Bereich 0 bis 6 verschoben und der Index bleibt dadurch immer im Feld; anstatt hinten rauszulaufen fängt man wieder vorne an.
Der Vollständigkeit halber hier noch die Variante mit XOR (läuft auf meinem PC unter Linux mit gcc ohne Optimierung um Faktor 3 schneller):
1 | #include <stdlib.h> |
2 | #include <stddef.h> |
3 | #include <stdio.h> |
4 | #include <string.h> |
5 | |
6 | #define PARITY_BESCHLEUNIGUNG
|
7 | |
8 | |
9 | // nur zum Test: simuliert die Bytes von der UART:
|
10 | static int i = 0; |
11 | static char simulationsdaten[] = |
12 | {
|
13 | "hallo ich bin doof, aber gottseidank weiss ich es nicht, "
|
14 | "bin aber nicht der einzige."
|
15 | "Jedenfalls noch helle genug, um mein Geld ehrlich zu verdienen."
|
16 | "Noch muss ich nicht bei der FDP anheuern..."
|
17 | };
|
18 | const int nSimulationsdaten = sizeof(simulationsdaten); |
19 | |
20 | unsigned int uart_getc() |
21 | {
|
22 | |
23 | return simulationsdaten[i++%nSimulationsdaten]; |
24 | }
|
25 | const int UART_NO_DATA = 0xff00; // nie ein gültiges Zeichen, nur zum Testen |
26 | |
27 | |
28 | |
29 | // Demo, wie ich mir das vorstelle:
|
30 | |
31 | |
32 | |
33 | // Der Index, wo im Ringpuffer das NÄCHSTE Zeichen abzulegen ist:
|
34 | static int ndx_RingpufferNext = 0; |
35 | static char rx0_buffer[7] = { 0 }; |
36 | |
37 | #ifdef PARITY_BESCHLEUNIGUNG
|
38 | // Parity-Byte des Ringpuffers:
|
39 | static char parity_rx0_buffer = 0; |
40 | #endif
|
41 | |
42 | |
43 | // Die Vergleichsfolgen:
|
44 | char *cmp_buffer_arr[10] = |
45 | {
|
46 | "\x35\x56\x23\x67\x50\x23\x77", // zum Testen 0 angehängt... |
47 | "\x35\x78\x23\x67\x23\x50\x77", // zum Testen 0 angehängt... |
48 | "\x66\x56\x23\x55\x50\x23\x87", // zum Testen 0 angehängt... |
49 | "\x65\x56\x33\x67\x50\x10\x05", // zum Testen 0 angehängt... |
50 | "Jedenfa", |
51 | "nheuern", |
52 | "einzige", |
53 | "ich bin", |
54 | "es nich", |
55 | "Noch mu", |
56 | };
|
57 | |
58 | #ifdef PARITY_BESCHLEUNIGUNG
|
59 | // Parity-Bytes der Vergleichsfolgen:
|
60 | static char parity_cmp_buffer_arr[10]; |
61 | #endif
|
62 | |
63 | |
64 | // vergleicht 7 Zeichen aus rx0_buffer (ab Position
|
65 | // (ndx_RingpufferNext+1) modulo 7) mit den 7 Zeichen ab cmp_buffer
|
66 | // und liefert 0, wenn nicht gleich bzw. 1, wenn gleich:
|
67 | int mmi_rx0_string_analyze ( const char *cmp_buffer ) |
68 | {
|
69 | int iZeichen; |
70 | for( iZeichen=0; iZeichen<7; ++iZeichen ) |
71 | {
|
72 | if( rx0_buffer[(ndx_RingpufferNext+iZeichen)%7]!=cmp_buffer[iZeichen] ) |
73 | {
|
74 | return 0; |
75 | }
|
76 | }
|
77 | return 1; |
78 | }
|
79 | |
80 | |
81 | |
82 | void check_rx0_buffer() |
83 | {
|
84 | unsigned int c; |
85 | c = uart_getc(); //hier kommt das nächste Byte an |
86 | if ( c & UART_NO_DATA ) |
87 | { //Peters Lib |
88 | }
|
89 | else
|
90 | {
|
91 | int iVergleich; |
92 | #ifdef PARITY_BESCHLEUNIGUNG
|
93 | // alten Wert austragen:
|
94 | parity_rx0_buffer ^= rx0_buffer[ndx_RingpufferNext]; |
95 | #endif
|
96 | rx0_buffer[ndx_RingpufferNext++] = c; // c eintragen, |
97 | // ndx_RingpufferNext weiter
|
98 | // setzen
|
99 | ndx_RingpufferNext %= 7; // ndx_RingpufferNext auf |
100 | // 0...6 begrenzen
|
101 | #ifdef PARITY_BESCHLEUNIGUNG
|
102 | // neuen Wert eintragen:
|
103 | parity_rx0_buffer ^= c; |
104 | #endif
|
105 | |
106 | for( iVergleich=0; iVergleich<10; ++iVergleich ) |
107 | {
|
108 | if( |
109 | #ifdef PARITY_BESCHLEUNIGUNG
|
110 | parity_rx0_buffer==parity_cmp_buffer_arr[iVergleich] |
111 | &&
|
112 | #endif
|
113 | mmi_rx0_string_analyze( cmp_buffer_arr[iVergleich] ) |
114 | )
|
115 | {
|
116 | //printf( "Text %s gefunden\n", cmp_buffer_arr[iVergleich] );
|
117 | }
|
118 | }
|
119 | }
|
120 | }
|
121 | |
122 | |
123 | |
124 | int main( int nargs, char **args ) |
125 | {
|
126 | int iGelesen; |
127 | |
128 | #ifdef PARITY_BESCHLEUNIGUNG
|
129 | // einmalig die Parity-Bytes der Vergleichsstrings intialisieren:
|
130 | int iVergleich; |
131 | for( iVergleich=0; iVergleich<10; ++iVergleich ) |
132 | {
|
133 | int iByte; |
134 | for( iByte=0; iByte<7; ++iByte ) |
135 | {
|
136 | parity_cmp_buffer_arr[iVergleich] ^= cmp_buffer_arr[iVergleich][iByte]; |
137 | }
|
138 | }
|
139 | #endif
|
140 | |
141 | size_t i; |
142 | for( i=0; i<500000; ++i ) |
143 | {
|
144 | for( iGelesen=0; iGelesen<nSimulationsdaten; ++iGelesen ) |
145 | {
|
146 | check_rx0_buffer(); |
147 | }
|
148 | }
|
149 | return 0; |
150 | }
|
Wow, danke, Klaus. Das mit %7 ist eine geniale Funktion. Ich bereue es jetzt schon auf keinen Fall von Assembler auf C umgestiegen zu sein. Mit jeder Funktion, die man dazu lernt, eröffnen sich neue Welten :c) >char *cmp_buffer_arr[10] = > { > "\x35\x56\x23\x67\x50\x23\x77", // zum Testen 0 angehängt... > "\x35\x78\x23\x67\x23\x50\x77", // zum Testen 0 angehängt... > "\x66\x56\x23\x55\x50\x23\x87", // zum Testen 0 angehängt... > "\x65\x56\x33\x67\x50\x10\x05", // zum Testen 0 angehängt... > "Jedenfa", > "nheuern", > "einzige", > "ich bin", > "es nich", > "Noch mu", > }; > Genau das brauche ich. Danke dafür. Was bedeutet eigentlich dieser Stern (*) vor dem cmp_buffer_arr[10] ? ich werde mir jetzt mal die Arbeit machen und schauen welche Vergleichsmethode schneller ist :c)
Igor Ebner schrieb: > Genau das brauche ich. Danke dafür. Was bedeutet eigentlich dieser Stern > (*) vor dem cmp_buffer_arr[10] ? weil cmp_buffer_arr ein Feld von 10 Zeigern auf char ist. Jeder dieser Zeiger zeigt dann auf den Anfang eines der Teilfelder. > > > ich werde mir jetzt mal die Arbeit machen und schauen welche > Vergleichsmethode schneller ist :c) Meine natürlich, weiß ich vorher :-)
So, als erstes mal Dein Messergebnis vom ersten code ohne XOR: Das schieben in den Ringpuffer per %7 dauerte bei jedem ankomenden Byte 100µs. Das Auswerten dauerte dann 400µs. Wenn ich meine Methode verwende und die Bytes im ir_buffer herum schiebe, dauert die Herumschieberei inkl laden des 7.ten Bytes 40µs. Und das Auswerten per memcmp nochmal 100µs. Ich denke bei so wenig Zeichen macht die dumme Methode weniger Rechenaufwand. Deine Methode würde sich - rein theoretisch und rechnerisch, ab ca 20 Zeichen lohnen. Die XOR Methode habe ich nicht mehr ausprobiert, aber die wird vermutlich an 40/100µs nicht ran kommen :c) Trotzdem vielen Dank an Dich, dass Du dir so viel Mühe gemacht hast. Du hast mir mehrere tolle Sachen beigebracht... %7 XOR compression und *cmp_buffer_arr ...und ich werde Dich heute in mein Nachtgebet mit Aufnehmen :c)
Ich auch, da bekommt die Aussage Dich ins Gebet mit aufzunehmen eine ganz neue Bedeutung :c)
In der Tat. Um nicht zu sagen, das mit dem Gebet war doch irgendwie gelogen :-)
Eine Alternative bei einer/wenigen festen Vergleichszeichenkette(n) wäre, den Zeichenstrom in einen Zustandsautomaten zu leiten, in diesem Fall ist das wegen des enormen Schreibaufwandes natürlich fehl am Platz und ca. halb so schnell. (allerdings auf meinem PC mit -O3 um ca. 1% schneller ;) )
1 | void CheckForHELLO(uint8_t ch) |
2 | {
|
3 | static uint8_t CharactersOK = 0; |
4 | switch (CharactersOK) |
5 | {
|
6 | case 0: |
7 | if (ch == 'H') |
8 | CharactersOK = 1; |
9 | else
|
10 | CharactersOK = 0; |
11 | break; |
12 | case 1: |
13 | if (ch == 'E') |
14 | CharactersOK = 2; |
15 | else
|
16 | CharactersOK = 0; |
17 | break; |
18 | case 2: |
19 | if (ch == 'L') |
20 | CharactersOK = 3; |
21 | else
|
22 | CharactersOK = 0; |
23 | break; |
24 | case 3: |
25 | if (ch == 'L') |
26 | CharactersOK = 4; |
27 | else
|
28 | CharactersOK = 0; |
29 | break; |
30 | case 4: |
31 | if (ch == 'O') |
32 | DoSomething(); |
33 | CharactersOK = 0; |
34 | break; |
35 | }
|
36 | }
|
Hört er dann nicht auf, wenn der erste Buchstabe getestet wurde? Wie kommt er zu den weiteren cases?
Die Idee dieses Konstrukts ist es, dass nicht erst gewartet wird, bis der String komplett empfangen wurde, sondern jedes Zeichen, sobald es empfangen wurde, in dieses Konstrukt eingeleitet wird. Und so handelt sich dieses Konstrukt von einem case zum nächsten (bei jeweils dem nächsten Funktionsaufruf mit dem jeweils gültigen Zeichen).
Ahhhh, verstehe... :c) Wenn man jedoch 10 verschiedene Zeichenketten zum überwachen hat, dann ist der Aufwand aber nicht mehr geringer, als mit einem Rollpuffer...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.