Autor Thema: Wie getc()/scanf() basteln? "Generelle" Tastatureingabe funktioniert bereits  (Gelesen 3576 mal)

ichmagbohnen

  • Beiträge: 7
    • Profil anzeigen
Gespeichert
Vorneweg, ich bin kein Code-Schnorrer, ich möchte nur wissen, wie ich das am geschicktesten machen kann  :-D

Meine Tastatur funktioniert soweit, bei jedem Tastendruck wird meine Interrupt Service Routine aufgerufen. Nun stehe ich vor der Frage, wie ich das am besten mache, ein getc() und später dann scanf() zu basteln. Das scanf wird kaum noch ein Problem sein, wenn ich schonmal die einzelnen Tasten bekomme.
Ich möchte eine getc-Funktion, die solange wartet bis ein neues Zeichen anliegt und das dann zurückgibt. Ausserdem noch eine, die nicht wartet und wenn ein neues Zeichen anliegt, das zurückgibt, ansonsten 0 oder einen negativen Wert oder oder oder (was genau, ist im Moment ja noch egal).
Doch ich kann ja weder von der ISR aus sagen dass er dann und dann was bereitstellen soll, da ja niemand weiss, wann getippt wird, noch kann ich genau in dem Moment tippen, wie mein getc() was holen will.

Gibt es denn ein Registerbit/Register in dem steht ob nun ein neues Zeichen im Puffer liegt oder ob es noch das alte ist (vergleichen von alt und neu bringt ja nichts, wenn ein Zeichen zwei oder mehrmals nacheinander kommt). Wenn nein, kann ich ja in der ISR einen Pointer auf eine bestimmte RAM-Adresse setzen und dort so ein Bit einrichten. So mache ich es mit meinem X/Y Koordinaten und der Textfarbe.
Ist das sinnvoll so? Wohl eher nicht....

Erzählt mir mal bitte, wie ihr das macht damit ich auch ein wenig abgucken kann ;) :evil:
go on home british soldiers, go on home. have you got no fucking homes of your own?!
for eight hundred years, we fought you without fear, and we will fight you for eight hundred more!

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
Ich mach das so, dass die ISR die gedrückte Taste feststellt, und das Zeichen in einer Variable speichert. Den Tastaturpuffer leere ich also direkt durch das auslesen.

Die getc() Methode überprüft dann in einer Schleife, ob in der Variable ein gültiges Zeichen gespeichert ist. Sobald eins drin ist, wird die Variable ausgelesen, und mit einem ungültigen Wert überschrieben. Der ausgelesene Wert wird dann zurückgegeben.

Die andere Methode (key_hit() oder wie man sie nennen will), ist genauso wie die getc() Methode, nur mit einer if-Abfrage, statt einer Schleife. Wenn kein Zeichen drin ist, dann kehr die Methode also einfach zurück und wartet nicht.

Du solltest für die drei Methoden jeweils einen kritischen Abschnitt betreten, damit du nicht bei unerwarteten Interrupts Probleme bekommst. Wenn du ein Multitasking-System hast, musst du dir außerdem was besseres als eine Warteschleife einfallen lassen.
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
Nabend,

du könntest es folgendermaßen machen:
Du hast deinen Keyboard-Treiber, dieser hält eine Liste, die angibt, welche Taks Interesse an einen Tastenanschlag hat.
Sobald eine Taste gedrückt wurde, gibt dein Treiber ein Signal an alle interessierten Tasks, damit diese wissen, dass eine Taste gedrückt wurde.
Das könntest du über die IPC deines Kernels machen.

Die Tasks, die dann auf einen Anschlag warten, kannst du auch blocken, wodurch du die Arbeit des Schedulers vermindern kannst.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

ichmagbohnen

  • Beiträge: 7
    • Profil anzeigen
Gespeichert
Also von Multitasking bin ich noch weit entfernt :D
Ich wäre schon froh, wenn ich endlich mal Programme zum laufen bekommen würde, die nicht direkt in der einen Kernel Binary eingebaut sind :D Aber bis dahin braucht es auch noch ein weilchen. Im Moment versuch ich mich einnigermassen durchzuschlagen um eine Shell hinzubekommen.
Aber nur so lernt man  8-)

Zitat
Ich mach das so, dass die ISR die gedrückte Taste feststellt, und das Zeichen in einer Variable speichert. Den Tastaturpuffer leere ich also direkt durch das auslesen.
Umpf schon wieder was, was ich nicht richtig verstanden hatte :D
Ich dachte, dass wenn ich in meiner getc() (die kommende ;)) ein Zeichen aus dem Tastaturpuffer lese und nicht überprüfe, ob das Zeichen neu ist, dass dann immer das gleiche kommt....

