3 Pseudo-Scheduling Funktion zur Ausgabesteuerung

Eine hohe Anforderung an ein User-Interface ist jene, dass eine möglichst regelmäßige Aktualisierung der Anzeigen stattfinden soll. In vielen Situation ändern sich quasi zugleich 2 Zeilen der LCD-Anzeige ständig, was nach einer hohen ,,Refresh-Rate'' verlangt.

Ein zu häufiges Ansteuern der Anzeige, die sehr oft mit Display- und Businitialisierungen verbunden ist, kann allerdings dazu führen, dass auf Grund der ,,Trägheit'' des LCD-Displays die Anzeige noch nicht fertig aufgebaut ist, wenn der neue, eventuell geänderte Wert bereits wieder ausgegeben wird. Dies führt zu einem ,,Verblassen'' der LCD-Anzeige bzw. zu einem unruhigen ,,Flackern'' das die Lesbarkeit deutlich vermindert.

Um dies zu verhindern, wurde eine einfache Zeitsteuerung über den 8-Bit Timer/Counter0 realisiert (Scheduling [7] S. 188). Dieser niedrigst-priorisierte Timer-Interrupt wird dazu folgendermassen ,,programmiert'':

	; ... from inc/constants.inc
	; 4000000/256=15625 ~ 16kHz/TCNT0
	.equ Timer0Div        = 0b00000100 ; cpuClk/256
	.equ Timer0Val        = -128       ; 15625/128~120Hz
	; ...
	; level0_value = 4000000/256/128 ~ 8.2msec
	; -----------------------------
	 .equ schedLevel1Val  = 0x10  ;  16*level0_value ~ 7.5Hz
	 .equ schedLevel2Val  = 0x80  ; 128*level0_value ~ 0.9Hz
	; ... from lib/systimer.lib
	; Timer0 clock(io)/64
	  OUTB  TCCR0, Timer0Div       ; prescaler value
	; Timer0 oreset value (-128)
	  OUTB  TCNT0, Timer0Val       ; set new init value 
Der daraus resultierende Grundtakt (z. Zt. ca. 120 Hz) wird nun in drei Schedulerringen mit unterschiedlichen Teilern verwendet, damit ist es möglich, drei unabhängige Zeit-Zyklen (Ringe) zu verwalten.

Figure 7.13: Scheduler und ,,scheduled Service'' Beispiel
\includegraphics[%
width=14cm]{graphics/Scheduler.eps}

Die konkrete Implementierung verwendet dazu die Timer/Counter0 Overflow Interrupt Service Routine, die drei Schalter (Flags) verwendet, die im jeweiligen Ring nach Erreichen eines vordefinierten Timerwertes auf ,,aktiv'' gesetzt werden.

Jede Service-Routine, die einen dieser Ringe verwendet, muss das Flag auswerten und die Abarbeitung abbrechen wenn der Wert ,,inaktiv'' ist. Falls das Flag aber ,,aktiv'' ist, wird diese Serviceroutine ausgeführt und am Ende der Routine wird das Flag von der Service-Routine wieder auf ,,inaktiv'' gesetzt, danach beginnt der Zyklus wieder von vorne.

Anmerkung:
Im Gegensatz zum herkömmlichen Scheduling Begriff, der den einzelnen Services eine garantierte Ausführungszeit zusichern soll, zielt diese Methode darauf ab, für ein Service eine kürzestmögliche Wiederholzeit festzulegen, unabhängig davon, wie oft der Programmteil aufgerufen wird.
Abb. 7.13 zeigt ein konkretes Beispiel, das die Steuerung der Anzeigenhäufigkeit (auto_update_display) im automatischen Positioniermodus (siehe 7.8.1) kontrolliert. Dieses Service wird mit mittlerer Priorität ausgeführt.

	; ---------------------------------
	; scheduler controlled display update (can be called always)
	; ---------------------------------
	auto_update_display:                ; 3 rcall overhead
	  lds   sched_temp, level1_waiting  ; 2 memory access
	  tst   sched_temp                  ; 1 test function
	  brne  auto_update                 ; 1 (2 if true) branch
	  ret                               ; 4 - sum=11 (2.75 usecs)
	; ...
	; do display update ...
	auto_update:
	  PUSHW REG_Z
	  push  ltmp2
	  push  temp1
	  rcall powr_funcmode_1 ; update power value display
	  rcall angl_funcmode_2 ; update angle value display
	  pop   temp1
	  pop   ltmp2
	  POPW  REG_Z
	; ---------------------------------
	; reset scheduler values for a new timer cycle
	  clr   sched_temp
	  sts   level1_waiting, sched_temp ; reset scheduler flag
	  ret 
In diesem Projekt wird Ring 1 zur Steuerung der Anzeigenhäufigkeit im automatischen Positioniermodus (siehe 7.8.1) und Ring 2 zur Aktualisierung der Temperaturanzeige im ,,Idle'' Modus (in der Datei lib/mainmenu.lib) verwendet, Ring 0 wird in der aktuellen Implementierung nicht benutzt.

Alle Timer-Initialiserungen und Timer-Services sind in lib/systimer.lib definiert.

gerhard.reithofer@tech-edv.co.at