Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: ichmagbohnen am 28. March 2009, 20:02
-
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:
-
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.
-
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.
-
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-)
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?!
-
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;
}
-
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....
-
Die korrekte Möglichkeit, irgendeine Speicherstelle im RAM zu benutzen, sind globale Variablen. ;)
-
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.
-
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.
-
Aaaah wunderbar :-) :-)
Jetzt funktionierts, vielen Dank euch allen!