Tips für PICs 11: Multitasking
        
      
    
      
	Ein PIC ist zwar ein leistungsfähiger Microcontroller, aber seinen Aktivitäten sind doch arge Grenzen 
	gesetzt. So fehlt ihm ein Betriebssystem (beim PC könnte dieses 'Windows' oder 'Linux' heißen), das 
	verschiedene anfallende Arbeiten koordiniert.
	Eine solche Koordination muß der PIC-Programmierer selber vornehmen. Der PIC besitzt eine Hardware, die eine 
	Unterbrechung des laufenden Programms ('Interrupt') bewirkt. Hiermit kann der Programmierer Programmteile 
	schreiben, die eine solche geforderte Koordinierung ermöglichen.
	
	Wir sind dabei, für das Faller-Car-System eine Infrarot-Fernsteuerung zu bauen. Die Autos sollen dabei durch 
	einen PIC an Bord gesteuert werden, der von außen Befehle über Infrarot-Licht erhält.
	Die Aufgabenstellung für diesen PIC lautet:
	- empfange Datentelegramme,
	- erzeuge Datentelegramme,
	- erzeuge eine PWM (pulsweitenmodulierte Spannung) für den Motorantrieb,
	- erzeuge eine schnelle Pulsfolge für einen Spannungsvervielfacher,
	- erzeuge eine langsame Pulsfolge für einen Blinker.
	Diese Aufgaben hat er praktisch gleichzeitig zu bewältigen.
	Das Erzeugen der Telegramme und Impulsfolgen geschieht aktiv vom PIC aus (der sich somit die Zeit hierfür in 
	engen Grenzen selber einteilen kann), wobei jedoch das Empfangen eines Telegramms eine sofortige Reaktion verlangt, 
	da ansonsten wichtige Informationen verloren gehen. Das bedeutet aber, daß, egal was gerade an Arbeiten 
	anliegt, der PIC diese sofort unterbrechen muß, um das Empfangen vorzunehmen. Jedoch dürfen 
	hierdurch die anderen Arbeiten keinesfalls in Mitleidenschaft gezogen werden. Im Klartext heißt dies, 
	daß z.B. die Ansteuerung des Motors sich nicht ändern darf, nur weil gerade ein Telegramm empfangen 
	wird.
	
	So etwas wird als 'Multitasking' bezeichnet, also mehrere Dinge quasi-gleichzeitig zu machen, ohne daß diese 
	sich auch nur im Geringsten gegenseitig behindern. Hierfür benötigt ein wie auch immer gearteter 
	Rechner eine Interrupt-Verarbeitung. ('Interrupt' könnte man mit 'Unterbrechungs-Anforderung' übersetzen.) 
	Dies bedeutet, daß der PIC, wenn er einen solchen Interrupt erkennt, sofort jede softwaremäßige 
	Arbeit unterbrechen muß und in einem 'Interrupt-Bearbeitungs-Programm' (IR-Routine) diesen Interrupt 
	bearbeiten muß, und das mit höchster Priorität. Bei kleinen PICs (wie wir sie verwenden) ist der 
	Einbau einer IR-Routine von der Hardware her ermöglicht. Diese Routine selber ist nicht noch einmal durch 
	weitere Interrupts unterbrechbar und muß daher ihre Arbeiten in kürzestmöglicher Zeit 
	abschließen. Evtl. währenddessen auftretende weitere Interrupts gehen nicht verloren. Sie müssen aber 
	warten, bis sie an die Reihe kommen. Es ist natürlich klar, daß für solche Arbeiten Rechenzeit 
	'abgezwackt' wird, die anderen Aktivitäten nun nicht zur Verfügung steht.
	
      	
      
	Lösung
      	
      
	Ein Multitasking kann nur funktionieren, wenn:
	a) der Rechner relativ viel 'Freizeit' hat und
	b) der Programmierer das Programm richtig schreibt.
	zu a:
	Die Zeit, in der der Rechner Aufgaben bearbeitet, darf nur etwa 1 bis allerhöchstens 10 % der Gesamtzeit 
	sein.
	zu b:
	
	Schlechte Programmierung kann für das Multitasking tödlich sein. Alle Takte, alle Zeitverzögerungen 
	dürfen niemals über NOP-Schleifen (das sind Programmstellen, in denen der Rechner 
	"no-operation"-Befehle bearbeitet, also durch Nichts-Tun Zeit schindet) bewerkstelligt werden. Vielmehr 
	muß das Hauptprogramm in einer einzigen unbehinderten Schleife laufen können und nur 'gelegentlich' in 
	eine Aufgabe verzweigen. Es darf nur an einer einzigen Stelle eine Warteposition (d.h. eine Warteschleife) haben, in 
	der es, nach getaner Arbeit, auf einen Takt von einem Zeitgeber (der, wenn er abgelaufen ist, einen Interrupt 
	erzeugt) wartet. Alle anderen Zeiten müssen von diesem Takt abgeleitet werden. Jede Art von 
	Rückwärtsschleifen ist verboten. Sprünge sind daher nur vorwärts erlaubt. Die IR-Routine darf 
	nur die wirklich allernötigsten Befehle enthalten, damit nicht zu viel Zeit bei der Abarbeitung verloren 
	geht.
	Am sichersten und sinnvollsten ist es, überhaupt keine Wartestellen zu programmieren, sondern, wie im 
	nebenstehenden Bild gezeigt, die Hauptprogrammschleife selber als Warteschleife zu verwenden.
	So eine Programmstruktur ermöglicht es, daß der Rechner alle Arbeiten erledigt hat, wenn er auf die 
	Warteschleife stößt. Im Bild, das dieses Prinzip darstellen soll, ist diese Warteschleife in Rot 
	gekennzeichnet. Der PIC rast also in Höchstgeschwindigkeit durch die rote Schleife und fragt nur ab, ob etwas 
	getan werden muß. In der Interrupt-Routine haben sich u.a. irgendwelche Timer gemeldet, da ihre vorgegebene 
	Zeit abgelaufen ist. Dort werden wenige zeitkritische Vorgänge wie das Ende eines auszugebenden Impulses 
	bearbeitet. Meist genügt aber das Setzen einer Kennung, daß diese Zeit abgelaufen ist. Dies ist im Bild 
	oben dargestellt.
	Die beiden gezeichneten Programmteile kommunizieren also nur durch Setzen von Kennungen, sind aber ansonsten 
	voneinander unabhängig.
	
      	
      
	Starker Tobak!
      	
      
	Deshalb wollen wir die vorgeschlagene Vorgehensweise an Beispielen aus unserer Auto-Steuerung 
	verdeutlichen:
	Der schnellste benötigte Takt ist der für die Ausgabe eines Telegramms. Alle anderen Takte sind von 
	diesem Takt abgeleitet; man kann auch sagen, sie sind Vielfache dieses Taktes.
	Dieser Takt wird von einem Timer (einer Hardware-Uhr im PIC) erzeugt, der die hilfreiche Eigenschaft besitzt, 
	völlig unabhängig von den Software-Aktivitäten zu laufen und daher nicht von ihnen gestört 
	wird; und umgekehrt! Er beträgt in unserem Beispiel 200 µs. Weil wir es gleich noch mit anderen Timern zu 
	tun bekommen werden, wollen wir diesen Vorgang als 'Muttertakt' bezeichnen. Dieser wird (über den Timer) 
	hergeleitet aus dem Takt des Oszillators, der den gesamten PIC in Gang hält.
	
      	
      
	Ein kleines Detail hierzu:
      	
      
	Wenn ich einen Impuls für ein Telegramm oder die Motorsteuerung ausgeben will, dann schalte ich den 
	entsprechenden Ausgang am PIC ein; darf jetzt aber auf keinen Fall warten, bis der Impuls zuende sein soll; sondern 
	ich muß einen weiteren Timer (wir nennen ihn hier 'Impuls-Timer') mit der geplanten Impulsdauer starten und 
	dann sofort andere Aufgaben erledigen. Erst wenn alles abgearbeitet ist, darf ich an der zentralen Wartestelle 
	'Däumchen drehen' und auf den Muttertakt (oder andere Ereignisse) warten.
	Irgendwann wird der 'Impuls-Timer' abgelaufen sein und sich per Interrupt melden. Hier muß die IR-Routine  
	nichts weiter tun als nur den Impuls-Ausgang wieder abschalten; eine Arbeit, die in wenigen µs erledigt ist. 
	Tricky dicky: in einem solch einfachen Fall lohnt es sich nicht, daß die IR-Routine eine Kennung setzt, 
	damit dann das Hauptprogramm den Impuls abschaltet! Es ist wirklich nur ein einziger Befehl dazu vonnöten; 
	das Setzen einer Kennung dauert länger ...
	Ähnliches geschieht auch beim Empfangen eines Telegramms: Die ansteigende Flanke eines Impulses erzeugt einen 
	Interrupt. In der IR-Routine wird wieder ein Timer ('Telegramm-Timer') mit einer Rückmelde-Zeit von genau 100 
	µs gestartet, mehr muß nicht getan werden. Meldet sich der Telegramm-Timer, wieder per Interrupt, so 
	wird der Telegramm-Eingang abgefragt, ob der Impuls immer noch ansteht. Wenn ja, ist es ein '1'-Impuls; wenn nein, 
	ist eine '0' empfangen worden. Dieser Wert wird vermerkt. Und wieder ist mit sehr wenig Rechenzeit ein Ereignis 
	abgearbeitet worden.
	
	(Zum Verständnis: Unsere Norm für die Übertragung der Infrarot-Befehle besagt, daß die Impulse 
	einen Takt von 200 µs haben. Eine '0' hat eine Impulsdauer von 67 µs, eine '1' eine von 133 µs. 
	Wenn ich den Telegramm-Eingang genau 100 µs nach Impuls-Beginn abfrage, ist ein '0'-Impuls schon lange zuende, 
	aber ein '1'-Impuls dauert noch lange an.)
	
	Das Warten auf den 'Muttertakt' geschieht einfach, indem ich einen Merker auf '1' setze und dann warte, bis die 
	IR-Routine diesen wieder auf '0' gesetzt hat. So startet der 'Rundlauf' des Hauptprogramms immer im selben Takt, 
	egal, was und wieviel zwischendurch erledigt werden mußte.
	Mit einer solchen Strategie lassen sich tatsächlich mehrere zeitkritische Vorgänge bearbeiten.
	In der nebenstehenden Zeichnung sehen Sie die Aufgaben, die ein PIC in einem unserer Faller-Car-Fahrzeuge erledigen 
	soll. Das meiste funktioniert bereits. Das Prinzip ist richtig.
	
      
      
	Für weitere Fragen stehen gern zur Verfügung:
	- der MEC; Besichtigung und Fachsimpelei z.B. an unseren "Club-Abenden"
	- der Autor: Hans Peter Kastner
	
      
    
      
	erstellt am: 01.01.2015
	
	Copyright © 2015 by Modelleisenbahnclub Castrop-Rauxel 1987 e.V.