Porterweiterung - Darf's ein Port mehr sein?
Materialbedarf
Anz. | Bezeichnung | Datenblatt |
1 | Batterie/Spannungsquelle 9V | |
1 | Spannungsregler 7805 |
![]() |
1 | ATMega8 AVR-Prozessor |
![]() |
1 | 74HC164 |
![]() |
2 | 74HC175 |
![]() |
8 | Widerstand 220 Ohm | |
1 | Widerstand 10 kOhm | |
1 | Elektrolytkondensator 100 µF/16V | |
1 | Kondensator 100nF | |
8 | Standard-Leuchtdiode 3mm oder 5mm |
![]() ![]() |
Wenn die Ports nicht reichen
Man ist intensiv dabei sein neues Projekt zu planen. Kern des Gerätes soll ein ATmega8 sein. Aber nach kurzer Planungsphase der Hardware muss man feststellen, dass man nicht alle Ein- und Ausgabeelemente an den vorhanden Ports angeschlossen bekommt. Die Anzahl der Ports reichen vorne und hinten nicht. Die Lösung ist relativ einfach. Man muss die Ports um Weitere ergänzen. Wie ist dies möglich?
Dazu schauen wir uns einmal an, was so ein Port eigentlich ist. Die Ports des AVR können als Ausgang und als Eingang arbeiten. Wenn Sie als Ausgang arbeiten, werden interne Daten-FlipFlops zum Pin durchgeschaltet. Diese Daten-FlipFlops werden mit einer Zuweisung mit den gewünschten Daten gefüllt (In Bascom mit Portx = Wert). Dann werden die Daten zu den Pins durchgeschaltet.
Soll der Port als Eingang arbeiten, werden einfach nur die Eingänge an den internen Datenbus des AVR gelegt wo sie dann weiter verarbeitet werden.
Ergänzung von Ausgangsports durch Daten-Register
Will man weitere Ausgangsports haben, ist es das Einfachste man klemmt weitere Daten-Register an den AVR. Nun muss man nur noch die externen Register mit Daten füllen.
![]() Um jetzt den entsprechenden Latch zu füllen, muss man nun am Port D die gewünschten Daten anlegen. Jetzt muss nur noch der Steuereingang CP des entsprechenden Registers kurz auf 1 gelegt werden. Für Latch 1 liegt der CP-Eingang auf Port C Bit 0 und für das zweite Latch auf Üprt C Bit 1. Wurde ein kurzes 1-Signal an das entsprechende Latch abgegeben, werden die Daten übernommen, was dann die Leuchtdioden D1-D4, für Latch 1, bzw. D5-D8, für Latch 2, anzeigen. Um dies nun zu testen gibt es ein kleines Programm: |
$regfile "m8def.dat" Portd = &B00001001 Portc.0 = 1 : Portc.0 = 0 Portd = &B00001010
Portc.1 = 1 : Portc.1 = 0 |
Zu dem Programm muss nicht allzu viel gesagt werden. Erst legen wir mit
Portd = &B00001001 |
ein Bitmuster an Port D, welches wir ins 1. Latch übernehmen wollen. Damit dieses das tut, müssen wir den CP-Eingang des ICs kurz auf 1 legen. Wie wir wissen, liegt CP von Latch 1 auf Port C Bit 0. Somit brauchen wir nur 2 einfache Anweisungen:
Portc.0 = 1 : Portc.0 = 0 |
Nun leuchten D1 und D4 auf.
Für das zweite Latch läuft das Ganze ähnlich ab. Nur müssen wir hier nun das Bit 1 von Port C kurz auf 1 setzen.
Als nächstes schreiben wir einmal ein kleines Programm, welches auf den beiden Latches unterschiedliche Lichtmuster ausgeben. Auf Latch 1 wird ein 4 Bit Binärzähler dargestellt. Latch 2 zeigt hier ein kleines Lauflicht.
$regfile "m8def.dat" $crystal = 1000000 Dim Reg1 As Byte Dim Reg2 As Byte Config Portc.0 = Output Config Portc.1 = Output Config Portd = Output Reg2 = 1 Do Portd = Reg1 Portc.0 = 1 : Portc.0 = 0 Incr Reg1 Portd = Reg2 Portc.1 = 1 : Portc.1 = 0 Shift Reg2 , Left : If Reg2 = 16 Then Reg2 = 1 Waitms 300 Loop |
Mit Hilfe von Latches kann man also die Ports des AVR schon massiv erweitern. Nehmen wir einmal an, es sind 2 Latches mit 8 Bit angeschlossen, so benötigen wir 10 Portpins um 16 Ausgänge zu steuern. Verwenden wir 3 Latches, benötigen wir 11 Port-Pins und uns stehen schon 24 Ausgänge zur Verfügung.
Weitere Ausgangsports durch Schieberegister
Obwohl es mit Latches schon sehr gut möglich ist, die Anzahl der Ausgänge des AVR zu erhöhen, sind freie Port-Pins trotzdem noch Mangelware. Es gibt aber eine Möglichkeit, wo wir mit 3 oder 4 Port-Pins auskommen und dadurch den AVR theoretisch unendlich viele Ausgänge verpassen können.
Den Reset-Eingang (MR=Master Reset) des Schieberegisters wird an Port D Bit 0 angeschlossen. Schieberegister benötigen noch ein Taktsignal, welches hier CP genannt wurde, dieses hängt an Bit 1 des Ports D. Der 74HC164 besitzt 2 Dateneingänge, welche aber durch eine Und-Funktion miteinander verknüpft sind, so dass wir nur Da an Port D Bit 2 des AVR klemmen. Db wird dauerhaft an + gelegt. Die Ansteuerung eines Schieberegisters ist leider etwas komplizierter. Bevor es mit Daten gefüllt wird, sollte es erst einmal zurückgesetzt werden. MR muss kurzzeitig auf 0 gesetzt werden. Im Normalbetrieb befindet sich dieser Eingang auf 1-Signal. Als Nächstes muss man das 1. Bit, welches in das Schieberegister hinein geschoben werden soll an Da anlegen. Nun muss man CP kurz auf 1 legen. Jetzt ist das 1. Bit im Register. Nun kann das 2. Bit an Da angelegt werden. Wieder CP kurz auf 1 legen. Das 1. Bit 'wandert' eine Stufe hoch und das 2. Bit wird hinein geschoben. Dies wird nun so lange wiederholt bis das Register gefüllt ist. Da wir hier nur 4 Ausgänge verwenden, muss das Ganze 4 mal wiederholt werden. Das diese Routine nicht ganz so einfach ist, wie beim parallelem Latch zeigt das entsprechende Testprogramm: |
$regfile "m8def.dat" $crystal = 1000000 Dim Reg As Byte Dim Save As Byte Dim Outbit As Boolean Dim Cnt As Byte Config Portd.0 = Output Config Portd.1 = Output Config Portd.2 = Output Portd.1 = 0 Do Save = Reg : Portd.0 = 0 : Portd.0 = 1 For Cnt = 1 To 4 Outbit = Save And 1 : Portd.2 = Outbit Portd.1 = 1 : Portd.1 = 0 Shift Save , Right Next Cnt Incr Reg : Waitms 300 Loop |
Mit diesem Programm realisieren wir wieder einen kleinen 4 Bit Binärzähler.
Bevor wir etwas ins Schieberegister schreiben können, müssen wir als erstes unsere Zählvariable sichern. Hierzu wurde die Variable 'Save' definiert. Dies ist notwendig da diese Variable im Laufe der Datenübertragung verändert wird. Dann sollte das Schiebergister zurück gesetzt werden.
Save = Reg : Portd.0 = 0 : Portd.0 = 1 |
Wie weiter oben schon erwähnt, wollen wir nur 4 Bit übertragen. Daher hat die folgende For-Next-Schleife auch nur 4 Durchläufe.
Als ersten Befehl innerhalb der Schleife maskieren wir das kleinste Bit unseres zu übertragenen Wertes aus und legen das Ergebnis an den Datenport:
Outbit = Save And 1 : Portd.2 = Outbit |
Der Einfachheit halber nehmen wir das unterste Bit. Da dieses Bit im Schieberegister aber später nach oben geschoben wird, kommt es am Schieberegisterausgang zu einer Spiegelung. Aber das Prinzip dürfte trotzdem verstanden werden.
Nun wo das Datenbit an Da anliegt, müssen wir dem Schieberegister noch den Befehl zur Übernahme geben. Dies wird ja erreicht durch ein kurzes anlegen des 1-Signal am CP des ICs:
Portd.1 = 1 : Portd.1 = 0 |
Jetzt ist das Bit in das Schieberegister übertragen worden. Nun müssen wir noch dafür sorgen, dass beim nächsten Schleifendurchgang das nächste Bit übertragen wird:
Shift Save , Right |
Hier schieben wir jetzt das ganze Variablenbyte um eine Stelle nach rechts. Das bereits übertragene Bit wird dann jeweils 'vergessen'.
Zum Abschluss schließen wir die For-Next-Schleife noch ab. So werden nun die unteren 4 Bit unserer Zählvariable ans Schieberegister übertragen und wir können den Wert an den Leuchtdioden ablesen. Aber eben nur die unteren 4 Bit. Die oberen 4 Bit der Zählvariable werden in diesem Beispiel ignoriert.
Jetzt muss noch die Zählvariable durch 'Incr Reg' um 1 erhöht werden. Und, damit wir den Wert an den LEDs auch ablesen können, wurde eine Wartezeit eingefügt.
Somit ist es möglich, rein theoretisch, unendlich viele Ausgänge mit nur wenigen Ports zu realisieren. Ein großer Nachteil dieser Methode soll aber nicht verschwiegen werden. Da jedes Bit, welches zusätzlich in eine Schieberegister-Kette geschoben werden soll, relativ viel Rechenzeit benötigt, können Schieberegister nicht für Anwendungen genutzt werden, wo hohe Ausgangsfrequenzen benötigt werden. Da dies aber selten vorkommt, ist es wohl weniger ein Problem. |