Hallo zusammen,
ich benütze einen Texteditor, die Avr Gcc Toolchain mit Makefile auf
einem Macbook, und mein Mikrocontroller ist ein Atmega 328 P, und ich
programmiere in C. Die Uart Bibliothek ist die von P. Fleury.
Es soll vom Terminalprogramm Coolterm das Wort „Start“ über Uart
geschickt werden, und der uC drauf reagieren (momentan durch das
Anzünden einer Led).
Was ich schon geschafft hab ist mit strcmp einen vorher initialisierten
String mit meiner Vorgabe zu vergleichen und das Ergebnis zu verwerten,
und auch mit strtok einen String am : zu trennen, und mit den
Einzelstrings weiter zu machen.
Ich häng aber irgendwie beim Empfang von mehr als einem Zeichen. Mein
Chararray schaut z. Zt. so aus char test[6] und es passen demnach 5
Zeichen rein plus die \0, als Markierung für Stringende.
Es wird auch nach jedem Zeichen eine Variable i hochgezählt und das neue
Zeichen „eins weiter“ in test[i] abgelegt. Funktioniert und paßt auch.
Was allerdings nicht geht ist daß wenn ich jetzt ein kürzeres Wort
schicke, z.B. Maus, hat ja ein Zeichen weniger und es wird trotz
if-Anweisung (c == „\n“) {i=0; test[i] = „\0“;} das Füllen vom Array
nicht unterbrochen und der String zurückgeschickt. Es wartet immer auf
genau 5 Zeichen, wenn ich denn noch eins schick kommt der String wieder
zurückgeschickt ans Coolterm.
Wo ist mein Denkfehler, müßte es nicht nach dem Empfang von \n
abbrechen?
Code zeigen kann ich wenn gewünscht erst später bin am Handy...
Vielen Dank und schöne Ostern.
Hallo,
Westallgäuer E. schrieb:> Code zeigen kann ich wenn gewünscht erst später bin am Handy...
Das solltest du tun, vorher kann man nicht viel dazu sagen.
rhf
Westallgäuer E. schrieb:> Wo ist mein Denkfehler
Der ist zunächst mal da wo du denkst dass du uns in blumigen
Worten die Funktion deines Programmes ausführlich erklären
könntest.
SCNR
Westallgäuer E. schrieb:> Es wird auch nach jedem Zeichen eine Variable i hochgezählt und das neue> Zeichen „eins weiter“ in test[i] abgelegt. Funktioniert und paßt auch.
Nö.
In deinem Programm-Fragment ist nicht zu erkennen dass du das
Array <test> mit irgendetwas befüllst ausser am Ende mit der Null.
Zeige dein komplettes Programm, nicht irgendwelche Fragmente.
Die Fleury Lib brauchst nicht zeigen.
Kann es sein, das Coolterm ganz einfach kein "\n" sendet? Ich kenne das
Programm leider nicht, allerdings habe ich schon andere
Terminal-Anwendungen gesehen, bei denen das Enter-Zeichen einstellbar
war.
Jemand schrieb:> Kann es sein, das Coolterm ganz einfach kein "\n" sendet? Ich kenne das> Programm leider nicht, allerdings habe ich schon andere> Terminal-Anwendungen gesehen, bei denen das Enter-Zeichen einstellbar> war.
Gutes Argument, ich hab in den Optionen die Wahl zwischen CR, LF, und
CR+LF. Momentan stehts auf LF, wird automatisch angehängt.
Nein Projektarbeit ists keine, ist ne reine Freizeitnummer. Aber ich hab
mich hier im Forum am Programmcode bedient, hier:
Beitrag "Fleury's Uart, wie string empfangen?"
Vielleicht kommts deswegen so bekannt vor...
Gruß
> test[i] = c;> i++;
Hier hängst du das neue Zeichen an die Zeichenkette an. Bis dahin ist
sie aber noch nicht terminiert.
> uart_puts(test);
Hier gibst du die nicht terminierte Zeichenkette aus. Weis der Geier was
dann passiert, jedenfalls sicher nichts gutes.
> i = 0;> test[i] = '\0';
Hier setzt du den Index zurück und machst die Zeichenkette leer. Das
sieht soweit OK aus.
Vor dem Ausgeben mit uart_puts() musst du ein '\0' an die Zeichenkette
anhängen, damit uart_puts() erkennen kann, wo sie endet.
Westallgäuer E. schrieb:> Ich häng aber irgendwie beim Empfang von mehr als einem Zeichen.
Nein, du hängst noch viel früher. Was du brauchst, ist das Nachdenken
über eine Kommandozeile, deren Aufbau und deren Auswertung.
Also nicht so einen Kuddelmuddel wegen diverser Übertragungsfehler
machen, sondern etwa so vorgehen (ganz grob skizziert):
1. Habe eine Kommandozeile in Form eines Arrays, z.B. char Zeile[64];
und einen Index für diese Zeile, z.B. int idx;
2. entleere die Zeile, indem du in Zeile[0] eine 0 hineinschreibst und
auch idx = 0; setzt.
3. Erwarte Zeichen von der Seriellen und stopfe sie mittels idx in die
Kommandozeile, bis entweder CR auftaucht oder die Zeile voll ist. Hinter
jedes hineiengestopfte Zeichen kommt wieder als Abschluß eine Null. An
dieser stelle kannst du auch eine einfache Bearbeitung einbauen, wie
z.B. Zeichen bei BS löschen
4. Ist die Zeile voll oder CR aufgetaucht, dann kommt die Auswertung.
Setze dazu idx wieder auf 0 und inkrementiere ihn, bis du zum ersten
nichtweißen Zeichen kommst. Dann kannst du die nachfolgenden Zeichen
auswerten.
5. Hast du eine gültige Sequenz gefunden, dann führe die zugehörige
Aktion aus und gehe dann wieder zu Punkt 2.
W.S.
Grüßgott,
so, habs jetzt anders geschrieben, jetzt funktionierts, alles was ich
schicke kommt auch genau so zurück ans Terminal. Bis hierhin sag ich mal
vielen Dank für die Hilfe. Ausschauen tuts zur Zeit so, ist
wahrscheinlich noch nicht der Weisheit letzter Schluß, aber hey
wenigstens machts mal was ;-)
1
uint16_tincoming=0;
2
charinput[6];
3
charinput_str[6];
4
5
uint8_ti=0;
6
if(incoming!='\n'&&incoming!='\r')
7
{
8
9
input[i]=incoming;
10
i++;
11
input[i]='\0';//Nullbyte dazu
12
strcpy(input_str,input);// strcpy (Ziel, Quelle)
13
i=0;// zurücksetzen für nächsten String
14
input[i]='\0';// leerer String
15
16
}
Jetzt hab ich aber noch ne andere Frage...und zwar will ich jetzt ja mit
den empfangenen Daten was machen, also habe ich folgenden Code
geschrieben:
1
if(strcmp(input_str,"Test")==0)
2
{
3
PORTB&=~(1<<PB1);//Led geht an zum Test
4
5
// hier sollen denn noch andere Sachen passieren
6
}
Aus einem mir bisher unbekannten Grund wird der Code in den {} oben nie
ausgeführt.
Habe ich stattdessen statt input_str ein global deklariertes Chararray,
funktioniert es:
1
charstr[6]="Test";
2
3
if(strcmp(str,"Test")==0)
4
{
5
PORTB&=~(1<<PB1);//Led geht an zum Test
6
7
// hier sollen denn noch andere Sachen passieren
8
}
Wenn aber das Wort "Test" in input_str vom Uart her kommt, geht es
nicht. Vielleicht brauch ich auch mal ne Pause aber ich verstehs
momentan nicht warum es so reagiert bzw. nicht reagiert...
Interessanterweise funktioniert es aber wenn ich auf einzelne Chars
vergleiche z.B. ein kleines a:
1
if(strcmp(input_str,"Test")==0)
2
{
3
PORTB&=~(1<<PB1);//Led geht an zum Test
4
5
// hier sollen denn noch andere Sachen passieren
6
}
Hat da vielleicht jemand ne Idee oder sieht gleich was nicht stimmt,
warum es mit einzelnen Zeichen geht aber mit ganzen Wörtern nicht? Das
wär echt hilfreich ich weiß nämlich grad nicht mehr weiter :-)
Schöne Feiertage.
Hi
Mit C kann ich dir nicht helfen, aber meine Kommunikation läuft immer
über einen Ringpuffer. Dafür braucht es einen Schreib- und einen
Lesezeiger auf einen Speicherblock. In C vermutlich ein Array mit Bytes.
Die beiden Variablen werden beim Programmstart gleichgesetzt. Kommt ein
Zeichen per Interrupt an, wird dieses in der ISR in die über den
Schreibzeiger adressierte Speicherstelle geschrieben. Anschließend der
Schreibzeiger erhöht und bei Erreichen der Arraygrenze der Schreibzeiger
wieder auf 0 gesetzt. Mit ein paar Hilfsbits schreibe ich in der
Hauptschleife die im Ringpuffer befindlichen Daten über der Lesezeiger
in einen freigemeldeten Arbeitsspeicher. Ein Bit könnte signalisieren
"Empfang läuft". Freigemeldet durch ein Ctrl-Bit nach der Bearbeitung
eines vollständigen Telegramms. Natürlich wird der Lesezeiger dem
Schreibzeiger nachgeführt. Bei der Datenübertragung in den
Arbeitsspeicher wird ein Telegrammkopf, der zur Synchronisation dient,
herausgefiltert und das erste folgende Byte mit der Anzahl der
übertragenen Daten zur Prüfung des vollständigen Telegramme
herangezogen. Durch den Ringpuffer bist du mit deinem Programm völlig
unabhängig und du brauchst nicht irgendwo zu warten, bis Daten gelesen
sind. Und ein Telegramm kann wie folgt aufgebaut sein
Kopf1 - bel.Zeichen
Kopf2 - bel. Zeichen
Kopf3 - bel. Zeichen
Anzahl Bytes im Telegramm, ohne Kopf, aber mit Anzahl-Byte
n - Daten
So läßt sich ein Telegramm gut auswerten.
Im Datenblock kann z.B. Absender, Empfänger, Auftrag und natürlich auch
Werte stehen.
Sind alle Daten eingetroffen, setzt du dir ein Hit, Empfang vollständig.
Nach Bearbeitung werden die Bits gelõscht und der Arbeitsspeicher
freigegeben.
Vielleicht hilft es dir
Gruß oldmax
Dann steht da nicht „Test“ im Array sondern noch etwas anderes.
Funktioniert strncmp mit Länge 4?
Wenn du mal den ganzen Code zeigen würdest - auch den für die Behandlung
vom \n - könnte man dir helfen
Zeig nochmal den Vergleich für das a
Hallo,
danke oldmax für die Anleitung hilft mir gut weiter.
Dirk, mehr Code gibts nicht. In der letzten Sektion muß natürlich if
(strcmp (input_str, „a“) == 0)
Deinen Hinweis mit strncmp probier ich mal aus danke.
Hoi zämä,
hab jetzt noch mal zwei Varianten ausprobiert, gehen beide auch nicht:
1
int8_tcmp=0;
2
3
cmp=strncmp(input_str,"Test",4);
4
5
if(cmp==0)
6
{
7
//mach die Led an
8
}
1
if(strncmp(input_str,"Test",4)==0)
2
{
3
//mach die Led an
4
input_str[0]='\0';
5
}
Hab jetzt noch ein bißchen rumexperimentiert...es funktioniert wenn ich
sage wie unten, aber da wird ja nur das erste Zeichen geprüft, also
frage ich eigentlich ja nur a ab. Schreibe ich statt 1 ne 2 in die
Funktion und schicke ab rüber, gehts nicht mehr...
1
if(strncmp(input_str,"abc",1)==0)
2
{
3
//mach die Led an
4
input_str[0]='\0';
5
}
Da ist wohl tatsächlich was Anderes wie "Test" im Array...naja ich schau
mal morgen noch mal...danke für die Hilfe.
Guten Morgen,
@foobar:
Danke für den Hinweis, werde ich gleich mal machen.
Dirk B. schrieb:> Wird i denn jemals größer als 1?
Meinst Du den Index zum Hochzählen? Also ich schicke zur Zeit maximal 5
Zeichen..
> Sende mal bei dem Vergleich mit „a“ ein „ba“
Hm jetzt wirds lustig...ich vergleiche auf "a" und wenn ich "ba" schicke
reagierts gleich wie wenn ich "a" schicke. Im zweiten strcmp genauso, da
vergleiche ich auf "y" und wenn ich "xy" schicke reagierts auch beides
Mal gleich.
Es schaut grad so aus als sucht der Vergleich immer bloß das kleine a
bzw. das kleine y egal wo es ist...sobald ich aber auf mehr wie ein
Zeichen vergleiche z.B. "ba" und das schicke geht nix mehr...irgendwo
hab ich da einen Hund eingebaut...
Westallgäuer E. schrieb:> uint16_t incoming = 0;> char input[6];> char input_str[6];> uint8_t i = 0;> if (incoming != '\n' && incoming != '\r')> {> input[i] = incoming;> i++;> input[i] = '\0'; //Nullbyte dazu> strcpy (input_str, input); // strcpy (Ziel, Quelle)> i = 0; // zurücksetzen für nächsten String> input[i] = '\0'; // leerer String>> }>
Da du nicht den ganzen Code schickst, wie man dir jetzt schon oefters
gesagt hat, kann man nur raten. Aber, falls dein Code oben in einer
Funktion steckt, setzt du vor der if-Abfrage i jedesmal auf 0, das
heisst i wird nie hochgezaehlt und es steht immer nur ein Zeichen an der
ersten Stelle.
Wenn du keinen Debugger für den µC hast magst du die Auswertung der
Zeichenketten vielleicht vorher mit einem PC Programm üben. Dort
könntest du die serielle Eingabe durch die Tastatur ersetzen.
Hi
Ich hab mal in meinem Skizzenarchiv nachgesehen und eine Grafik zum
Ringpuffer gefunden. Sie verdeutlicht die Vorgehensweise.
Der Vorteil eines Ringpuffers, der ca. 3- 4fache Größe eines Telegramms
haben kann, du bist völlig unabhängig vom Empang der Daten.
Manchmal hat man Datenströme, die schnell hintereinander kommen, bevor
wieder eine Pause eintritt. Der Puffer sollte so groß sein, das er diese
Blöcke aufnehmen kann. Stellst du im Hauptprogramm fest, das Lesezeiger
und Schreibzeiger unterschiedlich sind, nimmst du das erste Zeichen und
vergleichst es mit dem 1. Zeichen deiner Telegrammkennung. Das geht
relativ einfach, wenn du dir einen kleinen Speicherblock anlegst, in dem
die Kennung hinterlegt ist. Dein Datenzähler adressiert nun die Kennung.
Stimmt der Vergleich, dann zählst du den Datenzähler hoch, sonst behälst
du den alten Wert. Hast du wie beim Beispiel bis 3 gezählt, dann stimmt
der Kopf und du setzt dir das Flag, "Kopf ok" und du beginnst mit dem
Datenzähler wieder bei 0. Diesen brauchst du nun, um die Anzahl der
Daten zu erfassen und gleichzeitig deinen Arbeitsspeicher zu
adressieren. Solange der Wert nun kleiner der Anzahl übertragener Bytes
ist, schreibst du Daten in deinen Puffer, hast du die Anzahl erreicht,
dann setzt du das Bit "Anzahl Daten erreicht". Damit sperrst du einen
weiteren Datenübertrag und gibst gleichzeitig den Inhalt zur Bearbeitung
frei. Nach Bearbeitung löscht du die Kontrollbits und gibst damit den
Arbeitspuffer für weitere Daten wieder frei. Bei dieser Vorgehensweise
ist eine unterschiedliche Datenmenge möglich. Wie bereits gesagt, kann
ich dir in C nicht helfen, da ich C nicht beherrsche. Routinen für
Assembler wären da kein Problem. Aber ich denke, mit der Skizze und den
Hinweisen sollte es dir möglich sein, diese Vorgehensweise auch in C
hinzubekommen.
Gruß oldmax
Die Ringpuffergeschichte ist ja ganz nett, aber der TO kämpft doch noch
mit viel grundlegenderen Problemen:
- erstmal muß eine komplette Zeichkette empfangen werden und
- diese muß sinnvoll/richtig ausgewertet werden
Der Ringpuffer ist doch dann das Sahnehäubchen. Und das wird auch nur
dann gebraucht, wenn der Controller nebenbei noch was anderes machen
soll, als auf Eingaben zu warten und diese auszuwerten.
Hi
Nun, ich hab meine Erfahrung und ein Ringpuffer ist ja nun wirklich nix
Erhabenes. Von mir aus kann er kämpfen bis zum Sanktnimmerleins Tag. Ich
wollte ihm nur helfen, zu verstehen.
Bernd schrieb:> Der Ringpuffer ist doch dann das Sahnehäubchen. Und das wird auch nur> dann gebraucht, wenn der Controller nebenbei noch was anderes machen> soll, als auf Eingaben zu warten und diese auszuwerten.
Tut er das nicht immer ?
Gruß oldmax
> Nun, ich hab meine Erfahrung und ein Ringpuffer ist ja nun wirklich nix> Erhabenes. Von mir aus kann er kämpfen bis zum Sanktnimmerleins Tag. Ich> wollte ihm nur helfen, zu verstehen.
Nur hilft ihm ein Ringpuffer überhaupt nicht. In Fleurys UART-Routinen
befinden sich bereits zwei - da sind sie angebracht. Aber nicht bei dem
Problem des TO.
Westallgäuer E. schrieb:> Dirk B. schrieb:>> Wird i denn jemals größer als 1?>> Meinst Du den Index zum Hochzählen? Also ich schicke zur Zeit maximal 5> Zeichen..>>> Sende mal bei dem Vergleich mit „a“ ein „ba“>> Hm jetzt wirds lustig...ich vergleiche auf "a" und wenn ich "ba" schicke> reagierts gleich wie wenn ich "a" schicke.
Das deutet darauf hin, dass die Eingabe immer nur beim Index [0]
gespeichert wird.
Entweder änderst du i nicht oder es wir immer wieder auf 0 gesetzt.
Könnte man sehr leicht beurteilen, wenn man den Code hat.
Westallgäuer E. schrieb:> Aus einem mir bisher unbekannten Grund wird der Code in den {} oben nie> ausgeführt.
Tja, dann denke mal drüber nach, wann genau die Bedingung wahr werden
kann.
Ich hänge dir mal was zum Lesen und Verstehen dran. Bedenke mal, daß es
imer besser ist, low-level Zeugs zu trennen von Algorithmen, also
high-level Zeugs. Strukturiere also deine Projekte, so daß du ein jedes
separat austesten kannst und dich dann drauf verlassen kannst.
W.S.
Martin V. schrieb:> Ich hab mal in meinem Skizzenarchiv nachgesehen und eine Grafik zum> Ringpuffer gefunden. Sie verdeutlicht die Vorgehensweise.
Ein Ringpuffer ist zum Zwischenspeichern innerhalb des Lowlevel-Treibers
geeignet, aber dort soll er gefälligst auch bleiben, ohne daß
übergeordnete Programmteile auf ihn einen Zugriff haben. Stattdessen
sollte es nur 2 Abfragefunktionen geben:
bool IsCharAvailable(void);
und
char GetChar(void);
Für das Handhaben von Kommandozeilen macht man das anders. Dort ist ein
Ringpuffer sinnlos, da man ja nach Abarbeiten des Kommandos ohne
jeglichen Aufwand die Kommandozeile löschen kann.
W.S.
W.S. schrieb:> Ein Ringpuffer ist zum Zwischenspeichern innerhalb des Lowlevel-Treibers> geeignet, aber dort soll er gefälligst auch bleiben, ohne daß> übergeordnete Programmteile auf ihn einen Zugriff haben.
Das ist doch Unsinn. Das zwingt de facto zu (völlig nutzlosem)
Umkopieren.
> Stattdessen> sollte es nur 2 Abfragefunktionen geben:> bool IsCharAvailable(void);> und> char GetChar(void);
Also ich habe da zwei andere Funktionen (in der Realität natürlich oft
in Assembler, aber ich schreibe es mal C-isch, damit du es verstehen
kannst):
uint8_t CharsInBuffer(void);
und
char GetChar(uint8_t Index);
Damit kann ich alles das machen, was du mit deinen zwei Funktionen auch
machen kannst, aber ich kann auch noch sehr viel mehr damit machen, ohne
die Notwendigkeit, den Mist in einen weiteren Buffer umkopieren zu
müssen. Die nützlichen Eigenschaften des Ringpuffers werden von diesen
erweiterten Möglichkeiten des Zugriffs von der Empfängerseite übrigens
in keinster Weise beeinträchtigt.
> Für das Handhaben von Kommandozeilen macht man das anders. Dort ist ein> Ringpuffer sinnlos, da man ja nach Abarbeiten des Kommandos ohne> jeglichen Aufwand die Kommandozeile löschen kann.
Harhar. Das kann nur jemand vertellen, der noch nie seinen Code gegen
einen automatisierten Peer getestet hat. Kleiner Hinweis: sowas kann
Kommandozeilen ggf. extrem schnell absondern und nicht immer ist im
Protokoll ein Feedback oder Prompt vorgesehen, was den Peer in seinem
Elan bremsen würde...
Zeno schrieb:> Jetzt bin ich auf die Antwort von W.S. gespannt.>> Der Thread hat jetzt durchaus das Potenzial interessant zu werden.
Naja, ich hoffe, es würde ihm auffallen, dass da natürlich noch eine
Funktion fehlt. Die liefere ich hier nach:
void AcceptChars(uint8_t count);
Hi
Manchmal verstehe ich euch nicht. Jeder, der programmieren kann, weiß
doch, was ein Ringpuffer ist und wie man mit ihm umgeht. Für einen
Anfänger aber ist oft allein das Wort ein Hexenwerk und damit dieser
Irrglaube ein wenig endet, habe ich versucht, dem TO mit einer Grafik
die Funktion zu erklären. Sein Problem ist scheinbar in der
Adressierung, denn so wie es aussieht, funktioniert Senden und
Empfangen. Lediglich die Inhalte sind nicht wie erwartet. Mein Beitrag
sollte ihm helfen, die Daten adressmäßig zuzuordnen. Und das es dazu
globale Adresszeiger braucht. Sicherlich ist dieser auch in einer
Hochsprache, sofern man C dazu zählen kann, auch in einer Funktion zu
übergeben, aber er muß im Prinzip schon irgendwo global verfügbar und
gültig sein.
Wenn er einen Adresszeiger in einer Funktion aufruft, ist dieser, wenn
er lokal vereinbart ist, halt immer 0. Ob das der Grund für das
Fehlverhalten ist, können wir aufgrund fehlender Information aber nicht
wissen und darum hab ich die Skizze ins Forum gestellt. Nicht für euch
Experten. Das maß ich mir nicht an, euch zu belehren. Aber ein Anfänger
sollte mit dieser Hilfe seinen Fehler finden oder vielleicht die gesamte
vorherige Vorgehensweise neu aufsetzen können.
Also, diskutiert nicht darüber, was und wozu irgendwelche Puffer sind.
Das in der Skizze der Vorschlag enthalten ist, Daten aus dem Ringpuffer
in einen Arbeitspuffer zu kopieren, ist der besseren Übersicht
geschuldet. Natürlich kann man den sparen und direkt die Daten im
Ringpuffer auswerten, machts aber nicht leichter.
Ein schönes Osterfest wünsch ich euch.
Gruß oldmax
Hallo zusammen,
ich werd da der Sache mal nachgehen und schauen ob ich mit Euren Tipps
und Hinweisen da was hinkrieg.
Ich melde mich.
Gruß und schöne Woche.
Servus mitanand,
also ich wollt bloß kurz Bescheid sagen jetzt funktionierts...danke für
Eure Hilfe. Jetzt muß ich bloß noch gucken wie ich meinen String mit
strtok auftrennen kann und denn die nach dem : empfangenen Werte auf
zwei verschiedene Variablen verteilen kann...und mal gucken ob es nicht
irgendwo sich selbere blockiert...aber wird schon schiefgehen ;-)
Vielen Dank nochmal und schönes Wochenende
strtok verändert den String (indem es die Delimiter mit '\0'
überschreibt)
sscanf kann da viel besser funktionieren
oder strchr und strtol (oder ähnliche Funktion)
Dirk B. schrieb:> strtok verändert den String...
Die ganze Herangehensweise ist mMn ausgesprochen ungünstig, man könnte
dazu auch falsch sagen. Ich würde das Ganze in 3 Ebenen aufteilen:
1.Ebene: (=low level) Behandlung des Zeichenempfanges als solchen.
2.Ebene: Auflaufen einer Kommandozeile in einen Kommandostring (ASCIIZ)
3.Ebene: Auswertung der Kommandozeile ohne sowas wie strtok usw.
Dabei ist das Erkennen eines Kommandos eigentlich recht einfach:
1
charmatch(char*item,char**Zptr)
2
{char*P;
3
IgnoreSpace(Zptr);
4
P=*Zptr;
5
if(UpCase(*P)!=*item)return0;
6
while(*item){if(UpCase(*P++)!=(*item++))return0;}
7
*Zptr=P;
8
IgnoreSpace(Zptr);
9
return1;
10
}
Und wie man ein IgnoreSpace oder ein UpCase schreibt, sollte bekannt
sein.
W.S.
W.S. schrieb:> Und wie man ein IgnoreSpace oder ein UpCase schreibt, sollte bekannt> sein.
Die spannende Frage ist, was macht IgnoreSpace()? Doch nicht etwas den
Eingabestring verändern?
Stefan ⛄ F. schrieb:> Die spannende Frage ist...
Nö, es gibt hier gar keine spannenden Fragen. Zum Auswerten wird einfach
ein Zeiger auf den Zeilenanfang gesetzt und zum Übergehen von white
space inkrementiert bis er auf ein nicht-white-space Zeichen oder die
abschließende 0 kommt. Match funktioniert ähnlich: es setzt den Zeiger
hinter den erkannten Token und läßt ihn bei unerkanntem Token dort
stehen, wo er ist.
W.S.
Nachtrag:
Weil einem sowas immer wieder vorkommt, hatte ich das Ganze hier schon
mal gepostet, also das komplette Kommandoprogramm incl. einer simplen
Korrektur für die Eingabe (BKSP löscht das zuletzt eingegebene Zeichen).
Das reicht für die allermeisten Fälle aus.
W.S.
sscanf zerlegt die Zeile in 2 Strings und einen Wert.
Dann wird der erste String mit der Kommandoliste verglichen und bei
Match der Funktionspointer in der Liste ausgeführt.
Die Liste endet mit einem leeren String (""). Damit kann man beliebig
Einträge hinzufügen.
CMD_FMT wird so definiert, daß die Stringpuffer nicht überlaufen können,
z.B.
1
#define CMD_FMT "%16s" // for array size 17
Soll die Schreibweise egal sein, nimmt man statt strcmp das strcasecmp.