Hallo! Ich habe mir ein Programm geschrieben für eine PS2 Tastatur. Dieses Funktioniert für meine Zwecke auch ganz gut. Jetzt habe ich eine Funktion int keyb_get(void) die Zyklisch aufgerufen wird und mir den char zurückgibt wenn einer vorhanden ist, sonst -1. Diese Funktion habe ich mit fdevopen verknüpft. FILE* kb_init() { ... return fdevopen(NULL, keyb_get); } In der Main rufe ich die kb_init Funktion einmal auf und speichere den Rückgabewert in stdin. In meiner Main-Endlosschleife rufe ich gets(myString) auf. Eigentlich sollte ja myString erst beschrieben werden wenn ich Enter drücke, jedoch wird myString immer beschrieben und immer nur an der Position 0. Aja myString wird in der main angelegt: char myString[100] = { 0 }; Wie mache ich es richtig damit myString erst beim drücken von Enter beschrieben wird? Den Rückgabewert von gets bzw fgets habe ich auch nicht so richtig verstanden. Ist das ein Pointer? wohin? Vielen Dank für eure Hilfe! LG, Godi
Gottfried S. schrieb: > Den Rückgabewert von gets bzw fgets habe ich auch nicht so richtig > verstanden. Ist das ein Pointer? wohin? Im Internet findet sich dazu (gets in google und 1. Treffer): "char * gets ( char * str ); Return Value On success, the function returns the same str parameter. If the End-of-File is encountered and no characters have been read, the contents of str remain unchanged and a null pointer is returned. If an error occurs, a null pointer is returned. Use either ferror or feof to check whether an error happened or the End-of-File was reached." Du musst also ein ausreichend großes Character Array anlegen und den Pointer dazu der Funktion übergeben. Der Rückgabewert wird nur benötigt um den Fehlerfall zu überprüfen. Der String ist nach dem Aufruf in dem character Array. Gottfried S. schrieb: > return fdevopen(NULL, keyb_get); Damit legt das Betriebssystem ein Filehandle an. benutzt du auch brav fclose() um das Handle wieder zu schließen wenn du es nicht mehr brauchst? Du brauchst ein C Buch!
Udo Schmitt schrieb: > > Du musst also ein ausreichend großes Character Array anlegen und den > Pointer dazu der Funktion übergeben. Der Rückgabewert wird nur benötigt > um den Fehlerfall zu überprüfen. Der String ist nach dem Aufruf in dem > character Array. > > benutzt du auch brav fclose() um das Handle wieder zu schließen wenn du > es nicht mehr brauchst? > > Du brauchst ein C Buch! Hallo! Ja C Buch würde ich mal brauchen. ;) fdevopen findet sich aber auch nicht in "c von a bis z"... Danke für den Hinweis auf fclose(), benütze ich aber nicht weil zur Laufzeit des Programmes das File immer offen sein soll. Ich habe ein ausreichend großes character Array angelegt. char myString[100] = { 0 }; Vielleicht habe ich einfach ein Verständnissproblem von fgets bzw gets. Diese Funktionen sollten ja in den Buffer so lange die Zeichen nacheinander schreiben bis ein new Line kommt und dann wieder von vorne beginnen. Also in meinem Fall wird fgets zyklisch (Main - Endlosschleife) aufgerufen und fragt bei der Funktion keyb_get nach ob ein neues Zeichen vorhanden ist. Wenn ja dann gibt keyb_get das zeichen zurück sonst -1. fgets speichert das Zeichen in den Buffer. Wenn ein neues Zeichen kommt dann sollte fgets dieses an die nächste Position im Puffer schreiben. Bei mir wird aber immer nur an die erste Stelle im Buffer geschrieben (myString[0]). Irgendwie bin ich ratlos... godi
Gottfried S. schrieb: > Vielleicht habe ich einfach ein Verständnissproblem von fgets bzw gets. > Diese Funktionen sollten ja in den Buffer so lange die Zeichen > nacheinander schreiben bis ein new Line kommt und dann wieder von vorne > beginnen. Das ist so schon alles richtig. > Also in meinem Fall wird fgets zyklisch (Main - Endlosschleife) > aufgerufen und fragt bei der Funktion keyb_get nach ob ein neues Zeichen > vorhanden ist. Wenn ja dann gibt keyb_get das zeichen zurück sonst -1. > fgets speichert das Zeichen in den Buffer. Wenn ein neues Zeichen kommt > dann sollte fgets dieses an die nächste Position im Puffer schreiben. Was aber fgets nicht macht: Du kannst nicht fgets mehrmals aufrufen und hoffen, dass dir das fgets magisch die Zeichen an den bereits vorhandenen Buffer dranhängt. fgets weiß nicht wo es zuletzt aufgehört hat zu schreiben. > Bei mir wird aber immer nur an die erste Stelle im Buffer geschrieben > (myString[0]). Zeig mal deinen Code. Ich denke du verwendest fgets falsch bzw. frage ich mich gerade, ob nicht fgets für das was du vorhast überhaupt das falsche Werkzeug ist und du dir durch das Beharren auf fgets mehr Arbeit aufzwirbelst als eigentlich notwendig. Hinweis: die Standard-IO Funktionen kann man auf einem µC, bei dem die Ein/Ausgaben sowieso speziell sind, meist nicht sinnvoll benutzen. Man zeiht da nur einen Rattenschwanz an Code ins System ohne dafür etwas großartig nützliches zu bekommen.
Danke für deine ausführliche Antwort. Auf fgets beharre ich deshalb weil es leider so gefordert wird. Habe aber schon gelesen, dass es die Performance eher beeinträchtigt als es an Komfort bringt. Hier mal die wichtigsten Codestellen:
1 | FILE *lcdout, *kbin; |
2 | |
3 | /************************************************************************/
|
4 | /* this function return a character for the standard I/O
|
5 | /************************************************************************/
|
6 | int keyb_get(void) { |
7 | int16_t read = readElement(); |
8 | |
9 | //without ECHO
|
10 | if(kb_echo == OFF) { |
11 | return read; |
12 | }
|
13 | else { |
14 | //with ECHO
|
15 | if (read >= 0) { |
16 | char c = read; |
17 | lcd_put(c); |
18 | }
|
19 | return read; |
20 | }
|
21 | }
|
22 | |
23 | /************************************************************************/
|
24 | /* This function initialize the keyboard
|
25 | /************************************************************************/
|
26 | FILE* kb_init() { |
27 | receiveKb_init(); |
28 | kb_LED.set = FALSE; |
29 | kb_reset(); |
30 | return fdevopen(NULL, keyb_get); |
31 | }
|
32 | |
33 | /************************************************************************/
|
34 | /* main program
|
35 | /************************************************************************/
|
36 | int main(void) { |
37 | char myString[100] = { 0 }; |
38 | |
39 | //initial receive data from keyboard
|
40 | kbin = kb_init(); |
41 | |
42 | keyb_set_echo(ON); |
43 | |
44 | //initial the LCD
|
45 | lcdout = lcd_init(); |
46 | |
47 | //Set the LCD Contrast
|
48 | lcd_set_contrast(0x00); |
49 | //set the cursor to the home position
|
50 | lcd_home(); |
51 | |
52 | // main program
|
53 | while(1) |
54 | {
|
55 | fgets(myString, 100, kbin); |
56 | // Hier sollte dann mit myString weitergearbeitet werden wenn fgets fertig ist.
|
57 | |
58 | }
|
59 | }
|
>Du kannst nicht fgets mehrmals aufrufen und hoffen, dass dir das fgets >magisch die Zeichen an den bereits vorhandenen Buffer dranhängt. fgets >weiß nicht wo es zuletzt aufgehört hat zu schreiben. Daran wird es scheitern... godi
Gottfried S. schrieb: > int keyb_get(void) { > int16_t read = readElement(); aus dem Rest deiner Beschreibung entnehme ich: readElement wartet nicht auf einen Tastendruck > while(1) > { > fgets(myString, 100, kbin); > // Hier sollte dann mit myString weitergearbeitet werden wenn fgets > fertig ist. Tja. Damit erklärt sich das dann hier. Für fgets bedeutet 'fertig' auch der Umstand, dass keine Taste gedrückt wurde. Deine keyb_get meldet im Grunde EOF an fgets zurück, woraufhin fgets aufhört keyb_get zu rufen und sich Zeichen zu holen. >>Du kannst nicht fgets mehrmals aufrufen und hoffen, dass dir das fgets >>magisch die Zeichen an den bereits vorhandenen Buffer dranhängt. fgets >>weiß nicht wo es zuletzt aufgehört hat zu schreiben. > > Daran wird es scheitern... ganz genau. Du müsstest diesen fgets wiederrum in eine while Schleife stecken, die solange läuft, solange nicht das letzte empfangene Zeichen ein \n war. ABER: Wozu das ganze: fgets ist nicht dafür eingerichtet, dass es von sich aus unterbrechbar ist. D.h. 1 Call von fgets liefert eine Eingabezeile oder aber alles aus dem Eingabestrom bis zum 'End Of File' (janachdem was vorher angetroffen wird). Du hast für dich definiert, das die End Of File Bedingung dadurch erfüllt ist, dass keine Taste gedrückt wurde. Und genau so verhält sich dann auch fgets. Dein konkretes Problem liegt also darin, dass du für keyb_get eine Definition getroffen hast, die dir das ganze fgets ad Absurdum führt. Das C-Stream Konzept passt nun mal nicht wirklich zu interaktiven Tastendrücken. Das ist leider ein Problem, für das dir Standard-C keine richtige Lösung anbieten kann. Das C-Konzept sieht vor, dass solange gewartet wird, bis dein Benutzer eine Taste drückt oder aber ein tatsächliches EOF daherkommt. Nichts tun, im Sinne von "Wenn eine Eingabe da ist, hol sie dir und ansonsten steig gleich aus der Funktion aus" ist nicht voegesehen. Wenn du es dir leisten kann, dass fgets Däumchen dreht und auf Tastendrücke wartet, kannst du das natürlich immer noch erreichen, indem deine keyb_get dieses Däumchen drehen realisiert und solange wartet, bis ein Tastendruck daherkommt.
1 | int keyb_get(void) |
2 | {
|
3 | int16_t read; |
4 | |
5 | // warte auf einen Tastendruck
|
6 | while( ( read = readElement() ) < 0 ) |
7 | ;
|
8 | |
9 | if( read == 4 ) // Strg-D ist EOF |
10 | return EOF; |
11 | |
12 | if(kb_echo) |
13 | lcd_putc((char)read); |
14 | |
15 | return read; |
16 | }
|
nur ist das natürlich eine Lösung, wie man sie genau auf einem µC eigentlich nicht haben will. ZUmindest solange nicht, solange der µC während des Wartens auf einen Tastendruck auch noch andere Dinge erledigen können soll.
gets() lässt sich übrigens prinzipbedingt gar nicht "richtig aufrufen". Das liegt daran, dass es keine Möglichkeit hat zu wissen, wie groß der übergebene Puffer denn ist, den der Nutzer bereitgestellt hat. Damit besteht prinzipiell das Risiko, dass der Puffer zu klein ist und über dessen Grenzen geschrieben wird. Daher sollte man gets() niemals benutzen.
Vielen Dank für eure ausführlichen Antworten! Hat mir endlich weitergeholfen. Ok jetzt werde ich mir selbst eine Funktion schreiben die mir die Zeichen zu einen String bis zur new Line zusammenfügt.
Gottfried S. schrieb: > Vielen Dank für eure ausführlichen Antworten! > Hat mir endlich weitergeholfen. > > Ok jetzt werde ich mir selbst eine Funktion schreiben die mir die > Zeichen zu einen String bis zur new Line zusammenfügt. Ist sowieso die vernünftigste Variante. Denn ich gehe jede Wette ein, dass dein Eingabezeilen-Leser auch über ein paar Line-Editing-Möglichkeiten verfügen soll. So Dinge wie: Backspace auswerten und das letzte eingebebene Zeichen wieder löschen, eventuell mit dem Cursor in der Zeile links/rechts rumfahren, unterschiedliches Verhalten ja nachdem ob Einfüge- oder Überschreibmodus, Kommando zum Löschen der Eingabezeile ab Cursorposition etc. All das sind Dinge die du klarerweise von fgets nicht bekommst.
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.