Also würde das ungefähr so funktionieren, oder?
void isr() {
    ......
    unsigned char zeichen = scancode_zu_ascii_schon_umgesetzt;
}
....
unsigned char getc() {
    hole_die_variable_aus_der_anderen_funktion;
}
Doch wie mache ich das? Das geht doch so gar nicht? Mit Pointern? Doch woher weiss ich in der getc() dann wohin der Pointer zeigen muss? Da hat er doch die ganzen anderen variablen aus den anderen Funktionen nicht?!


go on home british soldiers, go on home. have you got no fucking homes of your own?!
for eight hundred years, we fought you without fear, and we will fight you for eight hundred more!

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
Dafür brauchst du eine globale Variable.

unsigned char zeichen = 0; // (Der ASCII Code) 0 soll jetzt mal ein ungültiges Zeichen sein.

void isr() {
     ...
     zeichen = scancode_zu_ascii_schon_umgesetzt;
}


unsigned char getc() {
    unsigned char temp;

    // warten bis ein Zeichen verfügbar ist
    while (zeichen == 0)
    {
        // nichts tun
    }

    // das Zeichen auslesen
    temp = zeichen;

    // signalisieren, dass wir das zeichen gelesen haben
    zeichen = 0;

    return temp;
}
Dieser Text wird unter jedem Beitrag angezeigt.

ichmagbohnen

  • Beiträge: 7
    • Profil anzeigen
Gespeichert
Ist das auch ohne globale Variablen möglich? Ich finde die nicht schön und die verleiten mich immer wieder dazu Murks zu programmieren... Als ich mit C angefangen habe und noch keine Ahnung von Pointern hatte bzw diese nie richtig übergeben konnte, waren da immer zig Globale im Code.... und daher wollte ich eigentlich ganz drauf verzichten.
Die einzige Möglichkeit, die ich im Moment sehe, um das ohne globale Variablen zu machen ist eine Speicherstelle im RAM zu missbrauchen, aber das ist doch sicher auch nicht Sinn der Sache....
« Letzte Änderung: 28. March 2009, 21:40 von ichmagbohnen »
go on home british soldiers, go on home. have you got no fucking homes of your own?!
for eight hundred years, we fought you without fear, and we will fight you for eight hundred more!

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
Die korrekte Möglichkeit, irgendeine Speicherstelle im RAM zu benutzen, sind globale Variablen. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

ichmagbohnen

  • Beiträge: 7
    • Profil anzeigen
Gespeichert
Naja, aber das klärt ja der Compiler im Moment für mich :D Ich dachte da eher an eine fixe Stelle, aber seis drum, global ist im Grund gar nicht mal so schlecht bei näherer Betrachtung.

Nun klemme ich hier dran:
Ich habe eine globals.h gemacht, in der steht:
#ifndef EXTERN
#define EXTERN extern
#endif

EXTERN int keybuf;
Nun binde ich die einmal in die keyboard.c ein und einmal in meine getc.c und zwar so:
#define EXTERN
#include <globals.h>

unsigned char getc() {
unsigned char temp;
while (keybuf == 0);
temp = keybuf;
keybuf = 0;
return temp;
}
Auf 0 gesetzt zu Anfangs in meiner init_keyboard() (die wird vor dem ersten getc() aufgerufen und soll später die LEDs nochmal nett beim booten blinken lassen.).
In meiner keyboard.c sieht der Spass so aus:
#include <globals.h>

isr ..... {
unsigned char keycode = inb(0x60);
if (keycode & 0x80) { // this checks for bit 7 to be 1
                // if it's the user has released a key
} else {
keybuf = keyboard_layout[keycode];
}
}
Nun rufe ich in einer dritten Datei mein getc auf, nur leider tut sich da nichts...
unsigned char input;
for(;;) {
input = getc();
printf("%c", input);
}

hmm, was mach ich daran falsch?

//edit: Nach ein paar debug-printf()s sehe ich, dass er an der while(....); in der getc() klemmt.
« Letzte Änderung: 28. March 2009, 22:26 von ichmagbohnen »
go on home british soldiers, go on home. have you got no fucking homes of your own?!
for eight hundred years, we fought you without fear, and we will fight you for eight hundred more!

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
Definier dein keybuf mal als volatile. Normalerweise rechnet der Compiler nicht damit, daß ihm außerhalb vom normalen Programmablauf ein Interrupthandler unterwegs die Variablen manipuliert, deswegen kann er das ganze zu einer Endlosschleife "optimieren". Mit volatile sagst du, daß sich diese Variable jederzeit "von selber" ändern kann.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

ichmagbohnen

  • Beiträge: 7
    • Profil anzeigen
Gespeichert
Aaaah wunderbar  :-) :-)

Jetzt funktionierts, vielen Dank euch allen!
go on home british soldiers, go on home. have you got no fucking homes of your own?!
for eight hundred years, we fought you without fear, and we will fight you for eight hundred more!

 

Einloggen