Elektronik-Projekt: Elektronischer Adventkalender


zurück zu Elektronik, Homepage

Adventkalender im Betrieb

3. Softwarebeschreibung

Die Aufgabe der Software für den PIC-Mikrocontroller besteht beim elektronischen Adventkalender hauptsächlich in der Erzeugung sehr vieler Flackerlichter (40 mal für jede Leuchtdiode, die den Baum bilden, 12 mal für jede Leuchtdiode, die den Stern symbolisieren und 24 für die Flammen der Kerzen. Diese Kerzen sind der eigentliche Adventkalender, da mit jedem Tag eine Kerze mehr leuchtet. Macht in Summe 76 Flackerlichter. Anmerkung: Die roten Leuchtdioden, die das Wachs der Kerze symbolisieren flackern natürlich nicht. Diese leuchten dauerhaft, wenn diese Kerze aktiv ist.). Diese 76 Flackerlichter und die 24 Leuchtdioden für das Wachs jeder Kerze sind in den Variablen (Register) Flackerlichter0 bis Flackerlichter12 abgelegt (Abbildung 3.1).

Variablen Flackerlichter0 bis Flackerlichter12

Die zweite wichtige Aufgabe der Software ist die Ausgabe der Variablen Flackerlichter0 bis Flackerlichter12 durch die Schieberegister IC2 bis IC14 (vgl. Abschnitt Abschnitt 2 (Schaltungsbeschreibung) .

Wichtig:
Die Zuordnung der Bits in den Variablen Flackerlichter0 bis Flackerlichter12 für die Leuchtdioden muss der Beschaltung der Schieberegister gemäß der Schaltung in Abbildung 2.2 entsprechen. Daher ist in Abbildung 3.1 zu jeder Variablen auch das zugehörige Schieberegister angegeben, und zur besseren Übersicht sind die Bits, die den Leuchtdioden entsprechen in deren Farben dargestellt (gelb: Flamme bzw. Stern, rot: Wachs und grün: Baum).

Die dritte wichtige Aufgabe der Software ist das Erkennen ob die Taste (S1) gedrückt wurde. Diese Aufgabe muss regelmäßig durchgeführt werden und erfolgt mit dem Unterprogramm TastenRoutine (siehe Abschnitt 3.4.2. Unterprogramm zur Tastenabfrage). Zur Erinnerung: Der Taster S1 aktiviert den Adventkalender, in dem die erste Kerze aktiviert wird. Zusätzlich flackern auch die grünen Leuchtdioden, die den Baum symbolisieren. Mit jedem weiteren Tastendruck leuchtet zusätzlich eine weitere Kerze. Siehe Abschnitt 2 (Schaltungsbeschreibung).

Manche Unterprogramme müssen zyklisch (also regelmäßig) aufgerufen werden. Dazu sind mehrere Zeitbasen notwendig. Diese werden mit Hilfe des Timer-Interrupts erzeugt. Siehe Abschnitt 3.2. Hauptprogramm und Abschnitt 3.3. Interrupt-Service-Routine (ISR, Timer 0).

Die in der Schaltung vorgesehenen Jumper (JP1 bis JP3) sind für zukünftige Optionen und Erweiterungen vorgesehen. In dieser Version werden diese nicht benötigt.

Zur besseren Übersicht ist der Quellcode in mehrere Dateien aufgeteilt:

Als Programmiersprache wurde hier C, und als Compiler die freie Demoversion des CC5X-Compilers von B. Knudsen DatamikroC von [B Knudsen Data 2007] verwendet.

Achtung:
Bei diesem Projekt wurde die freie (kostenlose) Demoversion des CC5X-Kompilers verwendet, da dieser einen sehr kompakten Assemblercode erzeugt. Der größte Nachteil an dieser Demoversion ist aber, dass der Compiler nur 1k große Programme kompilieren kann. Wenn man den gesamten Quellcode allerdings in mehrere C-Dateien aufteilt, kann man diese Einschränkung umgehen. Abschnitt 6 (Umgehen der 1k-Grenze des CC5X-Compilers) zeigt wie man dabei vorgeht.
Ein weiterer Nachteil an der Demoversion ist die Anzahl der Übergabeparameter an ein Unterprogramm. Aus diesem Grund sind bei diesem Projekt sehr viele externe Variablen notwendig.

Meine Erkenntnisse zur freien Demoversion des CC5X-Compiler habe ich auf einer anderen Seite auf meiner Webseite [Buchgeher 2006] zusammengefasst.
nach oben

3.1. Externe und globale Register, Portdefinitionen und Konstanten

Externe Register:
Die Variablen Flackerlichter0 bis Flackerlichter12 (Zeilen 26 bis 38) müssen als externe Register deklariert werden.
Weiters ein Register Namens TagesZaehler (Zeile 40). Dieses Register beinhaltet den aktuellen Tag.

Externe Register

Der Grund warum diese Variablen als externe Register deklariert werden müssen ist, weil diese Register von mehreren C-Dateien verwendet werden. Hier auch von den Dateien FLACKERLICHT_BAUM.C, FLACKERLICHT_KERZEN.C und FLACKERLICHT_STERN.C.

Wichtig:
Diese externen Variablen müssen in der Datei PROJEKT.H mit dem Schlüsselwort extern deklariert werden.

Globale Register:
Für die Erzeugung der Zeitbasen (hier für 409.6µs, 10ms und 1 Tag) sind die folgenden globalen Register notwendig:

Für die Tastenabfrage und für das automatische Weiterzählen sind die folgenden globalen Register notwendig:

Globale Register (Teil 1)
Globale Register (Teil 2)

Weitere globale Register werden auch für die Erzeugung der Flackerlichter benötigt (siehe 3.4.4. Konstanten, globale Variablen, Tabellen und Unterprogramme zur Erzeugung der Flackerlichter).

Portdefinitionen:
Im Allgemeinen werden bei jeder Anwendung die Ein- und Ausgangspins der diversen Hardwarekomponenten (hier Jumper, Taster und die Schieberegister) an einem anderen Portpin verwendet. Damit dies in der Software nur an einer Stelle berücksichtigt werden muss, befindet sich in der Software eine Portdefinition.

Portdefinition für die Schieberegister:
Für die Kommunikation mit den Schieberegistern sind drei Portleitungen des Mikrocontrollers notwendig. Diese müssen gemäß der Schaltung nach Abbildung 2.1 definiert werden (Zeilen 291 bis 293 in der Datei PROJEKT.H).

Portdefinition für die Jumper:
Die Jumper (JP1 bis JP3) werden zwar hier noch nicht verwendet, eine Portdefinition ist aber schon in der Datei PROJEKT.H vorgesehen (Zeilen 296 bis 298).

Portdefinition für den Taster:
Für den Taster ist keine Portdefinitionen notwendig, siehe Unterprogramm TastenRoutine (Abeschnitt 3.4.2.)

Portdefinitionen

Konstanten:
Beim elektronischen Adventkalender werden einige Konstanten zur Erzeugung der Zeitbasen und zur Erzeugung der Flackerlichter benötigt.

Konstanten für die Zeitbasen:
Für die Kommunikation mit den Schieberegistern sind drei Portleitungen des Mikrocontrollers notwendig. Diese müssen gemäß der Schaltung nach Abbildung 2.1 definiert werden (Zeilen 291 bis 293 in der Datei PROJEKT.H).


Die Konstante KONSTZEITBASIS10MS gibt die Anzahl der notwendigen Interrupt-Aufrufe für die 10-ms-Zeitbasis an. Hier, beim elektronischen Adventkalender, wird die Interrupt-Service-Routine (ISR) alle 409.6$\mu$s aufgerufen, daher ergibt sich für die Konstante der Wert 24 (24 x 409.6µs = 9.83ms = ca. 10ms).

Die Konstante KONSTZEITBASIS1SEK beinhaltet den Wert 102, da die 1-Sekunden-Zeitbasis mit Hilfe der 10-ms-Zeitbasis (genauer: 9.83 ms) erzeugt wird. Analoges gilt für die Konstanten KONSTZEITBASIS1MIN, KONSTZEITBASIS1STD und KONSTZEITBASIS1TAG: Die Zeitbasis für eine Minute wird mit Hilfe der 1-Sekunden-Zeitbasis erzeugt, daher beinhaltet die Konstante KONSTZEITBASIS1MIN den Wert 60. Die Zeitbasis für eine Stunde wird mit Hilfe der 1-Minuten-Zeitbasis erzeugt, daher beinhaltet die Konstante KONSTZEITBASIS1STD den Wert 60, und die Zeitbasis für einen Tag wird mit Hilfe der 1-Stunden-Zeitbasis erzeugt, daher beinhaltet die Konstante KONSTZEITBASIS1TAG den Wert 24. Siehe auch Abschnitt 3.3. (Interrupt-Service-Routine, ISR, Timer 0)

Konstanten zur Erzeugung der Zeitbasen

Konstanten für die Flackerlichter:
Die Konstanten, die für die Erzeugung der Flackerlichter benötigt werden, werden im Abschnitt 3.4.4. (Konstanten, globale Variablen, Tabellen und Unterprogramme zur Erzeugung der Flackerlichter) behandelt.

nach oben

3.2. Hauptprogramm

Zuerst müssen der Mikrocontroller und die (globalen) Register für die Erzeugung der Flackerlichter initialisiert werden. Diese Aufgaben werden von den Unterprogrammen Init (Zeile 576), Init_Flackerlicht_Baum (Flackerlichter für den Baum, Zeile 577), Init_Flackerlicht_Kerzen (Flackerlichter für die Kerzen, Zeile 578) ausgeführt. Die Flackerlichter für den Stern werden mit dem Unterprogramm Init_Flackerlicht_Stern (Zeile 579) initialisiert.

Nun befindet sich das Hauptprogramm in einer Endlosschleife. Diese Schleife besitzt die Aufgabe ständig die so genannten Botschaftsflags abzufragen. Ist eines dieser Botschaftsflags gesetzt, so muss vom Hauptprogramm eine bestimmte Aufgabe ausgeführt werden. Diese Aufgaben sind in Form von Unterprogrammen vorhanden.

Hier die Tätigkeiten in der Endlosschleife, welche durch die Botschaftsflags ausgelöst werden:

Achtung:
Die Botschaftsflags müssen nach der Ausführung der Aufgaben wieder gelöscht werden, da diese Aufgaben sonst ununterbrochen wiederholt werden!

Listing 3.5 zeigt das Hauptprogramm (Auszug aus Adventkalender.c).

Hauptprogramm
nach oben

3.3. Interrupt-Service-Routine (ISR, Timer 0)

Eine Interrupt-Service-Routine (kurz: ISR) ist im Prinzip ein Unterprogramm, welches aber im Gegensatz zu normalen Unterprogrammen "unvorhergesehen" aufgerufen wird. Hier, beim Timer-0-Interrupt jedes Mal wenn der Timer 0 überläuft, also von 255 auf 0 wechselt. Würde zum Beispiel ein RB-Interrupt verwendet werden, so würde bei jeder Pegeländerung von RB4 bis RB7 ein Interrupt auftreten und die entsprechende ISR wird ausgeführt. Eine ISR sollte so kurz wie möglich sein.

Ein wichtiger Punkt bei einer ISR ist, dass das w-Register (Working- oder Arbeitsregister) und das STATUS-Register in andere Register zwischengespeichert werden müssen, falls diese Register in der ISR ihre Registerinhalte verändern. Der Grund dafür ist, dass eine ISR eben unvorhergesehen aufgerufen wird, und die angesprochenen Register unter Umständen zu diesen Zeitpunkten gerade benötigte Werte enthalten. Nach Ausführung der ISR springt diese zwar wieder genau an die Stelle zurück, wo sie war, bevor der Interrupt auftauchte, aber mit einem möglicherweise falschen Wert im w-Register (bzw. STATUS-Register). Das Zwischenspeichern des w-Register bzw. des STATUS-Registers wird häufig auch als PUSH bezeichnet. Das Wiederherstellen von w-Register und STATUS-Register nennt man POP.
Beim CC5X-Compiler erfolgt das Zwischenspeichern der genannten Register mit der Anweisung int_save_registers (Zeile 159) und das zurückschreiben mit der Anweisung int_restore_registers (Zeile 199).

Woher weiß das Programm, dass ein Interrupt aufgerufen werden muss? Dazu gibt es für jede Interruptquelle ein Kontroll-Flag. Dies wird vom Controller gesetzt wenn dieser Interrupt auftritt. (Vorausgesetzt, dass diese Interruptquelle freigegeben wurde). Damit aber die ISR nicht ständig aufgerufen wird, muss dieses Bit in der ISR wieder gelöscht werden.

Ein wichtiger Punkt beim CC5X-Compiler ist, dass dem Compiler mitgeteilt werden muss, dass die Interrupt-Routine im Arbeitsspeicher des Mikrocontrollers ab Adresse 0004h beginnen muss. Dies erfolgt mit einer so genannten pragma-Anweisung (Zeile 155).

Nun aber zur projektspezifischen Timer 0-ISR. Diese hat lediglich die Aufgabe eine Zeitbasis für 409.6µs und eine zweite für ca. 10ms zu erzeugen. Damit eine Zeit von 10ms entsteht muss die ISR 24-mal aufgerufen werden (24 x 409.6µs = 9.83ms). Bei jedem ISR-Aufruf muss daher ein Zählregister (hier: ZaehlerZeitbasis10ms) um 1 vermindert werden. Besitzt es danach den Wert 0, so ist eine Zeit von ca. 10ms vergangen. Nun wird das Botschaftsflag FlagZeitbasis10ms im Register FlagISRHP gesetzt, und das Zählregister muss mit dem Wert 24 neu geladen werden. Der Wert 24 wird hier durch die Konstante KONSTZEITBASIS10MS ersetzt. Das selbe Prinzip wird auch für die Erzeugung der 24-Stunden-Zeitbasis verwendet, wobei mit Zwischenschritten auch Zeitbasen für eine Sekunde, eine Minute und eine Stunde erzeugt werden, die aber bei diesem Projekt nicht benötigt werden.

Anmerkung:
Die 409.6µs-Zeitbasis wird für die Erzeugung der Flackerlichter benötigt, die 10-ms-Zeitbasis für das regelmäßige Abfragen des Tasters und die 1-Tages-Zeitbasis für das automatische Weiterzählen der Tage.

Die Zeit von 409.6µs ergibt sich, weil als Taktquelle ein 20-MHz-Quarz (X1) verwendet wird, und weil der Vorteiler (VT) mit dem Wert 1:8 (TMR0 Rate, Zeile 231 im Unterprogramm Init) geladen wird. Für diese Zeit gilt:

Formel ISR

Listing 3.6 zeigt die kurze Interrupt-Service-Routine (Auszug aus Adventkalender.c).

Interrupt-Service-Routine
nach oben

3.4. Unterprogramme

Die insgesamt 11 Unterprogramme lassen sich wie folgt einteilen:

nach oben

3.4.1. Unterprogramm zur Initialisierung des PIC (Init)

Das Unterprogramm Init dient zur Initialisierung des Mikrocontroller und muss daher am Beginn des Hauptprogramms aufgerufen werden.

Da die Interrupt-Service-Routine (ISR) zyklisch (alle 409.6µs) aufgerufen wird, ist eine entsprechende Zeitbasis notwendig. Diese wird mit Hilfe eines Timer-Interrupts erzeugt. Für die Definition der Zeitbasis ist hier das mikrocontrollerinterne Funktions-Register OPTION zuständig. Damit bei einer PIC-Taktfrequenz von 20MHz eine Zeitbasis von 409.6µs erzeugt wird, muss das Register OPTION mit dem binären Wert bxxxx0010 geladen werden (Zeile 231). Das Zählregister für diese Zeitbasis (Funktions-Register TMR0) muss gelöscht werden (Zeile 229).

Die beiden Ports (beim PIC16F87 die Ports A und B) müssen gemäß der Beschaltung nach Abbildung 2.1 entweder als Eingang oder als Ausgang definiert werden (Zeilen 260 und 271).

Achtung:
Der PIC16F87 verfügt über analoge Komparatoren. Diese werden bei diesem Projekt nicht verwendet und müssen daher deaktiviert werden (Zeilen 283 und 284).

Alle Leuchtdioden deaktivieren. Daher die externen Register zur Erzeugung der Flackerlichter löschen, und mit dem Unterprogramm SR_74xx595_SendData ausgeben (Zeilen 288 bis 301).

Die globalen Zählregister für die Zeitbasen müssen initialisiert werden (Zeilen 305 bis 313).

Zum Schluss werden der Timer0-Interrupt und der globale Interrupt freigegeben (Zeile 231) [1]. Für das Freigeben der Interrupts ist hier das Register INTCON zuständig. Je nach benötigten Interrupts müssen die Freigabebits (im Englischen: Enable) gesetzt werden. (Hier das Freigabebit T0IE (Bit 5) für den Timer 0.) Zusätzlich muss auch die globale Interruptfreigabe GIE (General Interrupt Enable, Bit 7) gesetzt werden. Er ist sozusagen der Hauptschalter, der Interrupts ermöglicht. Der Timer-0-Interrupt ist nun eingeschaltet und sorgt hier für eine 409.6-µs-Zeitbasis.

Listing 3.7 zeigt das Unterprogramm zur Initialisierung des PIC16F87 (Auszug aus der Datei Adventkalender.c).

Init (Teil 1)
Init (Teil 2)
Init (Teil 3)
nach oben

3.4.2. Unterprogramm zur Tastenabfrage (TastenRoutine)

Das Unterprogramm TastenRoutine hat die Aufgabe regelmäßig zu prüfen, ob die Taste S1 gedrückt wurde (Zeilen 403 bis 407). Wurde die Taste gedrückt (Zeile 409) das Zählregister TagesZaehler erhöhen (Zeile 411) und die Zählregister für die Erzeugung der 1-Stunden-Zeitbasen neu initialisieren (Zeilen 417 bis 422). Weiters die automatische Tageszählung freigeben (TagesZaehlerEnable, Zeile 424). Dieses Unterprogramm wird daher zyklisch (ca. alle 10ms) vom Hauptprogramm aufgerufen.

Vorgehensweise:

  1. Port B einlesen und im Register temp1 sichern
  2. Dieses Register invertieren und in temp2 sichern (temp1 wird später noch einmal benötigt und darf daher nicht überschrieben werden!)
  3. Das Register TastenAlt gibt beim Aufruf (dieses Unterprogramms) den Zustand der Tasten an, der beim vorhergehenden Aufruf dieses Unterprogramms am Port B herrschte. Also den Zustand am Port B vor ca. 10 ms.
  4. Mit Hilfe der beiden Register temp2 und TastenAlt lässt sich somit ermitteln, ob eine bestimmte Taste zwischen dem vorhergehenden Aufruf dieses Unterprogramms und den gerade bearbeitenden Aufruf gedrückt wurde. Dies erfolgt mit einer bitweisen logischen-UND-Verknüpfung. Das Ergebnis dieser UND-Verknüpfung im Register TastenStatus sichern. Mit diesem Verfahren wird auch gleichzeitig das so genannte Tastenprellen überbrückt, da dieses Tastenprellen in der Regel weit weniger als 10ms dauert.
  5. Je nachdem ob die Taste gedrückt wurde, das Zählregister für die Tageszählung erhöhen, die Zählregister für die Zeitbasis neu initialisieren und die automatische Tageszählung freigeben.
  6. Register TastenAlt mit dem Inhalt von temp1 für den nächsten Unterprogrammaufruf laden.

Anmerkungen:

Listing 3.8 zeigt das Unterprogramm zur Tastenabfrage (Auszug aus Adventalender.c).

Tastenroutine
nach oben

3.4.3. Unterprogramm zur Tageszählung (Nächster_Tag)

Das Unterprogramm Naechster_Tag hat die Aufgabe die automatische Tageszählung zu erhöhen, falls das Register TagesZaehlerEnable gesetzt ist, und der Tageszähler noch kleiner als 24 ist. Dieses Unterprogramm wird zyklisch (ca. alle 24 Stunden) vom Hauptprogramm aufgerufen.

Anmerkungen:
Besitzt das Zählregister TagesZaehler den Wert 24, so wird dieser Zähler nicht mehr erhöht. D.h. Der Baum, alle Kerzen und der Stern "blinken" weiter. Das "Löschen" ist nur mit dem Taster oder mit dem Ein/Ausschalter möglich!

Listing 3.9 zeigt dieses Unterprogramm (Auszug aus Adventalender.c).

Tageszaehlung
nach oben

3.4.4. Konstanten, globale Variablen, Tabelle und Unterprogramme zur Erzeugung der Flackerlichter

Das Prinzip zur Erzeugung von Flackerlicht ist im Abschnitt 1 (Grundlegendes zur Erzeugung von Flackerlicht) sehr ausführlich erklärt. Hier erfolgen nun die Besonderheiten bei diesem Projekt.

Ein wichtiger Punkt bei der Erzeugung mehrerer Flackerlichter ist, dass der Eindruck entsteht, dass die Leuchtdioden unabhängig voneinander flackern. Bei diesem Projekt werden die Flackerlichter mit einer Tabelle erzeugt. Damit der Eindruck entsteht, dass die Leuchtdioden uabhängig voneinander flackern, besitzt jede Leuchtdioden eigene Variablen, und die Zählvariablen, die die Positionen in der Tabelle angeben, startet an einer anderen Position in der Tabelle. Dadurch erscheint der Eindruck, dass die Leuchtdioden unabhängig voneinander flackern. In Wirklichkeit ist der Flackerzyklus für jede Leuchtdiode gleich, sie sind nur zeitlich verschoben.

Anmerkung zum Quellcode:
Wenn man den Quellcode genau betrachtet, dann fällt auf, dass hier auf Schleifen verzichtet wurde. Mit Schleifen wäre der Quellcode deutlich kürzer und würde viel weniger Programmspeicher benötigen. Warum wurden hier keine Schleifen verwendet? Gegen die Verwendung von Schleifen spricht, dass diese sehr viel Overhead produzieren, und bei sovielen Flackerlichtern wie hier (insgesamt 76, wenn alle 24 Kerzen, der Baum und der Stern flackern) die Ausführungsgeschwindigkeit zu gering ist, sodass kein "flackern" mehr entsteht, nur mehr ein sehr langsames "hell-und-dunkler-werden" der Leuchtdioden.
Um die 1k-Grenze der freien Version des CC5X-Compilers nicht zu sprengen, wurde die Erzeugung der gesamten Flackerlichter in drei C-Quelldateien aufgeteilt (in Baum, Kerzen und Stern).

Konstanten:
Gemäß Abschnitt 1 (Grundlegendes zur Erzeugung von Flackerlicht) sind für die Erzeugung der Flackerlichter die beiden Konstanten KONST_PWM_OBERGRENZE (Zeile 156, beinhaltet den Wert 32) und KONST_GLEICHHEIT (Zeile 157, beinhaltet den Wert 5) notwendig.

Die Konstanten KONST_TABSTART_TAGxx (Zeilen 160 bis 235) geben für jede Leuchtdiode den Startwert in der Tabelle TabFlackerlicht an. So entsteht, wie schon vorher erwähnt, der Eindruck dass alle Leuchtdioden unabhängig voneinander flackern.

Bei einem "normalen" Adventkalender ist es üblich, dass die Türchen des Adventkalenders "durcheinander" angeordnet sind. So auch bei dieser elektronischen Variante. Die Türchen sind hier die Kerzen. Ab welchen Tag welche Kerze aktiv sein soll bestimmen die Konstanten KONST_TAGA bis KONST_TAGZ (Zeilen 238 bis 263), wobei KONST_TAGA dem Baum entspricht, KONST_TAGB bis KONST_TAGY den Kerzen und KONST_TAGZ dem Stern. Hier mein Vorschlag: am ersten Tag leuchtet zustätzlich zur ersten Kerze (Tag L) auch der Baum (Tag A), und am 24ten Tag zusätzlich zur letzten Kerze (Tag D) auch der Stern (Tag Z). Mit Hilfe der Konstanten KONST_TAGA bis KONST_TAGZ kann diese Zuordnung eigenen Bedürfnissen angepasst werden.
Die Abbildung 3.2 zeigt die Zuordnung der Kerzen und an welchem Tag welche Leuchtdioden aktiv werden.

Zuordnung der Leuchtdioden

Alle Konstanten sind in der Header-Datei PROJEKT.H definiert (Listing 3.10):

Konstanten fuer Flackerlichter (Teil 1)
Konstanten fuer Flackerlichter (Teil 2)
Konstanten fuer Flackerlichter (Teil 3)

Globale Variablen:
Damit die vielen Leuchtdioden unabhängig voneinander flackern sind für jede Leuchtdiode zwei globale Variablen notwendig (TabZaehlerTagXX und PWM_LED_TagXX).

Tabelle:
Wie im Abschnitt 1 (Grundlegendes zur Erzeugung von Flackerlicht) beschrieben erfolgt beim elektronischen Adventkalender die Erzeugung der Flackerlichter mit Hilfe einer Tabelle. Diese Tabelle soll hier wegen der Vollständigkeit nochmal erwähnt werden. Listing 3.11 zeigt (nochmal) die Tabelle TabFlackerlicht.

Tabelle fuer Flackerlichter (Teil 1)
Tabelle fuer Flackerlichter (Teil 2)

Unterprogramme:
Für die Erzeugung der vielen Flackerlichter sind sechs Unterprogramme notwendig.

Unterprogramm Init_Flackerlicht_Baum:
Dieses Unterprogramm hat nur die Aufgabe die Zählregister für die Leuchtdioden die den Baum symbolisieren mit den Anfangspositionen zu initialisieren und zwei Register für die Puls-Weiten-Modulation (für den Baum). Listing 3.12 zeigt dieses Unterprogramm.

Anmerkung:
Dieses Unterprogramm wird im Hauptprogramm nach dem Initialisieren des Mikrocontrollers aufgerufen (Siehe Hauptprogramm, Listing 3.5, Zeile 577).

Unterprogramm Init_Flackerlicht_Baum

Unterprogramm Flackerlicht_Baum:
Dieses Unterprogramm erzeugt das Flackern (Puls-Weiten-Modulation, PWM) für die Leuchtdioden, die den Baum symbolisieren.
Es entspricht vom Prinzip her dem Listing aus Abschnitt 1 (Grundlegendes zur Erzeugung von Flackerlicht).

Die wesentlichen Unterschiede gegenüber Abschnitt 1 sind:

  1. Dieses Unterprogramm erzeugt gleichzeitig 40 Flackerlichter.
  2. Das Setzen der Bits (TAGA_BAUMx) erfolgt nur wenn der Baum aktiviert (eingeschaltet) ist (Tageszähler größer oder gleich wie die Konstante KONST_TAGA).
Wichtig:
Dieses Unterprogramm muss im Hauptprogramm regelmäßig (zyklisch) aufgerufen werden (Siehe Hauptprogramm, Listing 3.5, Zeile 585).

Listing 3.13 zeigt die Realisierung von diesem etwas längerem Unterprogramm.

Unterprogramm Flackerlicht_Baum

Unterprogramm Init_Flackerlicht_Kerzen:
Dieses Unterprogramm hat nur die Aufgabe die Zählregister für die Leuchtdioden die die Kerzen symbolisieren mit den Anfangspositionen zu initialisieren und zwei Register für die Puls-Weiten-Modulation (für die Kerzen). Listing 3.14 zeigt dieses Unterprogramm.

Anmerkung:
Dieses Unterprogramm wird im Hauptprogramm nach dem Initialisieren des Mikrocontrollers aufgerufen (Siehe Hauptprogramm, Listing 3.5, Zeile 578).

Unterprogramm Init_Flackerlicht_Kerzen

Unterprogramm Flackerlicht_Kerzen:
Dieses Unterprogramm erzeugt das Flackern (Puls-Weiten-Modulation, PWM) für die Leuchtdioden, die die Kerzen symbolisieren.
Es entspricht vom Prinzip her dem Listing aus Abschnitt 1 (Grundlegendes zur Erzeugung von Flackerlicht).

Die wesentlichen Unterschiede gegenüber Abschnitt 1 sind:

  1. Dieses Unterprogramm erzeugt gleichzeitig 24 Flackerlichter.
  2. Das Setzen der Bits (TAGx_FLAMME bzw.TAGx_WACHS) erfolgt nur wenn diese Kerze aktiviert (eingeschaltet) ist (Tageszähler größer oder gleich wie die Konstante KONST_TAGx).
Wichtig:
Dieses Unterprogramm muss im Hauptprogramm regelmäßig (zyklisch) aufgerufen werden (Siehe Hauptprogramm, Listing 3.5, Zeile 586).

Listing 3.15 zeigt die Realisierung von diesem etwas längerem Unterprogramm.

Unterprogramm Flackerlicht_Kerzen (Teil 1)
Unterprogramm Flackerlicht_Kerzen (Teil 2)
Unterprogramm Flackerlicht_Kerzen (Teil 3)

Unterprogramm Init_Flackerlicht_Stern:
Dieses Unterprogramm hat nur die Aufgabe die Zählregister für die Leuchtdioden die den Stern symbolisieren mit den Anfangspositionen zu initialisieren und zwei Register für die Puls-Weiten-Modulation (für den Stern). Listing 3.16 zeigt dieses Unterprogramm.

Anmerkung:
Dieses Unterprogramm wird im Hauptprogramm nach dem Initialisieren des Mikrocontrollers aufgerufen (Siehe Hauptprogramm, Listing 3.5, Zeile 579).

Unterprogramm Init_Flackerlicht_Stern

Unterprogramm Flackerlicht_Stern:
Dieses Unterprogramm erzeugt das Flackern (Puls-Weiten-Modulation, PWM) für die Leuchtdioden, die den Stern symbolisieren.
Es entspricht vom Prinzip her dem Listing aus Abschnitt 1 (Grundlegendes zur Erzeugung von Flackerlicht).

Die wesentlichen Unterschiede gegenüber Abschnitt 1 sind:

  1. Dieses Unterprogramm erzeugt gleichzeitig 12 Flackerlichter.
  2. Das Setzen der Bits (TAGZ_STERNx) erfolgt nur wenn der Stern aktiviert (eingeschaltet) ist (Tageszähler größer oder gleich wie die Konstante KONST_TAGZ).
Wichtig:
Dieses Unterprogramm muss im Hauptprogramm regelmäßig (zyklisch) aufgerufen werden (Siehe Hauptprogramm, Listing 3.5, Zeile 587).

Listing 3.17 zeigt die Realisierung von diesem etwas längerem Unterprogramm.

Unterprogramm Flackerlicht_Stern (Teil 1)
Unterprogramm Flackerlicht_Stern (Teil 2)
nach oben

3.4.5. Unterprogramme zur seriellen Datenausgabe mit den Schieberegistern vom Typ 74xx595

Die Ansteuerung der Leuchtdioden erfolgt bei diesem Projekt mit Hilfe von Schieberegistern. Die softwaretechnische Ansteuerung der Schieberegister erfolgt mit Hilfe von zwei Unterprogrammen.

Protokoll zur Kommunikation mit den Schieberegistern:
Die Abbildung 3.3 zeigt das sehr einfache Protokoll zur Kommunikation mit den Schieberegistern vom Typ 74xx595, und die Reihenfolge, in welcher die Register in die Schieberegister geschoben werden müssen, damit die "richtigen" Leuchtdioden angesteuert werden.

Serielle Datenausgabe

Beim Übertragen der einzelnen Bits muss die Steuerleitung Port_Enable low sein. Erst nachdem alle Bits gesendet wurden muss ein kurzer High-Impuls (Ladeimpuls) erfolgen. Erst bei diesem Ladeimpuls übernehmen die Schieberegister die Daten.

Wichtig:
Das 8-Bit-Datenregister welches für das Schieberegister, dass vom Mikrocontroller am "weitesten entfernt" ist, zuständig ist (hier IC14), muss als erstes gesendet werden. Hier muss daher das Register Flackerlichter12 (für IC14) als erstes gesendet werden.

Portdefinitionen:
Für die Kommunikation mit den Schieberegistern sind drei Portleitungen des Mikrocontrollers notwendig. Diese werden in der Datei PROJEKT.H gemäß der Schaltung nach Abbildung 2.1 definiert.

Listing 3.18 zeigt die Portdefinitionen für die Kommunikation mit den Schieberegistern.

Portdefinition Schieberegister

Unterprogramme:
Die Kommunikation mit den Schieberegistern erfolgt mit den beiden Unterprogrammen SR_74xx595_SendData und SR_74xx595_SendByte.

Unterprogramm SR_74xx595_SendData:
Dieses Unterprogramm erzeugt dass Protokoll gemäß Abbildung 3.3. Zunächst muss die Steuerleitung Port_Enable gelöscht werden, dann nacheinander die Datenbits (in den Registern FlackerlichterXX) mit dem Unterprogramm SR_74xx595_SendByte in die Schieberegister schieben. Nach dem letzten Datenbit einen Ladeimpuls für die Übernahme in die Schieberegister erzeugen.

Listing 3.19 zeigt die Realisierung dieses Unterprogramms.

Unterprogramm SR_74xx595_SendData (Teil 1)
Unterprogramm SR_74xx595_SendData (Teil 2)

Hilfs-Unterprogramm SR_74xx595_SendByte:
Dieses Hilfs-Unterprogramm gibt mit Hilfe einer Schleife das MSB (Bit 7) am Datenausgang aus, erzeugt einen Takt und schiebt alle Bits um eine Stelle weiter.

Listing 3.20 zeigt die Realisierung dieses Unterprogramms.

Unterprogramm SR_74xx595_SendByte
nach oben

3.5. Konfigurationsbits

Ein praktischer Vorteil des CC5X-Compiler gegenüber anderen Compilern ist, dass die Konfigurationsbits für den Mikrocontroller (hier für den PIC16F87) direkt im Quellcode gesetzt werden können.

Listing 3.21 zeigt die notwendigen Einstellungen für den PIC16F87 für dieses Projekt.

Konfiguration des PIC16F87 (Teil 1)
Konfiguration des PIC16F87 (Teil 2)
nach oben

1 Der PIC16F87 besitzt 12 Interruptquellen. Bei diesem Projekt wird aber nur der Timer-0-Interrupt benötigt.

nach oben


zurück zu Elektronik, Homepage

Autor: Stefan Buchgeher
Erstellt: 7. Februar 2010
Letzte Änderung: