Ich bastel gerade an einem Gerät, das mehrere Tasten einlesen (34), 22 Leuchtdioden ansteuern und nebenbei noch Daten über RS232 versenden bzw .empfangen soll. Bis auf das Empfangen funktionieren auch alle Funktionen für sich gesehen schon ganz ordentlich.
Jetzt würde ich aber gerne verschiedene Zeitebenen einführen und habe das leider noch nie gemacht. Vielleicht kann mir ja jemand ein paar Tipps geben…
Mir gehts dabei mehr um das prinzipielle Vorgehen.
Ich bastel gerade an einem Gerät, das mehrere Tasten einlesen
(34), 22 Leuchtdioden ansteuern und nebenbei noch Daten über
RS232 versenden bzw .empfangen soll. Bis auf das Empfangen
funktionieren auch alle Funktionen für sich gesehen schon ganz
ordentlich.
Au welcher Basis ??
Transitoren
Gatter
mikrocontroller
SPS
PC
Jetzt würde ich aber gerne verschiedene Zeitebenen einführen
und habe das leider noch nie gemacht. Vielleicht kann mir ja
jemand ein paar Tipps geben…
Mir gehts dabei mehr um das prinzipielle Vorgehen.
Was sind Zeitebenen ??
Meinst du Zeigeber (Timer) ??
Sorry, hab mal wieder vorausgesetzt, dass jeder weiss was ich meine…
Es handelt sich hier um einen µC (ATmega128). Programiert in C.
Die Tasten sind genau wie die LEDs in einer Matrix verschaltet, werden also im Multiplexverfahren eingelesen bzw. angesteuert.
Zeitebenen dienen dazu, ein simples Multitasking zu ermöglichen. In der Regel wird dazu ein Timerinterrupt benötigt.
Die Tasks in der kleinsten Zeitebene haben die höchste Prio.
Ich benötige diese Zeitebenen um echtzeit zu gewährleisten, sprich garantierte Reaktionszeiten vorhersagen zu können. Die LEDs sollen natürlich auch während einer Übertragung nicht flackern…
Momentan läuft alles in der IDLE - Task, was ja aber spätestens beim Empfangen von Daten nichtmehr für echtzeit geeignet ist.
Mir geht es jetzt um die Realisierung. Wie kann ich solche Zeitebenen mit nur einem Timer implementieren? - Oder werden dazu mehrere verwendet?
Wie kann ich solche
Zeitebenen mit nur einem Timer implementieren? - Oder werden
dazu mehrere verwendet?
Ein Timer reicht im allgemeinen. Du machst ganz einfach an den Start der Timer-Interrrupt-Routine einen Zähler. Je nach Zählerstand verzweigst Du dann in die einzelnen Teile der Routine.
Beispielsweise wird der Timer-IRQ jede Millisekunde ausgelöst. Wichtige Routinen finden bei jedem ungraden Zählerstand statt (alle 2ms). LED-ansteuerung nur bei Zählerstand 2 und 12 (also alle 10ms), Tastaturabfrage nur bei Zählerstand 18 (alle 20ms, ggf. alle 5ms eine Spalte, dann mit 4 Zählerständen), Echtzeituhr bei Zählerstand 20 (auch alle 20ms), wobei dann der Zähler auch auf 0 zurückgesetzt wird.
Natürlich können parallel dazu weitere Interrupts bedient werden, z.B. RS232-Empfang oder -Sendung etc. und auch weitere Aufgaben in die Aufgabenliste eingebaut werden (A/D-Wandler etc.).
Wie sieht es denn dabei mit gemeinsam genutzen Ports aus? (Tastaur und LED Matrix nutzen gemeinsam Spaltensignale).
Für denn Fall, dass die Netto LZ einer Task länger dauert, als die Interrupt Zeit, müsste ich ja evtl. den Int sperren…oder??
Denkbar bei UART Empfang/Senden.
Wie sieht es denn dabei mit gemeinsam genutzen Ports aus?
(Tastaur und LED Matrix nutzen gemeinsam Spaltensignale).
Wenn gemeinsame Leitungen verwendet werden, muß selbstverständlich der Zugriff ‚in einem Rutsch‘ stattfinden. Der aktuelle Spaltenzustand muß dann also dann zunächst für die Abfrage verwendet werden und sofort danach (noch während des selben IRQ-Durchgangs) für die Ansteuerung der LED. Beim nächsten IRQ dann die nächste Spalte.
Bei der Umschaltung und Abfrage ein evt. Einschwingen beachten, falls z.B. Kondensatoren an den Tasten sitzen, die sich vor einer Abfrage erst aufladen müssen.
Für denn Fall, dass die Netto LZ einer Task länger dauert, als
die Interrupt Zeit, müsste ich ja evtl. den Int
sperren…oder??
Nein. Du musst entweder die Routine entsprechend kurz machen oder die Zeit zwischen den Interrupts entsprechend länger wählen. 1ms ist ja nur ein Beispiel.
Eine andere Möglichkeit ist, eine IRQ-Routine zu ‚splitten‘, also in zwei Teilen abarbeiten zu lassen. Beim ersten Aufruf die Daten reinholen und puffern, dazu ein Flag setzen, daß welche da sind. Und dann beim nächsten IRQ die Daten verarbeiten und das Flag resetten.
Denkbar bei UART Empfang/Senden.
Da reicht es doch, den Hardwarepuffer auszulesen und in einen Softwarepuffer zu schreiben bzw. umgekehrt. Das ganze mit Zeigern und Flags zwischen IRQ-Routine und Hauptprogramm als Handshake koppeln.
Wichtig ist immer, daß die Irq-Routinen immer so kurz wie nur irgend möglich sind, da sie richtig was von der Prozessorzeit wegnehmen. Die Hauptarbeit kann dann das Hautprogramm ‚in Ruhe‘ erledigen.
Ach ja: Vorsicht bei Verwendung einiger C-Funktionen. Manche darf man nicht in einem Interrupt verwenden, da sonst lokale Variablen überschriebne würden. Geht aus der Compilerdokumentation hervor, was man machen darf.
Ach ja: Vorsicht bei Verwendung einiger C-Funktionen. Manche
darf man nicht in einem Interrupt verwenden, da sonst lokale
Variablen überschriebne würden. Geht aus der
Compilerdokumentation hervor, was man machen darf.
Du spielst damit sicher auf die re - entrant - Fähigkeit von Unterprogrammen an. Das stellt hier kein Problem dar. Hab ich schon drauf geachtet.
Meine gedankliche Hürde hatte sich eher auf die Netto LZ bezogen, die evtl. Länger ist als die Zeit zw. zwei Interrups.