AVR-Tutorial: Schieberegister: Unterschied zwischen den Versionen
Heha (Diskussion | Beiträge) |
Heha (Diskussion | Beiträge) |
||
Zeile 414: | Zeile 414: | ||
== Porterweiterung für Eingänge == | == Porterweiterung für Eingänge == | ||
Ein naher Verwandter des 74xx595 ist der [[74xx | 74xx165]], er ist quasi das Gegenstück. Hierbei handet es sich um ein ''8-bit parallel-in/serial-out shift register''. Auf Deutsch: Ein 8 Bit Schieberegister mit parallelem Eingang und seriellem Ausgang. Damit kann man eine | Ein naher Verwandter des 74xx595 ist der [[74xx | 74xx165]], er ist quasi das Gegenstück. Hierbei handet es sich um ein ''8-bit parallel-in/serial-out shift register''. Auf Deutsch: Ein 8 Bit Schieberegister mit parallelem Eingang und seriellem Ausgang. Damit kann man eine große Anzahl Eingänge sehr einfach und preiswert zu seinem Mikrocontroller hinzufügen. | ||
=== Aufbau === | === Aufbau === | ||
Zeile 428: | Zeile 428: | ||
D0..D7 sind die parallelen Dateneingänge. | D0..D7 sind die parallelen Dateneingänge. | ||
Mittels des Eingangs PL ('''P'''arallel '''L'''oad) werden die Daten vom parallelen Eingang in das Schieberegister übernommen, wenn dieses Signal LOW ist. Hier muss man aber ein klein wenig aufpassen. Auf | Mittels des Eingangs PL ('''P'''arallel '''L'''oad) werden die Daten vom parallelen Eingang in das Schieberegister übernommen, wenn dieses Signal LOW ist. Hier muss man aber ein klein wenig aufpassen. Auf Grund der Schaltungsstruktur ist der Eingang PL mit dem Takt CLK verknüpft (obwohl es dafür keinen logischen Grund gibt :-0). Damit es nicht zu unerwünschten Fehlschaltungen kommt, muss der Takt CLK während des Ladens auf HIGH liegen. Wird PL wieder auf HIGH gesetzt, sind die Daten geladen. Das erste Bit liegt direkt am Ausgang Q7 an. Die restlichen Bits können nach und nach durch das Register geschoben werden. | ||
Der Eingang CE ('''C'''lock '''E'''nable) steuert, ob das Schieberegister auf den Takt CLK reagieren soll oder nicht. Ist CE gleich HIGH werden alle Takte an CLK ignoriert. Bei LOW werden mit jeder positiven Flanke die Daten um eine Stufe weiter geschoben. | Der Eingang CE ('''C'''lock '''E'''nable) steuert, ob das Schieberegister auf den Takt CLK reagieren soll oder nicht. Ist CE gleich HIGH werden alle Takte an CLK ignoriert. Bei LOW werden mit jeder positiven Flanke die Daten um eine Stufe weiter geschoben. |
Version vom 18. Juli 2012, 15:57 Uhr
Ab und an stellt sich folgendes Problem: Man würde wesentlich mehr Ausgangspins oder Eingangspins benötigen als der Mikrocontroller zur Verfügung stellt. Ein möglicher Ausweg ist eine Porterweiterung mit einem Schieberegister. Zwei beliebte Schieberegister sind beispielsweise der 74xx595 bzw. der 74xx165.
Porterweiterung für Ausgänge
Um neue Ausgangspins zu gewinnen kann der 74xx595 verwendet werden. Dabei handelt es sich um ein 8-Bit 3-state Serial-in/Serial-out or Parallel-Out Schieberegister mit einem Ausgangsregister und einem asynchronen Reset.
Hinter dieser kompliziert anmutenden Beschreibung verbirgt sich eine einfache Funktionalität: Das Schieberegister besteht aus zwei Funktionseinheiten: Dem eigentlichen Schieberegister und dem Ausgangsregister. In das Schieberegister können die Daten seriell hineingetaktet werden und durch ein bestimmtes Signal werden die Daten des Schieberegisters in das Ausgangsregister übernommen und können von dort auf die Ausgangspins geschaltet werden.
Im Einzelnen bedeuten die Begriffe:
Begriff | Erklärung |
---|---|
8-Bit | Acht Ausgangsbits |
3-state | Die acht Registerausgänge können drei Zustände, Low, High und High-Impedanz annehmen. Siehe Ausgangsstufen Logik-ICs |
Serial-in | Serieller Eingang des Schieberegisters |
Serial-out | Serieller Ausgang des Schieberegisters |
Parallel-Out | Parallele Ausgänge des Ausgangsregisters |
Schieberegister | Serielle Daten werden durch den Baustein durchgeschoben |
Ausgangsregister | Ein Speicher, welcher die Daten des Schieberegisters zwischenspeichern kann. Dieses besteht aus acht FlipFlops. |
Asynchroner Reset | Die Daten im Schieberegister können asynchron zurückgesetzt werden. |
Aufbau 74xx595
Hinweis: Die Benennung der Pins in den Datenblättern verschiedener Hersteller unterscheidet sich zum Teil. Die Funktionen der Pins sind jedoch gleich.
Achtung: Es gibt auch noch einen IC von TI mit eingebauten Treibern 50 V 150 mA, den TPIC6B595, der hat 20 Pins und eine abweichende Pinbelegung http://www.ti.com/product/tpic6b595
Pinbelegung 74xx595
DIL Pin-Nummer | Funktion | Dieses Tutorial | Motorola / ON Semi | Philips / NXP | Fairchild | SGS | Texas Instruments |
---|---|---|---|---|---|---|---|
1 | Ausgang B | QB | QB | Q1 | QB | QB | QB |
2 | Ausgang C | QC | QC | Q2 | QC | QC | QC |
3 | Ausgang D | QD | QD | Q3 | QD | QD | QD |
4 | Ausgang E | QE | QE | Q4 | QE | QE | QE |
5 | Ausgang F | QF | QF | Q5 | QF | QF | QF |
6 | Ausgang G | QG | QG | Q6 | QG | QG | QG |
7 | Ausgang H | QH | QH | Q7 | QH | QH | QH |
8 | Masse, 0 V | [nicht dargestellt] | GND | GND | GND | GND | GND |
9 | Serieller Ausgang | QH* | SQH | Q7´ | Q'H | QH´ | QH' |
10 | Reset für Schieberegister | SCL | RESET | /MR | /SCLR | /SCLR | /SRCLR |
11 | Schiebetakt | SCK | SHIFT CLOCK | SHCP | SCK | SCK | SRCLK |
12 | Speichertakt | RCK | LATCH CLOCK | STCP | RCK | RCK | RCLK |
13 | Ausgangssteuerung | G | OUTPUT ENABLE | /OE | /G | /G | /OE |
14 | Serieller Dateneingang | SER | A | DS | SER | SI | SER |
15 | Ausgang A | QA | QA | Q0 | QA | QA | QA |
16 | Betriebsspannung | [nicht dargestellt] | VCC | VCC | VCC | VCC | VCC |
Der Baustein besteht aus zwei Einheiten:
- dem Schieberegister
- dem Ausgangsregister
Im Schieberegister werden die einzelnen Bits durchgeschoben. Mit jeder positiven Taktflanke(LOW -> HIGH) an SCK wird eine Schiebeoperation durchgeführt.
Das Ausgangsregister hat die Aufgabe die Ausgangspins des Bausteins anzusteuern. Durch dieses Ausgangsregister ist es möglich, die Schiebeoperationen im Hintergrund durchzuführen, ohne dass IC Pins ihren Wert ändern. Erst wenn die Schiebeoperation abgeschlossen ist, wird der aktuelle Zustand der Schieberegisterkette durch einen Puls an RCK in das Ausgangsregister übernommen.
Funktionsweise
Am Eingang SER (Pin 14) wird das gewünschte nächste Datum (0 oder 1) angelegt. Durch einen positiven Puls an SCK (Pin 11) wird der momentan an SER anliegende Wert als neuer Wert für Bit 0, das unterste Bit des Schieberegisters, übernommen. Gleichzeitig werden alle anderen Bits im Schieberegister um eine Stelle verschoben: Das Bit 6 wird ins Bit 7 übernommen, Bit 5 ins Bit 6, Bit 4 ins Bit 5, etc. sodass das Bit 0 zur Aufnahme des SER Bits frei wird.
Eine Sonderstellung nimmt das ursprüngliche Bit 7 ein. Dieses Bit steht direkt auch am Ausgang QH* (Pin 9) zur Verfügung. Dadurch ist es möglich an ein Schieberegister einen weiteren Baustein 74xxx595 anzuschließen und so beliebig viele Schieberegister hintereinander zu schalten (kaskadieren). Auf diese Art lassen sich Schieberegister mit beliebig vielen Stufen aufbauen.
Wurde das Schieberegister mit den Daten gefüllt, so wird mit einem LOW-HIGH Puls am Pin 12, RCK der Inhalt des Schieberegisters in das Ausgangsregister übernommen.
Mit dem Eingang G (Pin 13) kann das Ausgangsregister freigegeben werden. Liegt G auf 0, so führen die Ausgänge QA bis QH entsprechende Pegel. Liegt G auf 1, so schalten die Ausgänge QA bis QH auf Tristate. D.h. sie treiben aktiv weder LOW oder HIGH, sondern sind hochohmig wie ein Eingang und nehmen jeden Pegel an, der ihnen von außen aufgezwungen wird.
Bleibt nur noch der Eingang SCL(Pin 10). Mit ihm kann das Schieberegister im Baustein gelöscht, also auf eine definierte 0, gesetzt werden.
Die Programmierung eines 74xxx595 Schieberegisters gestaltet sich sehr einfach. Im Grunde gibt es 2 Möglichkeiten:
- Mittels SPI kann der AVR das Schieberegister direkt und autark ansteuern. Das ist sehr schnell und verbraucht nur wenig CPU-Leistung
- Sind die entsprechenden SPI-Pins am AVR nicht frei, so ist auch eine softwaremäßige Ansteuerung des Schieberegisters mit einfachen Mitteln durchführbar.
Ansteuerung per Software
Für eine komplette Softwarelösung kann das Schieberegister an jede beliebige Port-Pin Kombination angeschlossen werden. Wir wählen die Pins PB0, PB1, PB2 und PB3 um dort die Schieberegisteranschlüsse SER, SCK, SCL und RCK anzuschließen. Des Weiteren muss das Schieberegister mit Strom versorgt werden, auch wenn das rechts im Bild nicht eingezeichnet ist. Pin 16 muss auf +5V und Pin 8 auf GND geschaltet werden.
Die Programmierung gestaltet sich dann nach folgendem Schema: Die 8 Bits eines Bytes werden nacheinander an den Ausgang PB0 (SER) ausgegeben. Durch Generierung eines Pulses 0-1-0 an Pin PB1 (SCK) übernimmt das Schieberegister nacheinander die einzelnen Bits. Dabei ist zu beachten, dass die Ausgabe mit dem höherwertigen Bit beginnen muss, denn dieses Bit wandert ja am weitesten zur Stelle QH. Sind alle 8 Bits ausgegeben, so wird durch einen weiteren 0-1-0 Impuls am Pin PB3 (RCK) der Inhalt der Schieberegisterbits 0 bis 7 in die Ausgaberegister QA bis QH übernommen. Dadurch, dass am Schieberegister der Eingang G konstant auf 0-Pegel gehalten wird, erscheint dann auch die Ausgabe sofort an den entsprechenden Pins und kann zb. mit LEDs (low-current LEDs + Vorwiderstand verwenden) sichtbar gemacht werden.
Der Schieberegistereingang SCL wird auf einer 1 gehalten. Würde er auf 0 gehen, so würde die Schieberegisterkette gelöscht. Möchte man einen weiteren Prozessorpin einsparen, so kann man diesen Pin auch generell auf Vcc legen. Das Schieberegister könnte man in so einem Fall durch Einschreiben von 0x00 immer noch löschen.
<avrasm> .include "m8def.inc"
.def temp1 = r16 .def temp2 = r17
.equ SCHIEBE_DDR = DDRB .equ SCHIEBE_PORT = PORTB .equ RCK = 3 .equ SCK = 1 .equ SCL = 2 .equ SIN = 0
ldi temp1, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1
- Die Port Pins auf Ausgang konfigurieren
ldi temp1, (1<<RCK) | (1<<SCK) | (1<<SCL) | (1<<SIN) ; Anm.1 out SCHIEBE_DDR, temp1
- die Clear Leitung am Schieberegister auf 1 stellen
sbi SCHIEBE_PORT, SCL
- Ein Datenbyte ausgeben
ldi temp1, 0b10101010 rcall Schiebe rcall SchiebeOut
loop:
rjmp loop
- -----------------------------------------------------------------------------
- Die Ausgabe im Schieberegister in das Ausgaberegister übernehmen
- Dazu am RCK Eingang am Schieberegister einen 0-1-0 Puls erzeugen
SchiebeOut:
sbi SCHIEBE_PORT, RCK cbi SCHIEBE_PORT, RCK ret
- -----------------------------------------------------------------------------
- 8 Bits aus temp1 an das Schieberegister ausgeben
Schiebe:
push temp2 ldi temp2, 8 ; 8 Bits müssen ausgegeben werden
Schiebe_1:
; ; jeweils das höchstwertige Bit aus temp1 ins Carry-Flag schieben ; Je nach Zustand des Carry-Flags wird die Datenleitung entsprechend ; gesetzt oder gelöscht ; rol temp1 ; MSB -> Carry brcs Schiebe_One ; Carry gesetzt? -> weiter bei Schiebe_One cbi SCHIEBE_PORT, SIN ; Eine 0 ausgeben rjmp Schiebe_Clock ; und Sprung zur Clock Puls Generierung
Schiebe_One:
sbi SCHIEBE_PORT, SIN ; Eine 1 ausgeben
; ; einen Impuls an SCK zur Übernahme des Bits nachschieben ;
Schiebe_Clock:
sbi SCHIEBE_PORT, SCK ; Clock-Ausgang auf 1 ... cbi SCHIEBE_PORT, SCK ; und wieder zurück auf 0
dec temp2 ; Anzahl der ausgegebenen Bits runterzählen brne Schiebe_1 ; Wenn noch keine 8 Bits ausgegeben -> Schleife bilden
pop temp2 ret
</avrasm>
Anm.1: Siehe Bitmanipulation
Ansteuerung per SPI-Modul
Noch schneller geht die Ansteuerung des Schieberegisters mittels SPI-Modul, welches in fast allen AVRs vorhanden ist. Hier wird der Pin SCL nicht benutzt, da das praktisch keinen Sinn hat. Er muss also fest auf VCC gelegt werden. (Oder mit den Reset-Pin des AVRs, das mit einer RC Schaltung versehen ist, verbunden werden. Damit erreicht man einen definierten Anfangszustand des Schieberegisters) Die Pins für SCK und SIN sind duch den jeweiligen AVR fest vorgegeben. SCK vom 74xxx595 wird mit SCK vom AVR verbunden sowie SIN mit MOSI (Master Out, Slave In). MISO (Master In, Slave Out) ist hier ungenutzt. Es kann NICHT als RCK verwendet werden, da es im SPI-Master Modus immer ein Eingang ist! Es kann aber als allgemeiner Eingang verwendet werden. Der AVR-Pin SS wird sinnvollerweise als RCK benutzt, da er sowieso als Ausgang geschaltet werden muss, sonst gibt es böse Überaschungen (siehe Datenblatt "SS Pin Functionality"). Dieser sollte mit einem Widerstand von 10K nach Masse, während der Start- und Initialisierungsphase, auf L-Potential gehalten werden. `(SS ist während dieser Zeit noch im Tri-State und es könnte passieren, dass die zufälligen Daten des Schieberegisters in das Ausgangslatch übernommen werden) Je nach Bedarf kann man die Taktrate des SPI-Moduls zwischen 1/2 ... 1/128 des CPU-Taktes wählen. Es spricht kaum etwas dagegen mit maximaler Geschwindigkeit zu arbeiten. Die AVRs können zur Zeit mit maximal 20 MHz getaktet werden, d.h. es sind maximal 10 MHz SPI-Takt möglich. Das ist für ein 74xxx595 kein Problem. Die Übertragung von 8 Bit dauert dann gerade mal 800ns!
<avrasm> .include "m8def.inc"
.def temp1 = r16
- Die Definitionen müssen an den jeweiligen AVR angepasst werden
.equ SCHIEBE_DDR = DDRB .equ SCHIEBE_PORT = PORTB .equ RCK = PB2 ; SS .equ SCK = PB5 ; SCK .equ SIN = PB3 ; MOSI
ldi temp1, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1
- SCK, MOSI, SS als Ausgänge schalten
in temp1, SCHIEBE_DDR ori temp1, (1<<SIN) | (1<<SCK) | (1<<RCK) out SCHIEBE_DDR,temp1
- SPI Modul konfigurieren
ldi temp1, (1<<SPE) | (1<<MSTR) out SPCR, temp1 ; keine Interrupts, MSB first, Master ; CPOL = 0, CPHA =0 ; SCK Takt = 1/2 XTAL ldi temp1, (1<<SPI2X) out SPSR, temp1 ; double speed aktivieren out SPDR, temp1 ; Dummy Daten, um SPIF zu setzen
- Ein Datenbyte ausgeben
ldi temp1, 0b10101010 rcall Schiebe ; Daten schieben rcall SchiebeOut ; Daten in Ausgangsregister übernehmen
loop:
rjmp loop
- -----------------------------------------------------------------------------
- Die Daten im Schieberegister in das Ausgaberegister übernehmen
- Dazu am RCK Eingang am Schieberegister einen 0-1-0 Puls erzeugen
SchiebeOut:
sbis SPSR, SPIF ; prüfe ob eine alte Übertragung beendet ist rjmp SchiebeOut sbi SCHIEBE_PORT, RCK cbi SCHIEBE_PORT, RCK ret
- -----------------------------------------------------------------------------
- 8 Bits aus temp1 an das Schieberegister ausgeben
Schiebe:
sbis SPSR, SPIF ; prüfe ob eine alte Übertragung beendet ist rjmp Schiebe out SPDR, temp1 ; Daten ins SPI Modul schreiben, Übertragung beginnt automatisch ret
</avrasm>
Kaskadieren von Schieberegistern
Um ein Schieberegister anzuschließen genügen also im einfachsten Fall 4 freie Prozessorpins (3 wenn SCL nicht benutzt wird) um weitere 8 Ausgangsleitungen zu bekommen. Genügen diese 8 Leitungen nicht, so kann ohne Probleme ein weiteres Schieberegister an das bereits vorhandene angeschlossen werden.
Das nächste Schieberegister wird mit seinem Dateneingang SER einfach an den dafür vorgesehenen Ausgang QH* des vorhergehenden Schieberegisters angeschlossen. Die Steuerleitungen SCK, RCK und SCL werden parallel zu den bereits vorhandenen geschaltet. Konzeptionell erhält man dadurch ein Schieberegister mit einer Breite von 16 Bit. Werden weiter Bausteine in derselben Manier angeschlossen, so erhöht sich die Anzahl der zur Verfügung stehenden Ausgabeleitungen mit jedem Baustein um 8 ohne dass sich die Anzahl der am Prozessor notwendigen Ausgabepins erhöhen würde. Um diese weiteren Register zu nutzen, muss man in der reinen Softwarelösung nur mehrfach die Funktion Schiebe aufrufen, um alle Daten auszugeben. Am Ende werden dann mit SchiebeOut die Daten in die Ausgangsregister übernommen.
Bei der SPI Lösung werden ebenfalls ganz einfach mehrere Bytes über SPI ausgegeben, ehe dann mittels RCK die in die Schieberegisterkette eingetakteten Bits in das Ausgangsregister übernommen werden. Um das Ganze ein wenig zu vereinfachen, soll hier eine Funktion zur Ansteuerung mehrerer kaskadierter Schieberegister über das SPI-Modul gezeigt werden. Dabei wird die Ausgabe mehrerer Bytes über eine Schleife realisiert, mehrfache Aufrufe der Funktion sind damit nicht nötig. Statt dessen übergibt man einen Zeiger auf einen Datenblock im RAM sowie die Anzahl der zu übertragenden Bytes. Außerdem wird die Datenübernahme durch RCK standardkonform integriert. Denn bei nahezu allen ICs mit SPI wird ein sog. CS-Pin verwendet (Chip Select) Dieser Pin ist meist LOW aktiv, d.h. wenn er HIGH ist, ignoriert der IC alle Signale an SCK und MOSI und gibt keine Daten an MISO aus. Ist er LOW, dann ist der IC aktiv und funktioniert normal. Bei der steigenden Flanke an CS werden die Daten ins Ausgangsregister übernommen. Die Funktion ist sehr schnell, da die Zeit während der die Übertragung eines Bytes läuft, dazu genutzt wird, den Schleifenzähler zu verringern und zu prüfen sowie neue Sendedaten zu laden. Zwischen den einzelnen Bytes gibt es somit nur eine Pause von max. 6 Systemtakten.
<avrasm> .include "m8def.inc" .def temp1 = r16
- Die Definitionen müssen an den jeweiligen AVR angepasst werden
.equ SCHIEBE_DDR = DDRB .equ SCHIEBE_PORT = PORTB .equ RCK = PB2 ; SS .equ SCK = PB5 ; SCK .equ SIN = PB3 ; MOSI
- -----------------------------------------------------------------------------
- Datensegment im RAM
- -----------------------------------------------------------------------------
.dseg .org $60 Schiebedaten: .byte 2
- -----------------------------------------------------------------------------
- Programmsegment im FLASH
- -----------------------------------------------------------------------------
.cseg
ldi temp1, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1
- SCK, MOSI, SS als Ausgänge schalten
in temp1,SCHIEBE_DDR ori temp1,(1<<SIN) | (1<<SCK) | (1<<RCK) out SCHIEBE_DDR,temp1
sbi SCHIEBE_PORT, RCK ; Slave select inaktiv
- SPI Modul konfigurieren
ldi temp1, 0b01010000 out SPCR, temp1 ; keine Interrupts, MSB first, Master ; CPOL = 0, CPHA =0 ; SCK Takt = 1/2 XTAL ldi r16,1 out SPSR,r16 ; Double Speed out SPDR,temp1 ; Dummy Daten, um SPIF zu setzen
- den Datenblock mit Daten füllen
ldi temp1,$F0 sts Schiebedaten,temp1 ldi temp1,$55 sts Schiebedaten+1,temp1
loop:
- den Datenblock ausgeben
ldi r16,2 ldi zl,low(Schiebedaten) ldi zh, high(Schiebedaten) rcall Schiebe_alle ; Daten ausgeben
rjmp loop ; nur zur Simulation
- -----------------------------------------------------------------------------
- N Bytes an das Schieberegister ausgeben und in das Ausgaberegister übernehmen
- r16
- Anzahl der Datenbytes
- Z
- Zeiger auf Datenblock im RAM
- -----------------------------------------------------------------------------
Schiebe_alle:
cbi SCHIEBE_PORT, RCK ; RCK LOW, SPI Standardverfahren push r17
Schiebe_alle_2:
ld r17,Z+
Schiebe_alle_3:
sbis SPSR,SPIF ; prüfe ob eine alte Übertragung beendet ist rjmp Schiebe_alle_3 out SPDR,r17 ; Daten ins SPI Modul schreiben, Übertragung beginnt automatisch dec r16 brne Schiebe_alle_2
Schiebe_alle_4:
sbis SPSR,SPIF ; prüfe ob die letzte Übertragung beendet ist rjmp Schiebe_alle_4
pop r17 sbi SCHIEBE_PORT, RCK ; RCK inaktiv, Datenübernahme ret
</avrasm>
Der Nachteil von Schieberegistern ist allerdings, dass sich die Zeit zum Setzten aller Ausgabeleitungen mit jedem weiteren Baustein immer weiter erhöht. Dies deshalb, da ja die einzelnen Bits im Gänsemarsch durch alle Bausteine geschleust werden müssen und für jeden einzelnen Schiebevorgang etwas Zeit notwendig ist. Ein Ausweg ist die Verwendung des SPI-Moduls, welches schneller arbeitet als die reine Softwarelösung. Ist noch mehr Geschwindigkeit gefragt, so sind mehr Port-Pins nötig. Kann ein kompletter Port mit 8 Pins für die Daten genutzt werden, sowie ein paar weitere Steuerleitungen, so können ein oder mehrere 74xxx573 eine Alternative sein, um jeweils ein vollständiges Byte auszugeben. Natürlich kann der 74xxx573 (oder ein ähnliches Schieberegister) auch mit dem 74xxx595 zusammen eingesetzt werden, beispielsweise in dem über das Schieberegister verschiedene 74xxx595 nacheinander aktiviert werden. Weitere Tips und Tricks dazu gibt es vielleicht in einem weiteren Tutorial...
Acht LEDs mit je 20mA pro Schieberegister
Will man nun acht LEDs mit dem Schieberegister ansteuern, kann man diese direkt über Vorwiderstände anschließen. Doch ein genauer Blick ins Datenblatt verrät, dass der 74xx595 nur maximal 70mA über VCC bzw. GND ableiten kann. Und wenn man den IC nicht gnadenlos quälen, und damit die Lebensdauer und Zuverlässigkeit drastisch reduzieren will, gibt es nur zwei Auswege.
- Den Strom pro LED auf 70/8 = 8,75mA begrenzen; Das reicht meistens aus um die LEDs schön leuchten zu lassen, vor allem bei low-current und ultrahellen LEDs
- Wenn doch 20 mA pro LED gebraucht werden, kann man die folgende Trickschaltung anwenden.
Der Trick besteht darin, dass 4 LEDs ihren Strom über das Schieberegister von VCC beziehen (HIGH aktiv) während die anderen vier ihren Strom über GND leiten (LOW aktiv). Damit bleiben ganz offiziell für jede LED 70/4 = 17,5mA. Um die Handhabung in der Software zu vereinfachen muss nur vor der Ausgabe der Daten das jeweilige Byte mit 0x0F XOR verknüpft werden, bevor es in das Schieberegister getaktet wird. Dadurch werden die LOW-aktiven LEDs richtig angesteuert und die Datenhandhabung in der Software muss nur mit HIGH-aktiven rechnen. Außerdem wird der G Eingang verwendet, um die Helligkeit aller LEDs per PWM zu steuern. Beachtet werden muss, dass die PWM im invertierten Modus generiert werden muss, da der Eingang G LOW aktiv ist.
Achtung! Die Widerstände sind auf blaue LEDs mit 3,3V Flussspannung ausgelegt. Bei roten, gelben und grünen LEDs ist die Flussspannung geringer und dementsprechend muss der Vorwiderstand größer sein.
Wenn 20mA immer noch nicht reichen sollten oder z.B. RGB-LEDs mit gemeinsamer Anode angesteuert werden müssen, dann hilft nur ein stärkerer IC. Der Klassiker ist der TPIC6A595 von TI, er kombiniert ein Schieberegister mit MOSFETs, sodass hier 250mA pro Kanal zur Verfügung stehen.
Porterweiterung für Eingänge
Ein naher Verwandter des 74xx595 ist der 74xx165, er ist quasi das Gegenstück. Hierbei handet es sich um ein 8-bit parallel-in/serial-out shift register. Auf Deutsch: Ein 8 Bit Schieberegister mit parallelem Eingang und seriellem Ausgang. Damit kann man eine große Anzahl Eingänge sehr einfach und preiswert zu seinem Mikrocontroller hinzufügen.
Aufbau
Der Aufbau ist sehr ähnlich zum 74xx595. Allerdings gibt es kein Register zum Zwischenspeichern. Das ist auch gar nicht nötig, da der IC ja einen parallelen Eingang hat. Der muss nicht zwischengespeichert werden. Es gibt hier also wirklich nur das Schieberegister. Dieses wird über den Eingang PL mit den parallelen Daten geladen. Dann können die Daten seriell mit Takten an CLK aus dem Ausgang Q7 geschoben werden.
Funktionsweise
DS ist der serielle Dateneingang, welcher im Falle von kaskadierten Schieberegistern mit dem Ausgang des vorhergehenden ICs verbunden wird.
D0..D7 sind die parallelen Dateneingänge.
Mittels des Eingangs PL (Parallel Load) werden die Daten vom parallelen Eingang in das Schieberegister übernommen, wenn dieses Signal LOW ist. Hier muss man aber ein klein wenig aufpassen. Auf Grund der Schaltungsstruktur ist der Eingang PL mit dem Takt CLK verknüpft (obwohl es dafür keinen logischen Grund gibt :-0). Damit es nicht zu unerwünschten Fehlschaltungen kommt, muss der Takt CLK während des Ladens auf HIGH liegen. Wird PL wieder auf HIGH gesetzt, sind die Daten geladen. Das erste Bit liegt direkt am Ausgang Q7 an. Die restlichen Bits können nach und nach durch das Register geschoben werden.
Der Eingang CE (Clock Enable) steuert, ob das Schieberegister auf den Takt CLK reagieren soll oder nicht. Ist CE gleich HIGH werden alle Takte an CLK ignoriert. Bei LOW werden mit jeder positiven Flanke die Daten um eine Stufe weiter geschoben.
Wird am Eingang CLK eine LOW-HIGH Flanke angelegt und ist dabei CE auf LOW, dann werden die Daten im Schieberegister um eine Position weiter geschoben: DS->Q0, Q0->Q1, Q1->Q2, Q2->Q3, Q3->Q4, Q4->Q5, Q5->Q6, Q6->Q7. Q0..Q6 sind interne Signale, siehe Datenblatt.
Q7 ist der serielle Ausgang des Schieberegisters. Dort Werden Takt für Takt die Daten ausgegeben. Hier wird normalerweise der Eingang des Mikrocontrollers oder der Eingang des nächsten Schieberegisters angeschlossen.
Q7\ ist der invertierte Ausgang des Schieberegisters. Er wird meist nicht verwendet.
Schaltung
Um nun beispielsweise zwei Schieberegister zu kaskadieren um 16 Eingangspins zu erhalten sollte man folgende Verschaltung vornehmen. Beachten sollte man dabei, dass
- der serielle Eingang DS des ersten Schieberegisters (hier IC1) auf einen festen Pegel gelegt wird (LOW oder HIGH).
- der serielle Datenausgang bei der Benutzung des SPI-Moduls an MISO und nicht an MOSI angeschlossen wird.
Nachfolgend werden zwei Beispiele gezeigt, welche die Ansteuerung nach bekanntem Muster übernehmen. Nur dass hier eben Daten gelesen anstatt geschrieben werden. Zu beachten ist, dass hier ein anderer Modus der SPI-Ansteuerung verwendet werden muss, weil der Baustein das nötig macht. Das muss beachtet werden, wenn auch Schieberegister für Ausgänge verwendet werden. Dabei muss jeweils vor dem Zugriff auf die Ein- oder Ausgangsregister der Modus des Taktes (CPOL) umgeschaltet werden.
Ansteuerung per Software
<avrasm>
- Porterweiterung für Eingänge mit Schieberegister 74xx165
- Ansteuerung per Software
.include "m8def.inc"
.def temp1 = r16 .def temp2 = r17 .def temp3 = r18
- Pins anpassen, frei wählbar
.equ SCHIEBE_DDR = DDRB .equ SCHIEBE_PORT = PORTB .equ SCHIEBE_PIN = PINB .equ CLK = PB3 .equ PL = PB1 .equ DIN = PB2
- -----------------------------------------------------------------------------
- Datensegment im RAM
- -----------------------------------------------------------------------------
.dseg .org 0x60 Daten: .byte 2 ; Speicherplatz für Eingangsdaten
- -----------------------------------------------------------------------------
- Programmsegment im FLASH
- -----------------------------------------------------------------------------
.cseg
ldi temp1, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1
- CLK und PL als Ausgänge schalten
ldi temp1, (1<<clk) | (1<<pl) out SCHIEBE_DDR, temp1
sbi schiebe_port, clk ; Takt im Ruhezustand immer auf 1 ; komische Schaltung im 74xx165
- Zwei Bytes einlesen
ldi ZL,low(Daten) ldi ZH,high(Daten) ldi temp1,2 rcall schiebe_eingang
loop:
rjmp loop
- -----------------------------------------------------------------------------
- N Bytes seriell einlesen
- temp1
- N, Anzahl der Bytes
- Z
- Zeiger auf einen Datenbereich im SRAM
- -----------------------------------------------------------------------------
schiebe_eingang:
push temp2 ; Register sichern push temp3
cbi schiebe_port, pl ; Daten parallel laden sbi schiebe_port, pl
schiebe_eingang_byte_schleife:
ldi temp3, 8 ; Bitzähler
schiebe_eingang_bit_schleife:
lsl temp2 ; Daten weiterschieben
- das IO Bit Din in das niederwerigste Bit von temp2 kopieren
sbic schiebe_pin, din ; wenn Null, nächsten Befehl überspringen ori temp2,1 ; nein, Bit setzen
cbi SCHIEBE_PORT, CLK ; Taktausgang auf 0 sbi SCHIEBE_PORT, CLK ; und wieder zurück auf 1, dabei Daten schieben
dec temp3 ; Bitzähler um eins verringern brne schiebe_eingang_bit_schleife ;wenn noch keine 8 Bits ausgegeben, nochmal
st z+,temp2 ; Datenbyte speichern dec temp1 ; Anzahl Bytes um eins verringern brne schiebe_eingang_byte_schleife ; wenn noch mehr Bytes zu lesen sind
pop temp3 pop temp2 ret
</avrasm>
Ansteuerung per SPI-Modul
<avrasm>
- Porterweiterung für Eingänge mit Schieberegister 74xx165
- Ansteuerung per SPI-Modul
.include "m8def.inc"
.def temp1 = r16 .def temp2 = r17 .def temp3 = r18
- Pins anpassen
- diese müssen mit den SPI-Pins des AVR Typs übereinstimmen!
.equ SCHIEBE_DDR = DDRB .equ SCHIEBE_PORT = PORTB .equ PL = PB2 ; SS .equ CLK = PB5 ; SCK .equ DIN = PB4 ; MISO
- -----------------------------------------------------------------------------
- Datensegment im RAM
- -----------------------------------------------------------------------------
.dseg .org 0x60 Daten: .byte 2 ; Speicherplatz für Eingangsdaten
- -----------------------------------------------------------------------------
- Programmsegment im FLASH
- -----------------------------------------------------------------------------
.cseg
ldi temp1, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1
- CLK und PL als Ausgänge schalten
ldi temp1,(1<<CLK) | (1<<PL) out SCHIEBE_DDR,temp1
- SPI Modul konfigurieren
ldi temp1, (1<<SPE) | (1<<MSTR) | (1<<CPOL) out SPCR, temp1 ; keine Interrupts, MSB first, Master ; CPOL = 1, CPHA =0 ; SCK Takt = 1/2 XTAL ldi temp1, (1<<SPI2X) out SPSR,temp1 ; double speed aktivieren out SPDR,temp1 ; Dummy Daten, um SPIF zu setzen
- Zwei Bytes einlesen
ldi ZL,low(Daten) ldi ZH,high(Daten) ldi temp1,2 rcall schiebe_eingang
loop:
rjmp loop
- -----------------------------------------------------------------------------
- N Bytes seriell einlesen
- temp1
- N, Anzahl der Bytes
- Z
- Zeiger auf einen Datenbereich im SRAM
- -----------------------------------------------------------------------------
schiebe_eingang:
push temp2 ; Register sichern
; CLK ist im Ruhezustand schon auf HIGH, CPOL=1
dummyende:
sbis SPSR,7 ; prüfe ob Dummy Übertragung beendet ist, sonst rjmp dummyende ; kann es bei langsameren Übertragungsraten zu
; Überschneidungen kommen.
cbi schiebe_port, pl ; Daten parallel laden sbi schiebe_port, pl
schiebe_eingang_1:
sbis SPSR,7 ; prüfe ob eine alte Übertragung beendet ist rjmp schiebe_eingang_1
schiebe_eingang_byte_schleife:
out SPDR,temp1 ; beliebige Daten ins SPI Modul schreiben ; um die Übertragung zu starten
schiebe_eingang_2:
sbis SPSR,7 ; auf das Ende der Übertragung warten rjmp schiebe_eingang_2
in temp2, spdr ; Daten lesen st z+,temp2 ; Datenbyte speichern dec temp1 ; Anzahl Bytes um eins verringern brne schiebe_eingang_byte_schleife ; wenn noch mehr Bytes zu lesen sind
pop temp2 ret
</avrasm>
Bekannte Probleme
AVR Studio 4.12 (Build 498) hat Probleme bei der korrekten Simulation des SPI-Moduls.
- Der Double-Speed Modus funktioniert nicht.
- Das Bit SPIF im Register SPSR, welches laut Dokumentation nur lesbar ist, ist im Simulator auch schreibbar! Das kann zu Verwirrung und Fehlern in der Simulation führen.
Hardwareprobleme
- Wenn das SPI-Modul aktiviert wird, wird NICHT automatisch SPIF gesetzt, es bleibt auf Null. Damit würde die erste Abfrage in Schiebe_alles in einer Endlosschleife hängen bleiben. Deshalb muss nach der Initialisierung des SPI-Moduls ein Dummy Byte gesendet werden, damit am Ende der Übertragung SPIF gesetzt wird
- Da das SPI-Modul in Senderichtung nur einfach gepuffert ist, ist es nicht möglich absolut lückenlos Daten zu senden, auch wenn man mit nop eine feste minimale Zeit zwischen zwei Bytes warten würde. Zwischen zwei Bytes muss immer eine Pause von mind. 2 Systemtakten eingehalten werden.
Weblinks
- AVR151: Setup And Use of The SPI Atmel Application Note (PDF)
- datasheetcatalog.com: 74HC595
- Roboternetz: Portexpander am AVR
- Interactive 595 Shift Register Simulator
- 48 I/O Porterweiterung mit Schieberegister 74HC595 und 74HC165