AVR-Tutorial: Schieberegister: Unterschied zwischen den Versionen

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche
(Anpassung an vorherigen Abschnitt)
K (Syntaxhighlight (asm), R/G, Tippfehler, URL akt., Kleinigkeiten)
 
(5 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
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.
Ab und an stellt sich folgendes Problem: Man würde wesentlich mehr Ausgangs- 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 [[74xx]]<nowiki />595 bzw. der 74xx165 (wobei xx = HC(T), LS, …).


== Porterweiterung für Ausgänge ==
== Porterweiterung für Ausgänge ==


Um neue Ausgangspins zu gewinnen kann der [[74xx | 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''.
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.
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.
Zeile 9: Zeile 9:
Im Einzelnen bedeuten die Begriffe:
Im Einzelnen bedeuten die Begriffe:


<center>
{| {{Tabelle}}
{| {{Tabelle}}
|- style="background-color:#ffddcc"
|- style="background-color:#fdc"
! Begriff || Erklärung
! style="min-width:10em" | Begriff || Erklärung
|-
|-
||8-Bit
| 8-Bit
|align="left"| Acht Ausgangs[[Bit|bit]]s
| Acht Ausgangs[[bit]]s
|-
|-
||3-state<br>(lies: Tristejt)
| 3-state<br />(lies: TRI-stejt)
|align="left"| Die acht Registerausgänge können drei Zustände, Low, High und High-Impedanz annehmen.<BR>Siehe [[Ausgangsstufen Logik-ICs]]
| Die acht Registerausgänge können die drei Zustände Low, High und High-Impedanz annehmen.<br />Siehe [[Ausgangsstufen Logik-ICs]]
|-
|-
||Serial-in
| Serial-in
|align="left"| Serieller Eingang des Schieberegisters
| Serieller Eingang des Schieberegisters
|-
|-
||Serial-out
| Serial-out
|align="left"| Serieller Ausgang des Schieberegisters
| Serieller Ausgang des Schieberegisters
|-
|-
||Parallel-Out
| Parallel-Out
|align="left"| Parallele Ausgänge des Ausgangsregisters. Hier 3-state
| Parallele Ausgänge des Ausgangsregisters. Hier 3-state
|-
|-
||Schieberegister
| Schieberegister
|align="left"| Serielle Daten werden durch den Baustein durchgeschoben
| Serielle Daten werden durch den Baustein durchgeschoben
|-
|-
|Ausgangsregister
| Ausgangsregister
|align="left"| Ein Speicher, welcher die Daten des Schieberegisters zwischenspeichern kann.<BR>Dieses besteht aus acht [[FlipFlop]]s.
| Ein Speicher, welcher die Daten des Schieberegisters zwischenspeichern kann.<br />Dieser besteht aus acht [[FlipFlop]]s.
|-
|-
|Asynchroner Reset
| Asynchroner Reset
|align="left"| Die Daten im Schieberegister können asynchron zurückgesetzt werden.
| Die Daten im ''Schieberegister'' können asynchron auf 0 gesetzt werden. '''Achtung!''' Keine unmittelbare Wirkung auf das ''Ausgangsregister'', daher praktisch wertlos.
|-
|-
|asynchron (Eingang)
| asynchron (Eingang)
|align="left"| Der Eingang wirkt ohne zusätzliche Taktflanke.<br>Der Gegenentwurf „synchron“ meint, dass der Eingang nur bei Flanke am Takteingang zur Wirkung kommt.
| Der Eingang wirkt ohne zusätzliche Taktflanke.<br />Der Gegenentwurf „synchron“ meint, dass der Eingang nur bei Flanke am Takteingang zur Wirkung kommt.
|}
|}
</center>


=== Aufbau 74xx595 ===
=== Aufbau 74xx595 ===


[[Bild:74xx595-1.png|framed|center|Pinbelegung eines 595]]
[[Bild:74xx595-1.png|framed|center|Pinbelegung eines 74xx595]]


Hinweis: Die Benennung der Pins in den Datenblättern verschiedener Hersteller unterscheidet sich zum Teil. Die Funktionen der Pins sind jedoch gleich.  
Hinweis: Die Benennung der Pins in den Datenblättern verschiedener Hersteller unterscheidet sich zum Teil. Die Funktionen der Pins sind jedoch gleich.


Werden viele Ausgänge mit bis zu 15 Volt benötigt (typischerweise zum Durchsteuern von MOSFETs, die nicht „logik-kompatibel“ sind), eignet sich der CMOS-Typ CD4096B zum Ersatz des '595, mit abweichender Pinbelegung. Seine Verwendung erfordert nur drei Pegelkonverter, etwa ½ 4504, ¾ 40109 oder diskret aufgebaut. Die genannten ICs sind preiswert und leicht beschaffbar.
Werden viele Ausgänge mit bis zu 15&nbsp;Volt benötigt (typischerweise zum Durchsteuern von MOS[[FET]]s, die nicht „logik-kompatibel“ sind), eignet sich der CMOS-Typ [https://www.ti.com/lit/ds/symlink/cd4094b.pdf 4094] zum Ersatz des 74xx595, mit abweichender Pinbelegung. Seine Verwendung erfordert nur drei Pegelkonverter, etwa ½&nbsp;[https://www.ti.com/lit/ds/symlink/cd4504b.pdf 4504], ¾&nbsp;[https://www.ti.com/lit/ds/symlink/cd40109b.pdf 40109] oder diskret aufgebaut. Die genannten ICs sind preiswert und leicht beschaffbar.


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
Achtung: Es gibt auch noch einen IC von TI mit eingebauten Treibern 50&nbsp;V 150&nbsp;mA, den [https://www.ti.com/product/tpic6b595 TPIC6B595], der hat 20&nbsp;Pins und eine abweichende Pinbelegung.
Auch dieser IC ist leicht beschaffbar. Man kann diesen aus einem '595 und einem ULN2803 vorstellen bzw. zusammensetzen: Seine Ausgänge ziehen nur nach Low, nicht nach High. Für den Anschluss von Relais werden externe Freilaufdioden benötigt, die beim ULN2803 integriert sind.
Auch dieser IC ist leicht beschaffbar. Man kann sich diesen aus einem 74xx595 und einem [https://www.st.com/resource/en/datasheet/uln2804a.pdf ULN2803] zusammengesetzt vorstellen: Seine Ausgänge ziehen nur nach ''Low'', nicht nach ''High''. Für den Anschluss von Relais werden externe [[Relais mit Logik ansteuern#Freilaufdiode|Freilaufdioden]] benötigt, die beim ULN2803 integriert sind.


==== HC oder HCT? ====
=== HC oder HCT? ===


Mal gibt es 74'''HC'''595, mal 74'''HCT'''595.
Mal gibt es 74'''HC'''595, mal 74'''HCT'''595.
Diese beiden Typen unterscheiden sich nur dadurch, wie sie Eingangs-Signale erkennen:
Diese beiden Typen unterscheiden sich nur dadurch, wie sie Eingangs-Signale erkennen:
* HC: High-Signal muss mindestens ca. 75% der Betriebsspannung haben (siehe V<sub>IH</sub> im Datenblatt);
* HC: High-Signal muss mindestens ca. 75 % der Betriebsspannung haben (siehe V<sub>IH</sub> im Datenblatt);
* HC'''T''': TTL-kompatibel: High-Signal muss mindestens 2 V haben (Betriebsspannung ist immer 5 V).
* HC'''T''': TTL-kompatibel, High-Signal muss mindestens 2&nbsp;V haben (Betriebsspannung ist immer 5&nbsp;V).
Es gibt auch 74LS595. In der modernen CMOS-Welt sollte man sich Low-Power-Schottky (= bipolar = Ruhestrom fressend) nicht mehr antun.
Es gibt auch 74'''LS'''595. In der modernen CMOS-Welt sollte man sich aber Low-Power-Schottky (= bipolar = Ruhestrom fressend) nicht mehr antun.


Im allgemeinen kann man alle Typen gleichermaßen verwenden und nimmt einfach den billigsten oder verfügbarsten. Nur beim Übergang zu echtem TTL oder verschiedenen Speisespannungen für Mikrocontroller und Portexpander wird es interessant.
Im allgemeinen kann man alle Typen gleichermaßen verwenden und nimmt einfach den billigsten oder verfügbarsten. Nur beim Übergang zu echtem TTL oder verschiedenen Speisespannungen für Mikrocontroller und Portexpander wird es interessant.


Ein häufiges Szenario ist ein Mikrocontroller mit 3-V-Speisung (etwa ein ARM7 oder MSP430). Dann kann man mit einem 74'''HCT'''595, an 5 V betrieben, echte 5-V-Ausgänge und die Pegelkonvertierung dazu haben.
Ein häufiges Szenario ist ein Mikrocontroller mit 3-V-Speisung (etwa ein ARM7 oder MSP430). Dann kann man mit einem 74'''HCT'''595, an 5&nbsp;V betrieben, echte 5-V-Ausgänge und die Pegelkonvertierung dazu haben.
74'''HC'''595 funktionieren hier nur mit Glück, und bei noch geringerer Speisespannung des Controllers etwa 2,5 V gar nicht.
74'''HC'''595 funktionieren hier nur mit Glück, und bei noch geringerer Speisespannung des Controllers etwa 2,5&nbsp;V gar nicht.


=== Pinbelegung 74xx595 ===
=== Pinbelegung 74xx595 ===


<center>
{| {{Tabelle}}
{| {{Tabelle}}
|- style="background-color:#ffddcc"
|- style="background-color:#fdc"
! DIL Pin-Nummer || Funktion || Dieses Tutorial || Motorola / ON Semi || Philips / NXP         || Fairchild     || SGS|| Texas Instruments
! DIL-Pin-Nummer || Funktion                 || Dieses Tutorial     || Motorola / ON Semi || Philips / NXP   || Fairchild     || SGS           || Texas Instruments
|-
|-
| 1 || Ausgang B           || QB || Q<sub>B</sub> || Q<sub>1</sub>  || Q<sub>B</sub>  || QB|| Q<sub>B</sub>
|             1 || Ausgang B                 || QB                 || Q<sub>B</sub>     || Q<sub>1</sub>  || Q<sub>B</sub>  || QB             || Q<sub>B</sub>
|-
|-
| 2 || Ausgang C           || QC || Q<sub>C</sub> || Q<sub>2</sub>  || Q<sub>C</sub>  || QC|| Q<sub>C</sub>
|             2 || Ausgang C                 || QC                 || Q<sub>C</sub>     || Q<sub>2</sub>  || Q<sub>C</sub>  || QC             || Q<sub>C</sub>
|-
|-
| 3 || Ausgang D           || QD || Q<sub>D</sub> || Q<sub>3</sub>  || Q<sub>D</sub>  || QD|| Q<sub>D</sub>
|             3 || Ausgang D                 || QD                 || Q<sub>D</sub>     || Q<sub>3</sub>  || Q<sub>D</sub>  || QD             || Q<sub>D</sub>
|-
|-
| 4 || Ausgang E           || QE || Q<sub>E</sub> || Q<sub>4</sub>  || Q<sub>E</sub>  || QE|| Q<sub>E</sub>
|             4 || Ausgang E                 || QE                 || Q<sub>E</sub>     || Q<sub>4</sub>  || Q<sub>E</sub>  || QE             || Q<sub>E</sub>
|-
|-
| 5 || Ausgang F           || QF || Q<sub>F</sub> || Q<sub>5</sub>  || Q<sub>F</sub>  || QF|| Q<sub>F</sub>
|             5 || Ausgang F                 || QF                 || Q<sub>F</sub>     || Q<sub>5</sub>  || Q<sub>F</sub>  || QF             || Q<sub>F</sub>
|-
|-
| 6 || Ausgang G           || QG || Q<sub>G</sub> || Q<sub>6</sub>  || Q<sub>G</sub>  || QG|| Q<sub>G</sub>
|             6 || Ausgang G                 || QG                 || Q<sub>G</sub>     || Q<sub>6</sub>  || Q<sub>G</sub>  || QG             || Q<sub>G</sub>
|-
|-
| 7 || Ausgang H           || QH || Q<sub>H</sub> || Q<sub>7</sub>  || Q<sub>H</sub>  || QH|| Q<sub>H</sub>
|             7 || Ausgang H                 || QH                 || Q<sub>H</sub>     || Q<sub>7</sub>  || Q<sub>H</sub>  || QH             || Q<sub>H</sub>
|-
|-
| 8 || Masse, 0 V || [nicht dargestellt] || GND           || GND            || GND             || GND|| GND
|             8 || Masse, 0&nbsp;V           || (nicht dargestellt) || GND               || GND            || GND           || GND           || GND
|-
|-
| 9 || Serieller Ausgang || QH* || SQ<sub>H</sub> || Q<sub>7</sub>´  ||Q'<sub>H</sub> || QH´||Q<sub>H'</sub>
|             9 || Serieller Ausgang         || QH*                 || SQ<sub>H</sub>     || Q<sub>7</sub>´  || Q'<sub>H</sub> || QH´           || Q<sub>H'</sub>
|-
|-
| 10 || Reset für Schieberegister             || SCL || RESET         || /MR            || /SCLR       || /SCLR || /SRCLR
|             10 || Reset für Schieberegister || SCL                 || RESET             || /MR            || /SCLR         || /SCLR         || /SRCLR
|-
|-
| 11 || Schiebetakt       || SCK || SHIFT CLOCK   || SH<sub>CP</sub> || SCK         || SCK || SRCLK
|             11 || Schiebetakt               || SCK                 || SHIFT CLOCK       || SH<sub>CP</sub> || SCK           || SCK           || SRCLK
|-
|-
| 12 || Speichertakt       || RCK || LATCH CLOCK   || ST<sub>CP</sub> || RCK         || RCK || RCLK
|             12 || Speichertakt             || RCK                 || LATCH CLOCK       || ST<sub>CP</sub> || RCK           || RCK           || RCLK
|-
|-
| 13 || Ausgangssteuerung     || G || OUTPUT ENABLE || /OE            || /G           || /G || /OE
|             13 || Ausgangssteuerung         || G                   || OUTPUT ENABLE     || /OE            || /G             || /G             || /OE
|-
|-
| 14 || Serieller Dateneingang || SER || A             || D<sub>S</sub>  || SER         || SI || SER
|             14 || Serieller Dateneingang   || SER                 || A                 || D<sub>S</sub>  || SER           || SI             || SER
|-
|-
| 15 || Ausgang A           || QA || Q<sub>A</sub> || Q<sub>0</sub>  || Q<sub>A</sub>  || QA|| Q<sub>A</sub>
|             15 || Ausgang A                 || QA                 || Q<sub>A</sub>     || Q<sub>0</sub>  || Q<sub>A</sub>  || QA             || Q<sub>A</sub>
|-
|-
| 16 || Betriebsspannung || [nicht dargestellt] || V<sub>CC</sub> || V<sub>CC</sub>  || V<sub>CC</sub> || V<sub>CC</sub>|| V<sub>CC</sub>
|             16 || Betriebsspannung         || (nicht dargestellt) || V<sub>CC</sub>     || V<sub>CC</sub>  || V<sub>CC</sub> || V<sub>CC</sub> || V<sub>CC</sub>
|}
|}
</center>


Der Baustein besteht aus zwei Einheiten:
Der Baustein besteht aus zwei Einheiten:
* dem Schieberegister
* dem Schieberegister,
* dem Ausgangsregister
* dem Ausgangsregister.


Im Schieberegister werden die einzelnen Bits durchgeschoben. Mit jeder positiven Taktflanke(LOW -> HIGH) an '''SCK''' wird eine Schiebeoperation durchgeführt.
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.
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===
===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.
Am Eingang '''SER''' (Pin 14) wird das gewünschte nächste Datum (0 oder 1) angelegt. Durch einen positiven Puls an '''SCK''' (Pin&nbsp;11) wird der momentan an SER anliegende Wert als neuer Wert für Bit&nbsp;0, das unterste Bit des Schieberegisters, übernommen. Gleichzeitig werden alle anderen Bits im Schieberegister um eine Stelle verschoben: Das Bit&nbsp;6 wird ins Bit&nbsp;7 übernommen, Bit&nbsp;5 ins Bit&nbsp;6, Bit&nbsp;4 ins Bit&nbsp;5, etc., sodass das Bit&nbsp;0 zur Aufnahme des SER-Bits frei wird.


[[Bild:74xx595-2.png|center]]
[[Bild:74xx595-2.png|center]]


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.
Eine Sonderstellung nimmt das ursprüngliche Bit&nbsp;7 ein. Dieses Bit steht direkt auch am Ausgang '''QH*''' (Pin&nbsp;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.
Wurde das Schieberegister mit den Daten gefüllt, so wird mit einem Low-High-Puls an '''RCK''' (Pin&nbsp;12) der Inhalt des Schieberegisters in das Ausgangsregister übernommen.


[[Bild:74xx595-3.png|center]]
[[Bild:74xx595-3.png|center]]


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 [[Ausgangsstufen Logik-ICs |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.
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 [[Ausgangsstufen Logik-ICs#Tristate|High-Z]]: d.&nbsp;h. sie treiben aktiv weder Low noch 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.
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 Ansteuerung eines 74xxx595 Schieberegisters gestaltet sich sehr einfach. Im Grunde gibt es 2 Möglichkeiten:
Die Ansteuerung eines 74xxx595-Schieberegisters gestaltet sich sehr einfach. Im Grunde gibt es zwei Möglichkeiten:
* Mittels [[SPI]] kann der [[AVR]] das Schieberegister direkt und autark ansteuern. Das ist sehr schnell und verbraucht nur wenig CPU-Leistung
* 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.
* Sind die entsprechenden SPI-Pins am AVR nicht frei, so ist auch eine softwaremäßige Ansteuerung des Schieberegisters mit einfachen Mitteln durchführbar.


Zeile 139: Zeile 135:


[[Bild:Mega8-595-SPI.png|framed|right|Anschluss eines 595]]
[[Bild:Mega8-595-SPI.png|framed|right|Anschluss eines 595]]
Für eine komplette Softwarelösung kann das Schieberegister an jede beliebige Port-Pin Kombination angeschlossen werden. Wir wählen die Pins '''PB2''', '''PB3''' und '''PB5''' um dort die Schieberegisteranschlüsse '''RCK''', '''SER''' und '''SCK''' anzuschließen. Des Weiteren muss das Schieberegister mit Spannung versorgt werden: Pin 16 muss auf +5V und Pin 8 auf GND geschaltet werden.
Für eine komplette Softwarelösung kann das Schieberegister an jede beliebige Port-Pin-Kombination angeschlossen werden. Wir wählen die Pins '''PB2''', '''PB3''' und '''PB5''' um dort die Schieberegisteranschlüsse '''RCK''', '''SER''' und '''SCK''' anzuschließen. Des Weiteren muss das Schieberegister mit Spannung versorgt werden: Pin&nbsp;16 muss auf +5&nbsp;V und Pin&nbsp;8 auf GND geschaltet werden.


 
Die Programmierung gestaltet sich dann nach folgendem Schema: Die 8 Bits eines Bytes werden nacheinander an den Ausgang '''PB3''' ('''SER''') ausgegeben. Durch Generierung eines Pulses 0–1–0 an Pin '''PB5''' ('''SCK''') übernimmt das Schieberegister nacheinander die einzelnen Bits. Dabei ist zu beachten, dass die Ausgabe mit dem höchstwertigen Bit (MSB) 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 '''PB2''' ('''RCK''') der Inhalt der Schieberegisterbits 0 bis 7 in das Ausgaberegister für 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 z.&nbsp;B. mit LEDs (Low-current-LEDs + Vorwiderstände verwenden, [[#Acht LEDs mit je 20 mA pro Schieberegister|siehe unten]]) sichtbar gemacht werden.
Die Programmierung gestaltet sich dann nach folgendem Schema: Die 8 Bits eines Bytes werden nacheinander an den Ausgang '''PB3''' ('''SER''') ausgegeben. Durch Generierung eines Pulses 0-1-0 an Pin '''PB5''' ('''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 '''PB2''' ('''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 Schieberegister-Rücksetzeingang '''SCL''' wird auf U<sub>CC</sub> gelegt. Das Einschieben von 0x00 hat die gleiche Wirkung wie das Rücksetzen mit diesem Pin.
Der Schieberegister-Rücksetzeingang '''SCL''' wird auf U<sub>CC</sub> gelegt. Das Einschieben von 0x00 hat die gleiche Wirkung wie das Rücksetzen mit diesem Pin.


<syntaxhighlight lang="avrasm">  
<syntaxhighlight lang="asm">
.include "m8def.inc"
.include "m8def.inc"


Zeile 166: Zeile 161:
; Die Port Pins auf Ausgang konfigurieren
; Die Port Pins auf Ausgang konfigurieren
;
;
     ldi  temp1, (1<<RCK) | (1<<SCK) | (1<<SIN) ; Anm.1
     ldi  temp1, (1<<RCK) | (1<<SCK) | (1<<SIN) ; s. Anm. 1
     out  SCHIEBE_DDR, temp1
     out  SCHIEBE_DDR, temp1


Zeile 224: Zeile 219:
</syntaxhighlight>
</syntaxhighlight>


Anm.1: Siehe [[Bitmanipulation]]
Anm. 1: Siehe [[Bitmanipulation]]


=== Ansteuerung per SPI-Modul===
=== Ansteuerung per SPI-Modul===
[[Bild:Mega8-595-SPI.png|framed|right|Anschluss eines 595 per SPI]]
[[Bild:Mega8-595-SPI.png|framed|right|Anschluss eines 595 per SPI]]
Noch schneller geht die Ansteuerung des Schieberegisters mittels [[Serial_Peripheral_Interface | SPI]]-Modul, welches in fast allen AVRs vorhanden ist. Auch hier wird der Pin '''SCL''' nicht benutzt, da das praktisch keinen Sinn hat. Er wird fest auf VCC gelegt. Die Pins für '''SCK''' und '''SIN''' sind durch den jeweiligen AVR fest vorgegeben. '''SCK''' vom '595 wird mit '''SCK''' vom AVR verbunden sowie '''SIN''' mit '''MOSI''' ('''M'''aster '''O'''ut, '''S'''lave '''I'''n). '''MISO''' ('''M'''aster '''I'''n, '''S'''lave '''O'''ut) ist hier ungenutzt. Es kann NICHT für '''RCK''' verwendet werden, da es im SPI-Master Modus immer ein Eingang ist! Es kann aber als allgemeiner Eingang oder für 74HC165 ([[#Porterweiterung_für_Eingänge|siehe unten]]) verwendet werden.
Noch schneller geht die Ansteuerung des Schieberegisters mittels [[Serial Peripheral Interface|SPI]]-Modul, welches in fast allen AVRs vorhanden ist. Auch hier wird der Pin '''SCL''' nicht benutzt, da das praktisch keinen Sinn hat. Er wird fest auf VCC gelegt. Die Pins für '''SCK''' und '''SIN''' sind durch den jeweiligen AVR fest vorgegeben. SCK vom 74xx595 wird mit SCK vom AVR verbunden sowie SIN mit '''MOSI''' (<u>M</u>aster <u>O</u>ut, <u>S</u>lave <u>I</u>n). '''MISO''' (<u>M</u>aster <u>I</u>n, <u>S</u>lave <u>O</u>ut) ist hier ungenutzt. Es kann ''nicht'' für '''RCK''' verwendet werden, da es im SPI-Master-Modus immer ein Eingang ist! Es kann aber als allgemeiner Eingang oder für 74HC165 ([[#Porterweiterung für Eingänge|siehe unten]]) 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 10 kΩ 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.)
Der AVR-Pin '''SS''' wird sinnvollerweise als '''RCK''' benutzt, da er sowieso als Ausgang geschaltet werden ''muss'', sonst gibt es böse Überraschungen (siehe Datenblatt ''SS Pin Functionality''“).


Bei den kleineren ATtinys mit '''USI''' (Universal Serial Interface) darf man sich von den Pin-Bezeichnungen MOSI und MISO nicht [http://de.wikipedia.org/wiki/Bockshorn_(Redensart) ins Bockshorn jagen] lassen: Hier ist MISO der Ausgang(!) '''DO''' und MOSI der Eingang(!) '''DI'''. Die Pinbezeichnungen MOSI und MISO sind nur zum Programmieren und irreführend, weil ohnehin nur für den Slave-Betrieb.
Bei den kleineren ATtinys mit '''USI''' (Universal Serial Interface) darf man sich von den Pin-Bezeichnungen MOSI und MISO nicht [https://de.wikipedia.org/wiki/Bockshorn_(Redensart) ins Bockshorn jagen] lassen: Hier ist MISO der Ausgang (!) '''DO''' und MOSI der Eingang (!) '''DI'''. Die Pinbezeichnungen MOSI und MISO sind nur zum Programmieren und irreführend, weil ohnehin nur für den Slave-Betrieb.


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 800 ns!
Je nach Bedarf kann man die Taktrate des SPI-Moduls zwischen 1/2 und 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&nbsp;MHz getaktet werden, d.&nbsp;h. es sind maximal 10&nbsp;MHz SPI-Takt möglich. Das ist für ein 74xx595 kein Problem. Die Übertragung von 8&nbsp;Bit dauert dann gerade mal 800&nbsp;ns!


<syntaxhighlight lang="avrasm">  
<syntaxhighlight lang="asm">
.include "m8def.inc"
.include "m8def.inc"


Zeile 260: Zeile 255:
     out  SCHIEBE_DDR,temp1     
     out  SCHIEBE_DDR,temp1     
;
;
; SPI Modul konfigurieren
; SPI-Modul konfigurieren
;
;
     ldi  temp1, (1<<SPE) | (1<<MSTR)
     ldi  temp1, (1<<SPE) | (1<<MSTR)
Zeile 268: Zeile 263:
     ldi  temp1, (1<<SPI2X)
     ldi  temp1, (1<<SPI2X)
     out  SPSR, temp1          ; double speed aktivieren
     out  SPSR, temp1          ; double speed aktivieren
     out  SPDR, temp1          ; Dummy Daten, um SPIF zu setzen
     out  SPDR, temp1          ; Dummy-Daten, um SPIF zu setzen
;
;
; Ein Datenbyte ausgeben
; Ein Datenbyte ausgeben
Zeile 283: Zeile 278:
; Die Daten im Schieberegister in das Ausgaberegister übernehmen
; Die Daten im Schieberegister in das Ausgaberegister übernehmen
;
;
; Dazu am RCK Eingang am Schieberegister einen 0-1-0 Puls erzeugen
; Dazu am RCK-Eingang am Schieberegister einen 0-1-0-Puls erzeugen
;
;
SchiebeOut:
SchiebeOut:
     sbis  SPSR, SPIF            ; prüfe ob eine alte Übertragung beendet ist
     sbis  SPSR, SPIF            ; prüfe, ob eine alte Übertragung beendet ist
     rjmp  SchiebeOut
     rjmp  SchiebeOut
     sbi  SCHIEBE_PORT, RCK
     sbi  SCHIEBE_PORT, RCK
Zeile 297: Zeile 292:
;
;
Schiebe:
Schiebe:
     sbis    SPSR, SPIF      ; prüfe ob eine alte Übertragung beendet ist
     sbis    SPSR, SPIF      ; prüfe, ob eine alte Übertragung beendet ist
     rjmp    Schiebe
     rjmp    Schiebe
     out    SPDR, temp1    ; Daten ins SPI Modul schreiben, Übertragung beginnt automatisch
     out    SPDR, temp1    ; Daten ins SPI-Modul schreiben, Übertragung beginnt automatisch
     ret
     ret
</syntaxhighlight>
</syntaxhighlight>
Zeile 306: Zeile 301:


[[Bild:Mega8-595-2.gif|framed|right|Kaskadieren mehrerer 595]]
[[Bild:Mega8-595-2.gif|framed|right|Kaskadieren mehrerer 595]]
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.
Um ein Schieberegister anzuschließen genügen also im einfachsten Fall 3 freie Prozessorpins (4, wenn '''SCL''' oder besser <strong style="text-decoration:overline">OE</strong> 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.
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 ggf. '''SCL''' bzw. <strong style='text-decoration:overline'>OE</strong> werden parallel zu den bereits vorhandenen geschaltet. Konzeptionell erhält man dadurch ein Schieberegister mit einer Breite von 16&nbsp;Bit. Werden weitere 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 <code>Schiebe</code> aufrufen, um alle Daten auszugeben. Am Ende werden dann mit <code>SchiebeOut</code> 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.
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 ('''C'''hip '''S'''elect) 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.
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 (<u>C</u>hip <u>S</u>elect). Dieser Pin ist meist ''low-aktiv'', d.&nbsp;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.


<syntaxhighlight lang="avrasm">  
<syntaxhighlight lang="asm">
.include "m8def.inc"
.include "m8def.inc"
.def temp1 = r16
.def temp1 = r16


; Die Definitionen müssen an den jeweiligen AVR angepasst werden
; Die Definitionen müssen an den jeweiligen AVR angepasst werden.
; Hinweis: Dieser Code passt nicht zum nebenstehenden Bild!


.equ SCHIEBE_DDR  = DDRB
.equ SCHIEBE_DDR  = DDRB
Zeile 332: Zeile 328:


.dseg
.dseg
.org $60
.org $60 ; bei modernen AVRs mit vergrößertem I/O-Adressraum $100
Schiebedaten:      .byte 2
Schiebedaten:      .byte 2


;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
;
; Programmsegment im FLASH
; Programmsegment im Flash-ROM
;
;
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
Zeile 343: Zeile 339:
.cseg
.cseg
     ldi    temp1, LOW(RAMEND)    ; Stackpointer initialisieren
     ldi    temp1, LOW(RAMEND)    ; Stackpointer initialisieren
     out    SPL, temp1
     out    SPL, temp1             ; (obsolet bei modernen AVRs)
     ldi    temp1, HIGH(RAMEND)
     ldi    temp1, HIGH(RAMEND)
     out    SPH, temp1
     out    SPH, temp1
Zeile 349: Zeile 345:
; SCK, MOSI, SS als Ausgänge schalten
; SCK, MOSI, SS als Ausgänge schalten
;
;
     in      temp1,SCHIEBE_DDR
     in      temp1, SCHIEBE_DDR
     ori    temp1,(1<<SIN) | (1<<SCK) | (1<<RCK)  
     ori    temp1, (1<<SIN) | (1<<SCK) | (1<<RCK)  
     out    SCHIEBE_DDR,temp1
     out    SCHIEBE_DDR, temp1


     sbi    SCHIEBE_PORT, RCK  ; Slave select inaktiv
     sbi    SCHIEBE_PORT, RCK  ; Slave select inaktiv
;
;
; SPI Modul konfigurieren
; SPI-Modul konfigurieren
;
;
     ldi    temp1, 0b01010000
     ldi    temp1, 0b01010000
Zeile 361: Zeile 357:
                                 ; CPOL = 0, CPHA =0
                                 ; CPOL = 0, CPHA =0
                                 ; SCK Takt = 1/2 XTAL
                                 ; SCK Takt = 1/2 XTAL
     ldi    r16,1
     ldi    r16, 1
     out    SPSR,r16           ; Double Speed
     out    SPSR, r16           ; Double Speed
     out    SPDR,temp1         ; Dummy Daten, um SPIF zu setzen
     out    SPDR, temp1         ; Dummy Daten, um SPIF zu setzen


; den Datenblock mit Daten füllen
; den Datenblock mit Daten füllen


     ldi    temp1,$F0
     ldi    temp1, $F0
     sts    Schiebedaten,temp1
     sts    Schiebedaten, temp1
     ldi    temp1,$55
     ldi    temp1, $55
     sts    Schiebedaten+1,temp1
     sts    Schiebedaten+1, temp1


loop:
loop:
; den Datenblock ausgeben
; den Datenblock (2 Byte) ausgeben


     ldi    r16,2
     ldi    r16, 2
     ldi    zl,low(Schiebedaten)
     ldi    zl, low(Schiebedaten)
     ldi    zh, high(Schiebedaten)
     ldi    zh, high(Schiebedaten)
     rcall  Schiebe_alle                    ; Daten ausgeben
     rcall  Schiebe_alle                    ; Daten ausgeben
Zeile 392: Zeile 388:
Schiebe_alle:
Schiebe_alle:
     cbi    SCHIEBE_PORT, RCK  ; RCK LOW, SPI Standardverfahren
     cbi    SCHIEBE_PORT, RCK  ; RCK LOW, SPI Standardverfahren
    push    r17


Schiebe_alle_2:
Schiebe_alle_2:
     ld      r17,Z+
     ld      r0, Z+
Schiebe_alle_3:
Schiebe_alle_3:
     sbis    SPSR,SPIF           ; prüfe ob eine alte Übertragung beendet ist
     sbis    SPSR, SPIF         ; prüfe, ob eine alte Übertragung beendet ist
    rjmp   Schiebe_alle_3
    rjmp   Schiebe_alle_3
     out    SPDR,r17           ; Daten ins SPI Modul schreiben, Übertragung beginnt automatisch
     out    SPDR, r0           ; Daten ins SPI-Modul schreiben, Übertragung beginnt automatisch
     dec    r16
     dec    r16
     brne    Schiebe_alle_2
     brne    Schiebe_alle_2


Schiebe_alle_4:
Schiebe_alle_4:
     sbis    SPSR,SPIF           ; prüfe ob die letzte Übertragung beendet ist
     sbis    SPSR, SPIF         ; prüfe, ob die letzte Übertragung beendet ist
    rjmp   Schiebe_alle_4
    rjmp   Schiebe_alle_4


    pop    r17
     sbi    SCHIEBE_PORT, RCK  ; RCK inaktiv, Datenübernahme
     sbi    SCHIEBE_PORT, RCK  ; RCK inaktiv, Datenübernahme
     ret
     ret
</syntaxhighlight>
</syntaxhighlight>


Der Nachteil von Schieberegistern ist allerdings, dass sich die Zeit zum Setzen 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 ''Latches'' [https://www.ti.com/product/CD74HC573 74xxx573] eine Alternative sein, um jeweils ein vollständiges Byte auszugeben. Natürlich kann der 74xxx573 (oder ein ähnliches Latch) auch mit dem 74xxx595 zusammen eingesetzt werden, beispielsweise indem über das Schieberegister verschiedene 74xxx595 nacheinander aktiviert werden. Weitere Tips und Tricks dazu gibt es vielleicht in einem weiteren Tutorial …


Der Nachteil von Schieberegistern ist allerdings, dass sich die Zeit zum Setzen 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 20 mA pro Schieberegister ===
 
=== Acht LEDs mit je 20mA pro Schieberegister ===


Will man nun acht [[LED]]s 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.
Will man nun acht [[LED]]s 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 70&nbsp;mA über VCC liefern bzw. über 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
* Den Strom pro LED auf höchstens 70&nbsp;mA&nbsp;/&nbsp;8 = 8,75&nbsp;mA begrenzen; das ist bei modernen LEDs schon mehr als genug, um sie schön hell leuchten zu lassen bei ''low-current'' (für 2&nbsp;mA ausgelegt!) und ultrahellen LEDs sowieso.
* Wenn doch 20 mA pro LED gebraucht werden, kann man die folgende Trickschaltung anwenden.
* Wenn doch 20&nbsp;mA pro LED gebraucht werden, kann man die folgende Trickschaltung anwenden.


[[bild:8x20mA_LED_mit_74xx595.png|framed|center|Mehrere LED anschließen]]
[[Bild:8x20mA_LED_mit_74xx595.png|framed|center|Mehrere LED anschließen]]


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.
Der Trick besteht darin, dass 4 LEDs ihren Strom über das Schieberegister von VCC beziehen (high-aktiv), während der Strom der anderen vier über GND abgeleitet wird (low-aktiv). Damit bleiben ganz offiziell für jede LED 70&nbsp;mA&nbsp;/&nbsp;4 = 17,5&nbsp;mA. 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.


<B>Achtung!</B> Die Widerstände sind auf blaue LEDs mit 3,3V Flussspannung ausgelegt. Bei roten, gelben und grünen [[LED]]s ist die Flussspannung geringer und dementsprechend muss der Vorwiderstand größer sein.
'''Achtung!''' Die Widerstände sind auf blaue LEDs mit 3,3&nbsp;V 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.
Wenn 20&nbsp;mA immer noch nicht reichen sollten oder z.&nbsp;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 250&nbsp;mA pro Kanal zur Verfügung stehen.


=== Achtung beim Startup! ===
=== Achtung beim Startup! ===


Die Ausgänge des '595 führen beim Einschalten undefinierte, also zufällige Pegel! Und der Eingang <span style="text-decoration:overline">SCL</span> löscht nur die Schieberegister-Flipflops (= unnütz, um mit <span style="text-decoration:overline">RESET</span> zu verbinden: Festlegung an U<sub>CC</sub> genügt vollauf). Sind deshalb ''definierte'' Pegel beim Einschalten unerlässlich, ''muss'' man <span style="text-decoration:overline">OE</span> beschalten:
Die Ausgänge des 74xx595 führen beim Einschalten undefinierte, also zufällige Pegel! Und der Eingang <span style="text-decoration:overline">SCL</span> löscht nur die Schieberegister-Flipflops (=&nbsp;unnütz, um mit <span style="text-decoration:overline">RESET</span> zu verbinden: Festlegung an U<sub>CC</sub> genügt vollauf). Sind deshalb ''definierte'' Pegel beim Einschalten unerlässlich, ''muss'' man <span style="text-decoration:overline">OE</span> beschalten:
* Entweder mit einem weiteren Mikrocontroller-Ausgang (der mit einem externen Pull-Up-Widerstand zu beschalten ist und nach dem ersten Durchschieben dauerhaft auf LOW gelegt wird)
* Entweder mit einem weiteren Mikrocontroller-Ausgang (der mit einem externen Pull-Up-Widerstand zu beschalten ist und nach dem ersten Durchschieben dauerhaft auf ''low'' gelegt wird)
* Oder mit einer RC(D)-Kombination, die die Ausgänge für eine gewisse Zeit auf Tristate hält. Spart einen Mikrocontroller-Pin.
* Oder mit einer RC(D)-Kombination, die die Ausgänge für eine gewisse Zeit auf ''High-Z'' hält. Spart einen Mikrocontroller-Pin.
Obendrein sind, wie auch beim direkten Anschluss am Mikrocontroller, die betreffenden Ausgänge des '595 mit externen Pull-Up- oder Pull-Down-Widerständen zu beschalten.
Obendrein sind, wie auch beim direkten Anschluss am Mikrocontroller, die betreffenden Ausgänge des 74xx595 mit externen Pull-Up- oder Pull-Down-Widerständen zu beschalten.


Man könnte meinen, dass der Anschluss <span style="text-decoration:overline">SCL</span> einfach ein böser Fallstrick ist, denn viel sinnvoller wäre eine Reset-Funktion für die Ausgangs-Flipflops. Schade dass es keinen Schaltkreis gibt, der das richtig implementiert; '''mikrocontroller.net''' würde einen solchen sofort empfehlen.
Man könnte meinen, dass der Anschluss <span style="text-decoration:overline">SCL</span> einfach ein böser Fallstrick ist, denn viel sinnvoller wäre eine Reset-Funktion für die Ausgangs-Flipflops. Schade, dass es keinen Schaltkreis gibt, der das richtig implementiert; ''mikrocontroller.net'' würde einen solchen sofort empfehlen.


== 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 große Anzahl Eingänge sehr einfach und preiswert zu seinem Mikrocontroller hinzufügen.
Ein naher Verwandter des [[74xx]]<nowiki />595 ist der [https://www.ti.com/product/CD74HC165 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 ===


[[bild:74xx165-1.png|framed|center|Pinbelegung eines 165]]
[[Bild:74xx165-1.png|framed|center|Pinbelegung eines 165]]


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.
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.
Zeile 453: Zeile 446:
DS ist der serielle Dateneingang, welcher im Falle von kaskadierten Schieberegistern mit dem Ausgang des vorhergehenden ICs verbunden wird.
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.
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 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.
Mittels des Eingangs PL (<u>P</u>arallel <u>L</u>oad) werden die Daten vom parallelen Eingang in das Schieberegister übernommen, wenn dieses Signal ''low'' ist. 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 (<u>C</u>lock <u>E</u>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.


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 [http://www.nxp.com/acrobat/datasheets/74HC_HCT165_CNV_2.pdf Datenblatt].
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 [https://www.ti.com/lit/gpn/cd74hc165 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 serielle Ausgang des Schieberegisters. Dort werden Takt für Takt die Daten ausgegeben. Hier wird normalerweise der Eingang des Mikrocontrollers oder der DS-Eingang des nächsten Schieberegisters angeschlossen.


Q7\ ist der invertierte Ausgang des Schieberegisters. Er wird meist nicht verwendet.
<span style="text-decoration:overline">Q7</span> ist der invertierte Ausgang des Schieberegisters. Er wird meist nicht verwendet.


=== Schaltung ===
=== Schaltung ===


Um nun beispielsweise zwei Schieberegister zu kaskadieren um 16 Eingangspins zu erhalten sollte man folgende Verschaltung vornehmen. Beachten sollte man dabei, dass
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 Eingang DS des ersten Schieberegisters (hier IC1) auf einen festen Pegel gelegt wird (GND oder VCC),
* der serielle Datenausgang bei der Benutzung des SPI-Moduls an MISO und nicht an MOSI angeschlossen wird.
* der serielle Datenausgang bei der Benutzung des SPI-Moduls an MISO und nicht an MOSI angeschlossen wird.


Zeile 478: Zeile 471:
=== Ansteuerung per Software ===
=== Ansteuerung per Software ===


<syntaxhighlight lang="avrasm">  
<syntaxhighlight lang="asm">
; Porterweiterung für Eingänge mit Schieberegister 74xx165
; Porterweiterung für Eingänge mit Schieberegister 74xx165
; Ansteuerung per Software
; Ansteuerung per Software
Zeile 509: Zeile 502:
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
;
; Programmsegment im FLASH
; Programmsegment im Flash-ROM
;
;
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
Zeile 528: Zeile 521:
; Zwei Bytes einlesen
; Zwei Bytes einlesen


     ldi    ZL,low(Daten)
     ldi    ZL, low(Daten)
     ldi    ZH,high(Daten)
     ldi    ZH, high(Daten)
     ldi    temp1,2
     ldi    temp1, 2
     rcall  schiebe_eingang
     rcall  schiebe_eingang


Zeile 557: Zeile 550:
     lsl    temp2              ; Daten weiterschieben
     lsl    temp2              ; Daten weiterschieben


; das IO Bit Din in das niederwerigste Bit von temp2 kopieren
; das IO-Bit Din in das niederwertigste Bit von temp2 kopieren


     sbic    schiebe_pin, din    ; wenn Null, nächsten Befehl überspringen
     sbic    schiebe_pin, din    ; wenn Null, nächsten Befehl überspringen
     ori    temp2,1             ; nein, Bit setzen
     ori    temp2, 1           ; nein, Bit setzen


     cbi    SCHIEBE_PORT, CLK  ; Taktausgang auf 0
     cbi    SCHIEBE_PORT, CLK  ; Taktausgang auf 0
Zeile 568: Zeile 561:
     brne    schiebe_eingang_bit_schleife ;wenn noch keine 8 Bits ausgegeben, nochmal
     brne    schiebe_eingang_bit_schleife ;wenn noch keine 8 Bits ausgegeben, nochmal


     st      z+,temp2           ; Datenbyte speichern
     st      z+, temp2           ; Datenbyte speichern
     dec    temp1              ; Anzahl Bytes um eins verringern
     dec    temp1              ; Anzahl Bytes um eins verringern
     brne    schiebe_eingang_byte_schleife  ; wenn noch mehr Bytes zu lesen sind
     brne    schiebe_eingang_byte_schleife  ; wenn noch mehr Bytes zu lesen sind
Zeile 579: Zeile 572:
=== Ansteuerung per SPI-Modul ===
=== Ansteuerung per SPI-Modul ===


<syntaxhighlight lang="avrasm">  
<syntaxhighlight lang="asm">
; Porterweiterung für Eingänge mit Schieberegister 74xx165
; Porterweiterung für Eingänge mit Schieberegister 74xx165
; Ansteuerung per SPI-Modul
; Ansteuerung per SPI-Modul
Zeile 589: Zeile 582:
.def temp3 = r18
.def temp3 = r18


; Pins anpassen
; Pins anpassen,
; diese müssen mit den SPI-Pins des AVR Typs übereinstimmen!
; diese müssen mit den SPI-Pins des AVR-Typs übereinstimmen!


.equ SCHIEBE_DDR  = DDRB
.equ SCHIEBE_DDR  = DDRB
Zeile 621: Zeile 614:
; CLK und PL als Ausgänge schalten
; CLK und PL als Ausgänge schalten


     ldi    temp1,(1<<CLK) | (1<<PL)
     ldi    temp1, (1<<CLK) | (1<<PL)
     out    SCHIEBE_DDR,temp1    
     out    SCHIEBE_DDR, temp1
;
;
; SPI Modul konfigurieren
; SPI-Modul konfigurieren
;
;
     ldi    temp1, (1<<SPE) | (1<<MSTR) | (1<<CPOL)
     ldi    temp1, (1<<SPE) | (1<<MSTR) | (1<<CPOL)
     out    SPCR, temp1        ; keine Interrupts, MSB first, Master
     out    SPCR, temp1        ; keine Interrupts, MSB first, Master
                                 ; CPOL = 1, CPHA =0
                                 ; CPOL = 1, CPHA =0
                                 ; SCK Takt = 1/2 XTAL
                                 ; SCK-Takt = 1/2 XTAL
     ldi    temp1, (1<<SPI2X)
     ldi    temp1, (1<<SPI2X)
     out    SPSR,temp1         ; double speed aktivieren
     out    SPSR, temp1         ; double speed aktivieren
     out    SPDR,temp1         ; Dummy Daten, um SPIF zu setzen
     out    SPDR, temp1         ; Dummy-Daten, um SPIF zu setzen


; Zwei Bytes einlesen
; Zwei Bytes einlesen


     ldi    ZL,low(Daten)
     ldi    ZL, low(Daten)
     ldi    ZH,high(Daten)
     ldi    ZH, high(Daten)
     ldi    temp1,2
     ldi    temp1, 2
     rcall  schiebe_eingang
     rcall  schiebe_eingang


Zeile 657: Zeile 650:


dummyende:
dummyende:
     sbis    SPSR,7             ; prüfe ob Dummy Übertragung beendet ist, sonst
     sbis    SPSR, 7             ; Prüfe, ob Dummy-Übertragung beendet ist, sonst
     rjmp    dummyende          ; kann es bei langsameren Übertragungsraten zu
     rjmp    dummyende          ; kann es bei langsameren Übertragungsraten zu
                        ; Überschneidungen kommen.
                                ; Überschneidungen kommen.
 


     cbi    schiebe_port, pl    ; Daten parallel laden
     cbi    schiebe_port, pl    ; Daten parallel laden
Zeile 666: Zeile 658:


schiebe_eingang_1:
schiebe_eingang_1:
     sbis    SPSR,7             ; prüfe ob eine alte Übertragung beendet ist
     sbis    SPSR, 7             ; Prüfe, ob eine alte Übertragung beendet ist
     rjmp    schiebe_eingang_1
     rjmp    schiebe_eingang_1


schiebe_eingang_byte_schleife:
schiebe_eingang_byte_schleife:
     out    SPDR,temp1         ; beliebige Daten ins SPI Modul schreiben
     out    SPDR, temp1         ; beliebige Daten ins SPI Modul schreiben
                                 ; um die Übertragung zu starten
                                 ; um die Übertragung zu starten
schiebe_eingang_2:
schiebe_eingang_2:
     sbis    SPSR,7             ; auf das Ende der Übertragung warten
     sbis    SPSR, 7             ; auf das Ende der Übertragung warten
     rjmp    schiebe_eingang_2
     rjmp    schiebe_eingang_2


     in      temp2, spdr        ; Daten lesen
     in      temp2, spdr        ; Daten lesen
     st      z+,temp2           ; Datenbyte speichern
     st      z+, temp2           ; Datenbyte speichern
     dec    temp1              ; Anzahl Bytes um eins verringern
     dec    temp1              ; Anzahl Bytes um eins verringern
     brne    schiebe_eingang_byte_schleife  ; wenn noch mehr Bytes zu lesen sind
     brne    schiebe_eingang_byte_schleife  ; wenn noch mehr Bytes zu lesen sind
Zeile 687: Zeile 679:
== Beides in ''einer'' Kette ==
== Beides in ''einer'' Kette ==


Kann man die '595 und die '165 an ''einem'' SPI-Anschluss betreiben?
=== Kann man die 74xx595 und die 74xx165 an ''einem'' SPI-Anschluss betreiben? ===


Ja, einfach verketten. Das geht auch „durcheinander“. Dafür gibt es zwei Möglichkeiten:
Ja, einfach verketten. Das geht auch „durcheinander“. Dafür gibt es zwei Möglichkeiten:


* Man verwendet ''getrennte'' Anschlüsse am Mikrocontroller für die Parallelübernahme der '595 (Ausgänge) und '165 (Eingänge). Dann sollten die Ausgänge am Ketten-Anfang (MOSI) und die Eingänge am Ketten-Ende (MISO) liegen. Beispielsweise werden für 3 Stück '595 und 2 Stück '165 24 Schiebetakte zum Ausgeben (mit anschließendem ↑RCLK) und 16 Schiebetakte (mit vorausgehendem ¬PL) zum Einlesen benötigt.
* Man verwendet ''getrennte'' Anschlüsse am Mikrocontroller für die Parallelübernahme der 74xx595 (Ausgänge) und 74xx165 (Eingänge). Dann sollten die Ausgänge am Ketten-Anfang (MOSI) und die Eingänge am Ketten-Ende (MISO) liegen. Beispielsweise werden für 3&nbsp;Stück 74xx595 und 2&nbsp;Stück 74xx165 24 Schiebetakte zum Ausgeben (mit anschließendem ↑RCLK) und 16 Schiebetakte (mit vorausgehendem ¬PL) zum Einlesen benötigt.
 
* Man verwendet einen ''gemeinsamen'' Anschluss '''¬L''' für ↑RCLK und ¬PL, ein Pin sparend. Die o.&nbsp;g. Reihenfolge der 74xx595 und 74xx165 ist weiterhin vorteilhaft. Nach dem o.&nbsp;g. Beispiel gilt folgendes Regime zum Ausgeben und Einlesen in einem Rutsch:
* Man verwendet einen ''gemeinsamen'' Anschluss '''¬L''' für ↑RCLK und ¬PL, ein Pin sparend. Die o.g. Reihenfolge der '595 und '165 ist weiterhin vorteilhaft. Nach dem o.g. Beispiel gilt folgendes Regime zum Ausgeben und Einlesen in einem Rutsch:
** Low-Nadel an ¬L (zum Laden der '165-Flipflops; die '595-Ausgänge verändern sich nicht)
** Low-Nadel an ¬L (zum Laden der '165-Flipflops; die '595-Ausgänge verändern sich nicht)
** 8 x 3 = 24 Schiebetakte (auch zum Nur-Einlesen müssen die Ausgabedaten wiederholt ausgegeben werden)
** 8 · 3 = 24 Schiebetakte (auch zum Nur-Einlesen müssen die Ausgabedaten wiederholt ausgegeben werden)
** Low-Nadel an ¬L (zum Aktualisieren der '595-Ausgänge; das erneute Einlesen in den '165 ist ohne Belang)
** Low-Nadel an ¬L (zum Aktualisieren der '595-Ausgänge; das erneute Einlesen in den '165 ist ohne Belang)


Kann man per Software messen, wie lang die Kette ist?
=== Kann man per Software messen, wie lang die Kette ist? ===


Für bestimmte PnP-artige Lösungen ist es zweckmäßig, die Länge der Kette zu kennen:
Für bestimmte PnP-artige Lösungen ist es zweckmäßig, die Länge der Kette zu kennen:
Man schiebt einfach eine einzelne 1 (oder eine einzelne 0) durch die Kette, ohne Parallelübernahmen. Vorher muss man die Kette in ihrer zu erwartenden Maximallänge initialisieren. Benutzt man byteweise arbeitende Hardware-SPI, wird man auf ganze Byte-Längen vertrauen und kann für mehr Sicherheit ein bestimmtes Kennbyte durchschicken.
Man schiebt einfach eine einzelne 1 (oder eine einzelne 0) durch die Kette, ohne Parallelübernahmen. Vorher muss man die Kette in ihrer zu erwartenden Maximallänge initialisieren. Benutzt man byteweise arbeitende Hardware-SPI, wird man auf ganze Byte-Längen vertrauen und kann für mehr Sicherheit ein bestimmtes Kennbyte durchschicken.


Kann man per Software messen, ''wo'' die '595 und die '165 liegen?
=== Kann man per Software messen, ''wo'' die '595 und die '165 liegen? ===


Nur wenn man davon ausgeht, dass sich die Eingänge nicht allzu schnell ändern. Das ist bei Tastern klar der Fall. Eine 100-prozentige Sicherheit gibt es nicht. Man schiebt ein bestimmtes Bitmuster (Byte) durch und nimmt '595 dort an, wo das Bitmuster auch zurückkommt. Man verwende mindestens 2 verschiedene Bitmuster, um eine derartige Eingangskombination auszuschließen. Wer ziemlich sicher gehen will, schiebt in einer Schleife alle 256 verschiedenen Kombinationen durch. Wenn (bei gemeinsamen ¬L) die Ausgänge unzulässig zappeln, muss man ¬OE beschalten, oder genau jene Bitkombinationen vermeiden.
Nur wenn man davon ausgeht, dass sich die Eingänge nicht allzu schnell ändern. Das ist bei Tastern klar der Fall. Eine 100-prozentige Sicherheit gibt es nicht. Man schiebt ein bestimmtes Bitmuster (Byte) durch und nimmt '595 dort an, wo das Bitmuster auch zurückkommt. Man verwende mindestens 2 verschiedene Bitmuster, um eine derartige Eingangskombination auszuschließen. Wer ziemlich sicher gehen will, schiebt in einer Schleife alle 256 verschiedenen Kombinationen durch. Wenn (bei gemeinsamem ¬L) die Ausgänge unzulässig zappeln, muss man ¬OE beschalten, oder genau jene Bitkombinationen vermeiden.


Kann man andere SPI-Hardware in die Kette einfügen?
=== Kann man andere SPI-Hardware in die Kette einfügen? ===


Genau dafür ist SPI gemacht! Aber nicht jeder (bspw.) A/D-Wandler ist dafür geeignet: Es muss möglich sein, Daten ''unverändert'' durchzuschieben. Oder wenigstens herumzuleiten. Wenn nicht, ist die einzig mögliche Anordnung ''zwischen'' den '595 (am Kettenanfang) und den '165 (am Kettenende). In der Regel wird eine gesonderte Chipselect-Leitung vom Mikrocontroller benötigt; nur in Ausnahmefällen ist o.g. '''¬L''' dafür geeignet (Datenblatt studieren!). Das Chipselect aus einem '595 zu generieren geht auch.
Genau dafür ist SPI gemacht! Aber nicht jeder (bspw.) A/D-Wandler ist dafür geeignet: Es muss möglich sein, Daten ''unverändert'' durchzuschieben. Oder wenigstens herumzuleiten. Wenn nicht, ist die einzig mögliche Anordnung ''zwischen'' den '595 (am Kettenanfang) und den '165 (am Kettenende). In der Regel wird eine gesonderte Chipselect-Leitung vom Mikrocontroller benötigt; nur in Ausnahmefällen ist o.&nbsp;g. '''¬L''' dafür geeignet (Datenblatt studieren!). Das Chipselect aus einem '595 zu generieren geht auch.


Was für Vorteile bringen '595 und '165 gegenüber einem größeren Mikrocontroller?
=== Was für Vorteile bringen '595 und '165 gegenüber einem größeren Mikrocontroller? ===


* Preis! Controller mit mehr Beinchen kosten oftmals deutlich mehr
* Preis! Controller mit mehr Beinchen kosten oftmals deutlich mehr
Zeile 719: Zeile 710:
* Exakt gleichzeitige Aktualisierung der Ausgänge und Abfrage der Eingänge, auch bei mehr als der Mikrocontroller-Portbreite (kann helfen, knifflige Übergangsprobleme zu lösen)
* Exakt gleichzeitige Aktualisierung der Ausgänge und Abfrage der Eingänge, auch bei mehr als der Mikrocontroller-Portbreite (kann helfen, knifflige Übergangsprobleme zu lösen)
* ESD-Schutz und Überlastschutz des Controllers
* ESD-Schutz und Überlastschutz des Controllers
* Einfache Pegelkonvertierung (typisch 3 V ↔ 5 V) mit 74HCT-Bauelementen
* Einfache Pegelkonvertierung (typisch 3&nbsp;V ↔ 5&nbsp;V) mit 74HCT-Bauelementen
* Verbleib beim „gewohnten“ Mikrocontroller möglich
* Verbleib beim „gewohnten“ Mikrocontroller möglich


Und welche Nachteile handelt man sich ein?
=== Und welche Nachteile handelt man sich ein? ===


* Fehlende Sonderfunktionen (etwa Hardware-PWM, Interrupts)
* Fehlende Sonderfunktionen (etwa Hardware-PWM, Interrupts)
* Fehlende Bidirektionalität
* Fehlende Bidirektionalität
* Geringere Geschwindigkeit sowie zusätzliche Verzögerung beim Startup
* Geringere Geschwindigkeit sowie zusätzliche Verzögerung beim Startup
** In Zahlen: Bei 16 MHz und Hardware-SPI dauert das Befüllen ''eines'' '595 genau 1 µs: Schiebetakt 8 MHz. Ein OUT-Befehl zu einem 8-Bit-Port ist 16-mal schneller. Auch die ''zusätzliche'' Startup-Verzögerung liegt in diesem Bereich
** In Zahlen: Bei 16 MHz und Hardware-SPI dauert das Befüllen ''eines'' '595 genau 1&nbsp;µs: Schiebetakt 8&nbsp;MHz. Ein OUT-Befehl zu einem 8-Bit-Port ist 16-mal schneller. Auch die ''zusätzliche'' Startup-Verzögerung liegt in diesem Bereich
** Der wesentliche Teil der Gesamt-Startup-Verzögerung kommt vom Startup-Timer, der nur mittels Fuse-Bits eingestellt werden kann. Hat man einen Arduino, braucht man ein Programmiergerät um diese zu ändern. Beispielsweise 65 ms + 16K Takte (@ 16 MHz) = 66 ms. Die Initialisierungsroutine bis main() initialisiert den RAM-Bereich [und geht bei C++ durch die statischen Konstruktoren], dauert 9 Takte pro Byte, bei 1 KByte 9K Takte, fällt mit ≈ 500 µs nicht so sehr ins Gewicht, wenn die Startup-Verzögerung so groß ist. Die Startup-Verzögerung ist kein Problem im Vergleich zu echten Mikrocontroller-Portpins, denn auch diese können nur verzögert angesteuert werden.
** Der wesentliche Teil der Gesamt-Startup-Verzögerung kommt vom Startup-Timer, der nur mittels Fuse-Bits eingestellt werden kann. Hat man einen Arduino, braucht man ein Programmiergerät um diese zu ändern. Beispielsweise 65&nbsp;ms + 16K Takte (@&nbsp;16&nbsp;MHz) = 66&nbsp;ms. Die Initialisierungsroutine bis <code>main()</code> initialisiert den RAM-Bereich (und geht bei C++ durch die statischen Konstruktoren), dauert 9 Takte pro Byte, bei 1&nbsp;KByte 9K Takte, fällt mit ≈&nbsp;500&nbsp;µs nicht so sehr ins Gewicht, wenn die Startup-Verzögerung so groß ist. Die Startup-Verzögerung ist kein Problem im Vergleich zu echten Mikrocontroller-Portpins, denn auch diese können nur verzögert angesteuert werden.
* Fehlende Weak-Pullups (bei den Eingängen, es sei denn, man verwendet veraltete 74LS165)
* Fehlende Weak-Pullups (bei den Eingängen, es sei denn, man verwendet veraltete 74LS165)
* Höherer Bestückungsaufwand durch das Mehr an Bauteilen
* Höherer Bestückungsaufwand durch das Mehr an Bauteilen


== Bekannte Probleme ==
== Bidirektionale Erweiterung ==
 
Wünscht man sich ''bidirektionale Einzelanschlüsse'' (wie im AVR-Mikrocontroller selbst), so ist man auf dem Holzweg: Dafür gibt es entweder keine oder alte, völlig überteuerte ICs. Ist das unbedingt erforderlich, benutzt man am besten einen ''weiteren AVR-Mikrocontroller'' im Slave-SPI-Modus. Für die Richtungsumschaltung steckt ein weiteres Latch in seiner Firmware, d.&nbsp;h. seine Gesamtschieberegisterlänge ist doppelt so lang wie die Anzahl der umschaltbaren Ein-/Ausgangspins.
 
Genügt Bidirektionalität 8-bit-weise, ist ein [https://www.ti.com/lit/ds/schs178c/schs178c.pdf 74HC(T)299] die richtige Lösung. Dieser kann sogar in die vorhandene Kette aus '595 und '164 eingebaut werden. Für die Umschaltung der Datenrichtung wird ein weiteres Portpin benötigt, welches bei akutem Pinmangel von einem vorgeschalteten '595 kommen kann.


AVR Studio 4.12 (Build 498) hat Probleme bei der korrekten Simulation des SPI-Moduls.
Da mit dem '299 typischerweise ein 8-Bit-Bus (oder breiter) für einen pinarmen Mikrocontroller gebildet wird, lohnt sich für diesen der Anschluss von RCK und DIR an dedizierte Mikrocontroller-Pins besonders, da hier Geschwindigkeit das A und O ist.


* Der Double-Speed Modus funktioniert nicht.
== 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.
* 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
Hardwareprobleme:
* Wenn das SPI-Modul aktiviert wird, wird '''nicht''' automatisch SPIF gesetzt, es bleibt auf null. Damit würde die erste Abfrage in <code>Schiebe_alles</code> 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 <code>nop</code> eine feste minimale Zeit zwischen zwei Bytes warten würde. Zwischen zwei Bytes muss immer eine Pause von mindestens 2 Systemtakten eingehalten werden.


* 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
== Siehe auch ==


* 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.
* Forumsbeitrag: [https://www.mikrocontroller.net/topic/215399#2145277 48-I/O-Porterweiterung mit Schieberegistern 74HC595 und 74HC165]


== Weblinks ==
== Weblinks ==


* [http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf AVR151: Setup And Use of The SPI] Atmel Application Note (PDF)
* Atmel Application Note [https://www.microchip.com/en-us/application-notes/an2585.html AVR151: Setup and use of the SPI]
* [http://www.datasheetcatalog.com/datasheets_pdf/7/4/H/C/74HC595.shtml datasheetcatalog.com: 74HC595]
* [http://www.datasheetcatalog.com/datasheets_pdf/7/4/H/C/74HC595.shtml datasheetcatalog.com: 74HC595]
* [http://www.rn-wissen.de/index.php/Portexpander_am_AVR Roboternetz: Portexpander am AVR]
* [http://www.rn-wissen.de/index.php/Portexpander_am_AVR Roboternetz: Portexpander am AVR]
* [http://conductiveresistance.com/interactive-595-shift-register-simulator/ Interactive 595 Shift Register Simulator]
* [http://conductiveresistance.com/interactive-595-shift-register-simulator/ Interactive 595 Shift Register Simulator]
* [http://www.mikrocontroller.net/topic/215399#2145277 48 I/O Porterweiterung mit Schieberegister 74HC595 und 74HC165]
 
----
----



Aktuelle Version vom 22. November 2022, 19:09 Uhr

Ab und an stellt sich folgendes Problem: Man würde wesentlich mehr Ausgangs- 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 (wobei xx = HC(T), LS, …).

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
(lies: TRI-stejt)
Die acht Registerausgänge können die 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. Hier 3-state
Schieberegister Serielle Daten werden durch den Baustein durchgeschoben
Ausgangsregister Ein Speicher, welcher die Daten des Schieberegisters zwischenspeichern kann.
Dieser besteht aus acht FlipFlops.
Asynchroner Reset Die Daten im Schieberegister können asynchron auf 0 gesetzt werden. Achtung! Keine unmittelbare Wirkung auf das Ausgangsregister, daher praktisch wertlos.
asynchron (Eingang) Der Eingang wirkt ohne zusätzliche Taktflanke.
Der Gegenentwurf „synchron“ meint, dass der Eingang nur bei Flanke am Takteingang zur Wirkung kommt.

Aufbau 74xx595

Pinbelegung eines 74xx595

Hinweis: Die Benennung der Pins in den Datenblättern verschiedener Hersteller unterscheidet sich zum Teil. Die Funktionen der Pins sind jedoch gleich.

Werden viele Ausgänge mit bis zu 15 Volt benötigt (typischerweise zum Durchsteuern von MOSFETs, die nicht „logik-kompatibel“ sind), eignet sich der CMOS-Typ 4094 zum Ersatz des 74xx595, mit abweichender Pinbelegung. Seine Verwendung erfordert nur drei Pegelkonverter, etwa ½ 4504, ¾ 40109 oder diskret aufgebaut. Die genannten ICs sind preiswert und leicht beschaffbar.

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. Auch dieser IC ist leicht beschaffbar. Man kann sich diesen aus einem 74xx595 und einem ULN2803 zusammengesetzt vorstellen: Seine Ausgänge ziehen nur nach Low, nicht nach High. Für den Anschluss von Relais werden externe Freilaufdioden benötigt, die beim ULN2803 integriert sind.

HC oder HCT?

Mal gibt es 74HC595, mal 74HCT595. Diese beiden Typen unterscheiden sich nur dadurch, wie sie Eingangs-Signale erkennen:

  • HC: High-Signal muss mindestens ca. 75 % der Betriebsspannung haben (siehe VIH im Datenblatt);
  • HCT: TTL-kompatibel, High-Signal muss mindestens 2 V haben (Betriebsspannung ist immer 5 V).

Es gibt auch 74LS595. In der modernen CMOS-Welt sollte man sich aber Low-Power-Schottky (= bipolar = Ruhestrom fressend) nicht mehr antun.

Im allgemeinen kann man alle Typen gleichermaßen verwenden und nimmt einfach den billigsten oder verfügbarsten. Nur beim Übergang zu echtem TTL oder verschiedenen Speisespannungen für Mikrocontroller und Portexpander wird es interessant.

Ein häufiges Szenario ist ein Mikrocontroller mit 3-V-Speisung (etwa ein ARM7 oder MSP430). Dann kann man mit einem 74HCT595, an 5 V betrieben, echte 5-V-Ausgänge und die Pegelkonvertierung dazu haben. 74HC595 funktionieren hier nur mit Glück, und bei noch geringerer Speisespannung des Controllers – etwa 2,5 V – gar nicht.

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.

74xx595-2.png

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 an RCK (Pin 12) der Inhalt des Schieberegisters in das Ausgangsregister übernommen.

74xx595-3.png

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 High-Z: d. h. sie treiben aktiv weder Low noch 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 Ansteuerung eines 74xxx595-Schieberegisters gestaltet sich sehr einfach. Im Grunde gibt es zwei 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

Anschluss eines 595

Für eine komplette Softwarelösung kann das Schieberegister an jede beliebige Port-Pin-Kombination angeschlossen werden. Wir wählen die Pins PB2, PB3 und PB5 um dort die Schieberegisteranschlüsse RCK, SER und SCK anzuschließen. Des Weiteren muss das Schieberegister mit Spannung versorgt werden: Pin 16 muss auf +5 V 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 PB3 (SER) ausgegeben. Durch Generierung eines Pulses 0–1–0 an Pin PB5 (SCK) übernimmt das Schieberegister nacheinander die einzelnen Bits. Dabei ist zu beachten, dass die Ausgabe mit dem höchstwertigen Bit (MSB) 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 PB2 (RCK) der Inhalt der Schieberegisterbits 0 bis 7 in das Ausgaberegister für 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 z. B. mit LEDs (Low-current-LEDs + Vorwiderstände verwenden, siehe unten) sichtbar gemacht werden.

Der Schieberegister-Rücksetzeingang SCL wird auf UCC gelegt. Das Einschieben von 0x00 hat die gleiche Wirkung wie das Rücksetzen mit diesem Pin.

.include "m8def.inc"

.def temp1 = r16
.def temp2 = r17

.equ SCHIEBE_DDR  = DDRB
.equ SCHIEBE_PORT = PORTB
.equ RCK          = 2
.equ SCK          = 5
.equ SIN          = 3

    ldi   temp1, LOW(RAMEND)     ; Stackpointer initialisieren
    out   SPL, temp1             ;(wird bei modernen AVRs nicht mehr benötigt)
    ldi   temp1, HIGH(RAMEND)
    out   SPH, temp1

;
; Die Port Pins auf Ausgang konfigurieren
;
    ldi   temp1, (1<<RCK) | (1<<SCK) | (1<<SIN) ; s. Anm. 1
    out   SCHIEBE_DDR, temp1

;
; 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

Anm. 1: Siehe Bitmanipulation

Ansteuerung per SPI-Modul

Anschluss eines 595 per SPI

Noch schneller geht die Ansteuerung des Schieberegisters mittels SPI-Modul, welches in fast allen AVRs vorhanden ist. Auch hier wird der Pin SCL nicht benutzt, da das praktisch keinen Sinn hat. Er wird fest auf VCC gelegt. Die Pins für SCK und SIN sind durch den jeweiligen AVR fest vorgegeben. SCK vom 74xx595 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 für RCK verwendet werden, da es im SPI-Master-Modus immer ein Eingang ist! Es kann aber als allgemeiner Eingang oder für 74HC165 (siehe unten) verwendet werden.

Der AVR-Pin SS wird sinnvollerweise als RCK benutzt, da er sowieso als Ausgang geschaltet werden muss, sonst gibt es böse Überraschungen (siehe Datenblatt „SS Pin Functionality“).

Bei den kleineren ATtinys mit USI (Universal Serial Interface) darf man sich von den Pin-Bezeichnungen MOSI und MISO nicht ins Bockshorn jagen lassen: Hier ist MISO der Ausgang (!) DO und MOSI der Eingang (!) DI. Die Pinbezeichnungen MOSI und MISO sind nur zum Programmieren und irreführend, weil ohnehin nur für den Slave-Betrieb.

Je nach Bedarf kann man die Taktrate des SPI-Moduls zwischen 1/2 und 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 74xx595 kein Problem. Die Übertragung von 8 Bit dauert dann gerade mal 800 ns!

.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             ; (bei modernen AVRs obsolet)
    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

Kaskadieren von Schieberegistern

Kaskadieren mehrerer 595

Um ein Schieberegister anzuschließen genügen also im einfachsten Fall 3 freie Prozessorpins (4, wenn SCL oder besser OE 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 ggf. SCL bzw. OE werden parallel zu den bereits vorhandenen geschaltet. Konzeptionell erhält man dadurch ein Schieberegister mit einer Breite von 16 Bit. Werden weitere 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.

.include "m8def.inc"
.def temp1 = r16

; Die Definitionen müssen an den jeweiligen AVR angepasst werden.
; Hinweis: Dieser Code passt nicht zum nebenstehenden Bild!

.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  ; bei modernen AVRs mit vergrößertem I/O-Adressraum $100
Schiebedaten:       .byte 2

;-----------------------------------------------------------------------------
;
; Programmsegment im Flash-ROM
;
;-----------------------------------------------------------------------------

.cseg
    ldi     temp1, LOW(RAMEND)     ; Stackpointer initialisieren
    out     SPL, temp1             ; (obsolet bei modernen AVRs)
    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 (2 Byte) 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

Schiebe_alle_2:
    ld      r0, Z+
Schiebe_alle_3:
    sbis    SPSR, SPIF          ; prüfe, ob eine alte Übertragung beendet ist
     rjmp   Schiebe_alle_3
    out     SPDR, r0            ; 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

    sbi     SCHIEBE_PORT, RCK   ; RCK inaktiv, Datenübernahme
    ret

Der Nachteil von Schieberegistern ist allerdings, dass sich die Zeit zum Setzen 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 Latches 74xxx573 eine Alternative sein, um jeweils ein vollständiges Byte auszugeben. Natürlich kann der 74xxx573 (oder ein ähnliches Latch) auch mit dem 74xxx595 zusammen eingesetzt werden, beispielsweise indem über das Schieberegister verschiedene 74xxx595 nacheinander aktiviert werden. Weitere Tips und Tricks dazu gibt es vielleicht in einem weiteren Tutorial …

Acht LEDs mit je 20 mA 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 70 mA über VCC liefern bzw. über 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 höchstens 70 mA / 8 = 8,75 mA begrenzen; das ist bei modernen LEDs schon mehr als genug, um sie schön hell leuchten zu lassen – bei low-current (für 2 mA ausgelegt!) und ultrahellen LEDs sowieso.
  • Wenn doch 20 mA pro LED gebraucht werden, kann man die folgende Trickschaltung anwenden.
Mehrere LED anschließen

Der Trick besteht darin, dass 4 LEDs ihren Strom über das Schieberegister von VCC beziehen (high-aktiv), während der Strom der anderen vier über GND abgeleitet wird (low-aktiv). Damit bleiben ganz offiziell für jede LED 70 mA / 4 = 17,5 mA. 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,3 V Flussspannung ausgelegt. Bei roten, gelben und grünen LEDs ist die Flussspannung geringer und dementsprechend muss der Vorwiderstand größer sein.

Wenn 20 mA 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 250 mA pro Kanal zur Verfügung stehen.

Achtung beim Startup!

Die Ausgänge des 74xx595 führen beim Einschalten undefinierte, also zufällige Pegel! Und der Eingang SCL löscht nur die Schieberegister-Flipflops (= unnütz, um mit RESET zu verbinden: Festlegung an UCC genügt vollauf). Sind deshalb definierte Pegel beim Einschalten unerlässlich, muss man OE beschalten:

  • Entweder mit einem weiteren Mikrocontroller-Ausgang (der mit einem externen Pull-Up-Widerstand zu beschalten ist und nach dem ersten Durchschieben dauerhaft auf low gelegt wird)
  • Oder mit einer RC(D)-Kombination, die die Ausgänge für eine gewisse Zeit auf High-Z hält. Spart einen Mikrocontroller-Pin.

Obendrein sind, wie auch beim direkten Anschluss am Mikrocontroller, die betreffenden Ausgänge des 74xx595 mit externen Pull-Up- oder Pull-Down-Widerständen zu beschalten.

Man könnte meinen, dass der Anschluss SCL einfach ein böser Fallstrick ist, denn viel sinnvoller wäre eine Reset-Funktion für die Ausgangs-Flipflops. Schade, dass es keinen Schaltkreis gibt, der das richtig implementiert; mikrocontroller.net würde einen solchen sofort empfehlen.

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

Pinbelegung eines 165

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. 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 DS-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 (GND oder VCC),
  • der serielle Datenausgang bei der Benutzung des SPI-Moduls an MISO und nicht an MOSI angeschlossen wird.
Anschluss eines 165

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

; 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-ROM
;
;-----------------------------------------------------------------------------
.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 niederwertigste 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

Ansteuerung per SPI-Modul

; 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

Beides in einer Kette

Kann man die 74xx595 und die 74xx165 an einem SPI-Anschluss betreiben?

Ja, einfach verketten. Das geht auch „durcheinander“. Dafür gibt es zwei Möglichkeiten:

  • Man verwendet getrennte Anschlüsse am Mikrocontroller für die Parallelübernahme der 74xx595 (Ausgänge) und 74xx165 (Eingänge). Dann sollten die Ausgänge am Ketten-Anfang (MOSI) und die Eingänge am Ketten-Ende (MISO) liegen. Beispielsweise werden für 3 Stück 74xx595 und 2 Stück 74xx165 24 Schiebetakte zum Ausgeben (mit anschließendem ↑RCLK) und 16 Schiebetakte (mit vorausgehendem ¬PL) zum Einlesen benötigt.
  • Man verwendet einen gemeinsamen Anschluss ¬L für ↑RCLK und ¬PL, ein Pin sparend. Die o. g. Reihenfolge der 74xx595 und 74xx165 ist weiterhin vorteilhaft. Nach dem o. g. Beispiel gilt folgendes Regime zum Ausgeben und Einlesen in einem Rutsch:
    • Low-Nadel an ¬L (zum Laden der '165-Flipflops; die '595-Ausgänge verändern sich nicht)
    • 8 · 3 = 24 Schiebetakte (auch zum Nur-Einlesen müssen die Ausgabedaten wiederholt ausgegeben werden)
    • Low-Nadel an ¬L (zum Aktualisieren der '595-Ausgänge; das erneute Einlesen in den '165 ist ohne Belang)

Kann man per Software messen, wie lang die Kette ist?

Für bestimmte PnP-artige Lösungen ist es zweckmäßig, die Länge der Kette zu kennen: Man schiebt einfach eine einzelne 1 (oder eine einzelne 0) durch die Kette, ohne Parallelübernahmen. Vorher muss man die Kette in ihrer zu erwartenden Maximallänge initialisieren. Benutzt man byteweise arbeitende Hardware-SPI, wird man auf ganze Byte-Längen vertrauen und kann für mehr Sicherheit ein bestimmtes Kennbyte durchschicken.

Kann man per Software messen, wo die '595 und die '165 liegen?

Nur wenn man davon ausgeht, dass sich die Eingänge nicht allzu schnell ändern. Das ist bei Tastern klar der Fall. Eine 100-prozentige Sicherheit gibt es nicht. Man schiebt ein bestimmtes Bitmuster (Byte) durch und nimmt '595 dort an, wo das Bitmuster auch zurückkommt. Man verwende mindestens 2 verschiedene Bitmuster, um eine derartige Eingangskombination auszuschließen. Wer ziemlich sicher gehen will, schiebt in einer Schleife alle 256 verschiedenen Kombinationen durch. Wenn (bei gemeinsamem ¬L) die Ausgänge unzulässig zappeln, muss man ¬OE beschalten, oder genau jene Bitkombinationen vermeiden.

Kann man andere SPI-Hardware in die Kette einfügen?

Genau dafür ist SPI gemacht! Aber nicht jeder (bspw.) A/D-Wandler ist dafür geeignet: Es muss möglich sein, Daten unverändert durchzuschieben. Oder wenigstens herumzuleiten. Wenn nicht, ist die einzig mögliche Anordnung zwischen den '595 (am Kettenanfang) und den '165 (am Kettenende). In der Regel wird eine gesonderte Chipselect-Leitung vom Mikrocontroller benötigt; nur in Ausnahmefällen ist o. g. ¬L dafür geeignet (Datenblatt studieren!). Das Chipselect aus einem '595 zu generieren geht auch.

Was für Vorteile bringen '595 und '165 gegenüber einem größeren Mikrocontroller?

  • Preis! Controller mit mehr Beinchen kosten oftmals deutlich mehr
  • Günstigeres Routing zu weiter entfernten Schaltungsteilen
  • Kleinere Steckverbinder zu weiteren Platinen, etwa Anzeige- und Bedien-Frontplatten
  • Beliebige Verlängerbarkeit
  • Exakt gleichzeitige Aktualisierung der Ausgänge und Abfrage der Eingänge, auch bei mehr als der Mikrocontroller-Portbreite (kann helfen, knifflige Übergangsprobleme zu lösen)
  • ESD-Schutz und Überlastschutz des Controllers
  • Einfache Pegelkonvertierung (typisch 3 V ↔ 5 V) mit 74HCT-Bauelementen
  • Verbleib beim „gewohnten“ Mikrocontroller möglich

Und welche Nachteile handelt man sich ein?

  • Fehlende Sonderfunktionen (etwa Hardware-PWM, Interrupts)
  • Fehlende Bidirektionalität
  • Geringere Geschwindigkeit sowie zusätzliche Verzögerung beim Startup
    • In Zahlen: Bei 16 MHz und Hardware-SPI dauert das Befüllen eines '595 genau 1 µs: Schiebetakt 8 MHz. Ein OUT-Befehl zu einem 8-Bit-Port ist 16-mal schneller. Auch die zusätzliche Startup-Verzögerung liegt in diesem Bereich
    • Der wesentliche Teil der Gesamt-Startup-Verzögerung kommt vom Startup-Timer, der nur mittels Fuse-Bits eingestellt werden kann. Hat man einen Arduino, braucht man ein Programmiergerät um diese zu ändern. Beispielsweise 65 ms + 16K Takte (@ 16 MHz) = 66 ms. Die Initialisierungsroutine bis main() initialisiert den RAM-Bereich (und geht bei C++ durch die statischen Konstruktoren), dauert 9 Takte pro Byte, bei 1 KByte 9K Takte, fällt mit ≈ 500 µs nicht so sehr ins Gewicht, wenn die Startup-Verzögerung so groß ist. Die Startup-Verzögerung ist kein Problem im Vergleich zu echten Mikrocontroller-Portpins, denn auch diese können nur verzögert angesteuert werden.
  • Fehlende Weak-Pullups (bei den Eingängen, es sei denn, man verwendet veraltete 74LS165)
  • Höherer Bestückungsaufwand durch das Mehr an Bauteilen

Bidirektionale Erweiterung

Wünscht man sich bidirektionale Einzelanschlüsse (wie im AVR-Mikrocontroller selbst), so ist man auf dem Holzweg: Dafür gibt es entweder keine oder alte, völlig überteuerte ICs. Ist das unbedingt erforderlich, benutzt man am besten einen weiteren AVR-Mikrocontroller im Slave-SPI-Modus. Für die Richtungsumschaltung steckt ein weiteres Latch in seiner Firmware, d. h. seine Gesamtschieberegisterlänge ist doppelt so lang wie die Anzahl der umschaltbaren Ein-/Ausgangspins.

Genügt Bidirektionalität 8-bit-weise, ist ein 74HC(T)299 die richtige Lösung. Dieser kann sogar in die vorhandene Kette aus '595 und '164 eingebaut werden. Für die Umschaltung der Datenrichtung wird ein weiteres Portpin benötigt, welches bei akutem Pinmangel von einem vorgeschalteten '595 kommen kann.

Da mit dem '299 typischerweise ein 8-Bit-Bus (oder breiter) für einen pinarmen Mikrocontroller gebildet wird, lohnt sich für diesen der Anschluss von RCK und DIR an dedizierte Mikrocontroller-Pins besonders, da hier Geschwindigkeit das A und O ist.

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 mindestens 2 Systemtakten eingehalten werden.

Siehe auch

Weblinks