Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Laderegler Test Tueftler Seite

(Mit SPI-Hardware)
(Link zu "595 Shift Register Simulator" hinzugefügt)
 
(19 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Bietet ein Controller nicht genügend I/O-Leitungen, dann kann man Portexpander werwenden. Dadurch hat man zusätzliche Ports zur Verfügung. Neben [[I2C Chip-Übersicht|Portexpandern der I²C-Klasse]] oder [[SPI]]-Klasse bietet sich an, 8-Bit-Schieberegister zu kaskadieren und als Expander zu verwenden. Das ist oft ausreichend, weil mehr Ausgänge gebraucht werden als Eingänge. Dabei verwendet man Schieberegister mit Ausgangs-Latch, d.h. die Daten werden erst dann an die Ausgänge geschaltet, wenn sie an Ort und Stelle sind.  
+
Bietet ein Controller nicht genügend I/O-Leitungen, dann kann ein Portexpander verwendet werden. Dadurch stehen zusätzliche Ports zur Verfügung. Neben [[I2C Chip-Übersicht|Portexpandern der I²C-Klasse]] oder [[SPI]]-Klasse bietet sich an, 8-Bit-Schieberegister zu kaskadieren und als Expander zu verwenden. Das ist oft ausreichend, weil mehr Ausgänge gebraucht werden als Eingänge. Dabei werden Schieberegister mit Ausgangs-Latch verwendet, d.h. die Daten werden erst dann an die Ausgänge geschaltet, wenn sie an Ort und Stelle sind.  
  
Falls man Eingänge benötigt, können auch Schieberegister mit Input-Latches ankaskadiert werden, welche die Eingänge von parallel nach seriell umsetzen (in diesem Artikel nicht näher beschrieben).
+
Falls Eingänge benötigt werden, können auch Schieberegister mit Input-Latches ankaskadiert werden, welche die Eingänge von parallel nach seriell umsetzen (in diesem Artikel nicht näher beschrieben).
 
+
{{Ausbauwunsch|
+
* Beispiel-Code in BASIC für die Software-Version
+
}}
+
  
 
= Pro & Contra =
 
= Pro & Contra =
Zeile 20: Zeile 16:
 
* Hardware bzw. Code der Version ohne Hardware-Unterstützung ist auch auf anderen Controllertypen als AVR verwendbar (sofern die Ausgangspegel passen).
 
* Hardware bzw. Code der Version ohne Hardware-Unterstützung ist auch auf anderen Controllertypen als AVR verwendbar (sofern die Ausgangspegel passen).
 
* Test der Schaltung direkt am PC möglich, falls man Zugriff auf den Parallelport oder [[RS232]] ('''Pegelanpassung erforderlich!''' z.B MAX232, Widerstände & [[Diode#Zenerdiode|Zenerdiode]]) hat. In diesem Fall verwendet man die Software PC-seitig und setzt/resettet die 3 Portleitungen, an die man die Expander angeschlossen hat.
 
* Test der Schaltung direkt am PC möglich, falls man Zugriff auf den Parallelport oder [[RS232]] ('''Pegelanpassung erforderlich!''' z.B MAX232, Widerstände & [[Diode#Zenerdiode|Zenerdiode]]) hat. In diesem Fall verwendet man die Software PC-seitig und setzt/resettet die 3 Portleitungen, an die man die Expander angeschlossen hat.
 +
* Indem die Enable-Leitung des Latches per PWM angesteuert wird, können die Ausgänge einfach und effizient gedimmt werden. Das ist interessant, wenn die Portexpander [[LED]]s treiben.
  
 
;Nachteile
 
;Nachteile
Zeile 25: Zeile 22:
 
* soll ein Ausgangs-Port geändert werden, müssen ''alle'' Daten neu gesendet werden  
 
* soll ein Ausgangs-Port geändert werden, müssen ''alle'' Daten neu gesendet werden  
 
* bei der Variante mit SPI-Hardware liegt MISO brach bzw ist nicht so einfach nutzbar zu machen
 
* bei der Variante mit SPI-Hardware liegt MISO brach bzw ist nicht so einfach nutzbar zu machen
 +
* Lange Leitungen sind problematisch, weil die CLK Leitung empfindlich auf Überschwinger reagiert.
  
 
=Resourcen=
 
=Resourcen=
Zeile 48: Zeile 46:
 
* evtl. Pullup/Pulldown-Widerstand: 20kΩ
 
* evtl. Pullup/Pulldown-Widerstand: 20kΩ
 
* Widerstände zum Entkoppeln vom ISP: einige kΩ
 
* Widerstände zum Entkoppeln vom ISP: einige kΩ
* evtl. Kondensatoren von 100pF zum Entstören der Dateinleitungen
+
* evtl. Kondensatoren von 100pF zum Entstören der Datenleitungen
 
* Strom für die Versorgung im Bereich von µA bis wenige mA (je nach Expander-Typ, Anzahl und Frequenz)
 
* Strom für die Versorgung im Bereich von µA bis wenige mA (je nach Expander-Typ, Anzahl und Frequenz)
  
Zeile 59: Zeile 57:
 
|}
 
|}
 
</center>
 
</center>
;Das umstrichelte Modul: kann einfach so oft nach rechts wiederholt werden, bis man so viele Ausgänge hat wie gewünscht. Die Bits wandern über Pin&nbsp;14 (SER) in den Expander. Acht Takte später erscheint das Bit wieder an Pin&nbsp;9 (QH*) und damit am SER-Eingang des folgenden Expanders.
+
;Das umstrichelte Modul: kann einfach so oft nach rechts wiederholt werden, bis es soviele Ausgänge hat, wie gewünscht. Die Bits wandern über Pin&nbsp;14 (SER) in den Expander. Acht Takte später erscheint das Bit wieder an Pin&nbsp;9 (QH*) und damit am SER-Eingang des folgenden Expanders.
 
;R1: ist ein Pullup-Widerstand, der während des ISP-Programmierens dafür sorgt, daß RCK nicht floatet, denn während der Programmierung sind die AVR I/O-Leitungen hochohmig. Dadurch bleiben die Ausgänge der Expander stabil (MOSI und SCK wackeln natürlich beim Programmierern).
 
;R1: ist ein Pullup-Widerstand, der während des ISP-Programmierens dafür sorgt, daß RCK nicht floatet, denn während der Programmierung sind die AVR I/O-Leitungen hochohmig. Dadurch bleiben die Ausgänge der Expander stabil (MOSI und SCK wackeln natürlich beim Programmierern).
;R2, R3: entkoppeln den ISP-Adapter. Ansonsten stören sie nicht weiter, denn beim Proggen muss praktisch kein Strom fliessen &ndash; abgesehen vom minimalen Leckstrom der Ports und Füllen der Portkapazität von ein paar pF.
+
;R2, R3: entkoppeln den ISP-Adapter. Ansonsten stören sie nicht weiter, denn beim Programmieren muss praktisch kein Strom fliessen &ndash; abgesehen vom minimalen Leckstrom der Ports und Füllen der Portkapazität von ein paar pF.
; Eingang G (Pin13): ist hier auf LOW verdrahtet. Falls gewünscht, kann er verwendet werden, um die Ausgänge der Expander hochohmig zu schalten (high-Z). Dann braucht man natürlich einen weiteren µC-Port, um das zu tun.
+
; Eingang G (Pin13): ist hier auf LOW verdrahtet. Falls gewünscht, kann er verwendet werden, um die Ausgänge der Expander hochohmig zu schalten (high-Z). Dann wird natürlich einen weiteren µC-Port benötigt, um das zu tun. Falls an den Expandern [[LED]]s zum Einsatz kommen sollen, kann G auch mit einem [[PWM]]-Ausgang des µC verdrahtet werden, um die Anzeige dimmen zu können. Im Falle eines PWM-Betriebs ist darauf zu achten, daß durch das gleichzeitige Schalten vieler Ausgänge/Lasten die Betriebsspannung "sauber" bleibt, indem man etwa auf ausreichend große Abblock-Kondensatoren an den Expandern achtet oder andere Maßnahmen zur hinreichenden Stabilisierung der Versorgungsspannung ergreift.
  
 
=Ports=
 
=Ports=
Ohne Nutzung der SPI-Hardware hat man die freie Auswahl, welche Ports man verwendet. Natürlich ist auch die Verwendung der SPI/ISP-Ports in jeder beliebigen Anordnung möglich und das Signal "SCK" muss nicht an Port "SCK" angeschlossen sein. Einzig auf das Signal '''RCK''' sollte man achten, denn falls es zugleich durch den ISP verwendet wird, flattern beim Programmieren möglicherweise die Expander-Ausgänge.
+
Ohne Nutzung der SPI-Hardware gibt es die freie Auswahl, welche Ports verwendet werden sollen. Natürlich ist auch die Verwendung der SPI/ISP-Ports in jeder beliebigen Anordnung möglich und das Signal "SCK" muss nicht an Port "SCK" angeschlossen sein. Einzig auf das Signal '''RCK''' sollte man achten, denn falls es zugleich durch den ISP verwendet wird, flattern beim Programmieren möglicherweise die Expander-Ausgänge.
  
 
Bei der Hardware-Version ist man auf die SPI-Pins  
 
Bei der Hardware-Version ist man auf die SPI-Pins  
Zeile 72: Zeile 70:
 
festgelegt, mit Ausnahme von '''RCK'''. Das kann irgendein Port sein (ausser '''MISO''', das bei aktiviertem SPI immer Input ist). Im Beispiel ist '''RCK''' an '''SS''' (SPI Slave Select) angeschlossen.  
 
festgelegt, mit Ausnahme von '''RCK'''. Das kann irgendein Port sein (ausser '''MISO''', das bei aktiviertem SPI immer Input ist). Im Beispiel ist '''RCK''' an '''SS''' (SPI Slave Select) angeschlossen.  
 
{{FarbigerRahmen |
 
{{FarbigerRahmen |
Falls man '''SS''' nicht in dieser Weise verwendet, muss man auf jeden Fall dafür sorgen, daß '''SS''' ''entweder'' auf OUT steht, oder ''nie'' auf LOW geht, da sonst SPI in den Slave-Modus schaltet!
+
Falls '''SS''' nicht in dieser Weise verwendet wird, muss auf jeden Fall dafür gesorgt werden, daß '''SS''' ''entweder'' auf OUT steht, oder ''nie'' auf LOW geht, da sonst SPI in den Slave-Modus schaltet!
 
}}
 
}}
  
Zeile 108: Zeile 106:
 
;<tt>#define SERPA_SIZE</tt>: Define für Anzahl der auszugebenden Bytes
 
;<tt>#define SERPA_SIZE</tt>: Define für Anzahl der auszugebenden Bytes
 
;<tt>extern unsigned char serpa[SERPA_SIZE]</tt>: Das Array, dessen Bytes ausgegeben werden. <tt>serpa[0]</tt> landet in dem Portexpander-IC, das direkt am Controller sitzt. Bit0 erscheint jeweils an Ausgang QA, Bit7 erscheint am Ausgang QH, etc.
 
;<tt>extern unsigned char serpa[SERPA_SIZE]</tt>: Das Array, dessen Bytes ausgegeben werden. <tt>serpa[0]</tt> landet in dem Portexpander-IC, das direkt am Controller sitzt. Bit0 erscheint jeweils an Ausgang QA, Bit7 erscheint am Ausgang QH, etc.
;<tt>void serpa_init()</tt>: Initialisiert die Schnittstelle bzw. die verwendeten Ports
+
;<tt>void serpa_init(void)</tt>: Initialisiert die Schnittstelle bzw. die verwendeten Ports
;<tt>void serpa_out()</tt>: Gibt die <tt>SERPA_SIZE</tt> Bytes aus dem Array <tt>serpa</tt> aus.
+
;<tt>void serpa_out(void)</tt>: Gibt die <tt>SERPA_SIZE</tt> Bytes aus dem Array <tt>serpa</tt> aus.
  
 
'''serpa.h'''
 
'''serpa.h'''
  
 
  {{comment|SERiell nach PArallel (serpa) im SPI-Protokoll}}
 
  {{comment|SERiell nach PArallel (serpa) im SPI-Protokoll}}
  #ifndef _SERPA_H_
+
  #ifndef SERPA_H
  #define _SERPA_H_
+
  #define SERPA_H
 
   
 
   
 
  {{comment|4 Bytes (32 Ports)}}
 
  {{comment|4 Bytes (32 Ports)}}
Zeile 121: Zeile 119:
 
   
 
   
 
  extern unsigned char serpa[];
 
  extern unsigned char serpa[];
  extern void serpa_out();
+
  extern void serpa_out (void);
  extern void serpa_init();
+
  extern void serpa_init (void);
 
   
 
   
  #endif {{comment|_SERPA_H_}}
+
  #endif {{comment|SERPA_H}}
  
 
== Mit SPI-Hardware ==  
 
== Mit SPI-Hardware ==  
  
Das Senden erfolgt ohne den SPI-Interrupt zu nutzen. Allein der ISR-Prolog/Epilog dauert schon so lange wie ein Schleifendurchlauf.
+
Das Senden erfolgt, ohne den SPI-Interrupt zu nutzen. Allein der ISR-Prolog/Epilog dauert schon so lange, wie ein Schleifendurchlauf.
  
 
'''serpa.c'''
 
'''serpa.c'''
Zeile 139: Zeile 137:
 
  unsigned char serpa[SERPA_SIZE];
 
  unsigned char serpa[SERPA_SIZE];
 
   
 
   
  void serpa_init()
+
  void serpa_init (void)
 
  {
 
  {
 
     MAKE_OUT (PORT_MOSI);  
 
     MAKE_OUT (PORT_MOSI);  
Zeile 161: Zeile 159:
 
  }
 
  }
 
   
 
   
  void serpa_out ()
+
  void serpa_out (void)
 
  {
 
  {
 
     unsigned char anz = SERPA_SIZE;
 
     unsigned char anz = SERPA_SIZE;
Zeile 176: Zeile 174:
 
       while (!(SPSR & (1 << SPIF)));
 
       while (!(SPSR & (1 << SPIF)));
 
   
 
   
       {{lcomment|clear SPIF}}
+
       {{lcomment|clear SPIF durch Lesen von SPDR}}
       data = SPDR;
+
       (void) SPDR;
 
     }
 
     }
 
     while (--anz > 0);
 
     while (--anz > 0);
Zeile 185: Zeile 183:
 
     SET (PORT_RCK);
 
     SET (PORT_RCK);
 
  }
 
  }
 
'''serpa.bas'''
 
<pre>
 
' SERiell nach PArallel (serpa) mit Hardware-Unterstuetzung
 
' Beispiel mit 2 Datenbytes
 
 
' SPI Bus (Hardware) als Master konfiguiren
 
Config SPI = Hard , Master = Yes
 
 
' SPI Bus initialisieren
 
' setzt das DDR Register entsprechend
 
Spiinit
 
 
' Bytes für die Daten
 
Dim Serpa(2) As Byte
 
Serpa(1) = &B10101010
 
Serpa(2) = &B00000000
 
 
' Die Bytes auf den SPI Bus schieben
 
Spiout Serpa(1) , 2
 
</pre>
 
  
 
== Ohne SPI-Hardware ==  
 
== Ohne SPI-Hardware ==  
Zeile 218: Zeile 195:
 
  unsigned char serpa[SERPA_SIZE];
 
  unsigned char serpa[SERPA_SIZE];
 
   
 
   
  void serpa_init ()
+
  void serpa_init (void)
 
  {
 
  {
 
     {{comment|Verwendete Ports auf OUT}}
 
     {{comment|Verwendete Ports auf OUT}}
Zeile 230: Zeile 207:
 
  }
 
  }
 
   
 
   
  void serpa_out ()
+
  void serpa_out (void)
 
  {
 
  {
 
     unsigned char anz = SERPA_SIZE;
 
     unsigned char anz = SERPA_SIZE;
Zeile 262: Zeile 239:
 
     SET (PORT_RCK);
 
     SET (PORT_RCK);
 
  }
 
  }
 +
 +
= BASCOM-Code=
 +
 +
== Mit SPI-Hardware ==
 +
 +
'''serpa.bas'''
 +
<pre>
 +
' SERiell nach PArallel (serpa) mit Hardware-Unterstuetzung
 +
' Beispiel mit 2 Datenbytes
 +
 +
' SPI Bus (Hardware) als Master konfiguiren
 +
Config SPI = Hard , Master = Yes
 +
 +
' SPI Bus initialisieren
 +
' setzt das DDR Register entsprechend
 +
Spiinit
 +
 +
' Bytes für die Daten
 +
Dim Serpa(2) As Byte
 +
Serpa(1) = &B10101010
 +
Serpa(2) = &B00000000
 +
 +
' Die Bytes auf den SPI Bus schieben
 +
Spiout Serpa(1) , 2
 +
</pre>
  
 
=Expander=
 
=Expander=
  
Von den meisten Expandern gibt es auch Unterversionen, wie 74HC (Highspeed CMOS), 74HTC (Highspeed CMOS, TTL-Compatible), etc. Hier tut's z.B. 74HC. Pro Expander fallen Kosten von ca 30-40 Cent an ([[Bezugsquellen#Elektronikbauteile|Reichelt]]). Ungelatchte Register wie 74*164 sind übrigens nicht zu empfehlen, weil bei deren Verwendung wäherend des Schiebens die Ausgänge flattern.
+
Von den meisten Expandern gibt es auch Unterversionen, wie 74HC (Highspeed CMOS), 74HCT (Highspeed CMOS, TTL-Compatible), etc. Hier tut's z.B. 74HC. Pro Expander fallen Kosten von ca 30-40 Cent an ([[Bezugsquellen#Elektronikbauteile|Reichelt]]). Ungelatchte Register wie 74*164 sind übrigens nicht zu empfehlen, weil bei deren Verwendung wäherend des Schiebens die Ausgänge flattern.
  
Die Verwendete SPI-Frequenz ist unkritisch und kann natürlich auch langsamer eingestellt werden. Taktfrequenzen von 100MHz sind für die ICs normalerweise kein Problem.
+
Die Verwendete SPI-Frequenz ist unkritisch und kann natürlich auch langsamer eingestellt werden. Taktfrequenzen von 50MHz sind für die ICs normalerweise kein Problem. Die steilen Flanken können aber ein Problem bei längeren Kabeln werden.
  
 
;8-Bit Schieberegister mit Ausgangs-Latch:
 
;8-Bit Schieberegister mit Ausgangs-Latch:
Zeile 287: Zeile 289:
  
 
=Weblinks=
 
=Weblinks=
* [http://people.freenet.de/gjl/pub/ebook/index.html Dokumentiertes Projekt, das drei 74*595 als Portexpander verwendet]
+
* [http://www.gjlay.de/pub/ebook/index.html Dokumentiertes Projekt, das drei 74*595 als Portexpander verwendet]
 +
* [http://conductiveresistance.com/interactive-595-shift-register-simulator/ "Interactive 595 Shift Register Simulator" - zum Online-Ausprobieren]
  
 +
[[Kategorie:Elektronik]]
 
[[Kategorie:Microcontroller]]
 
[[Kategorie:Microcontroller]]
 
[[Kategorie:Kommunikation]]
 
[[Kategorie:Kommunikation]]

Aktuelle Version vom 28. Oktober 2012, 12:07 Uhr

Bietet ein Controller nicht genügend I/O-Leitungen, dann kann ein Portexpander verwendet werden. Dadurch stehen zusätzliche Ports zur Verfügung. Neben Portexpandern der I²C-Klasse oder SPI-Klasse bietet sich an, 8-Bit-Schieberegister zu kaskadieren und als Expander zu verwenden. Das ist oft ausreichend, weil mehr Ausgänge gebraucht werden als Eingänge. Dabei werden Schieberegister mit Ausgangs-Latch verwendet, d.h. die Daten werden erst dann an die Ausgänge geschaltet, wenn sie an Ort und Stelle sind.

Falls Eingänge benötigt werden, können auch Schieberegister mit Input-Latches ankaskadiert werden, welche die Eingänge von parallel nach seriell umsetzen (in diesem Artikel nicht näher beschrieben).

Pro & Contra

Vorteile
  • schnell
  • preiswert
  • einfach anzusteuern (auch ohne Hardware-Unterstützung, deutlich einfacher als I²C)
  • Ansteuerung ohne Interrupt-Programmierung
  • modular aufgebaut und erweiterbar
  • alle Ports können gleichzeitig geschaltet werden, auch 100 Stück
  • SPI-Interface und ISP-Pins (die oft ungenutzt bleiben) können verwendet werden
  • Bus hat nur 3 Leitungen, dadurch kein kompliziertes Layout mit vielen Leitungen
  • Hardware bzw. Code der Version ohne Hardware-Unterstützung ist auch auf anderen Controllertypen als AVR verwendbar (sofern die Ausgangspegel passen).
  • Test der Schaltung direkt am PC möglich, falls man Zugriff auf den Parallelport oder RS232 (Pegelanpassung erforderlich! z.B MAX232, Widerstände & Zenerdiode) hat. In diesem Fall verwendet man die Software PC-seitig und setzt/resettet die 3 Portleitungen, an die man die Expander angeschlossen hat.
  • Indem die Enable-Leitung des Latches per PWM angesteuert wird, können die Ausgänge einfach und effizient gedimmt werden. Das ist interessant, wenn die Portexpander LEDs treiben.
Nachteile
  • bei dieser Version nur Ausgabe möglich
  • soll ein Ausgangs-Port geändert werden, müssen alle Daten neu gesendet werden
  • bei der Variante mit SPI-Hardware liegt MISO brach bzw ist nicht so einfach nutzbar zu machen
  • Lange Leitungen sind problematisch, weil die CLK Leitung empfindlich auf Überschwinger reagiert.

Resourcen

Tabelle: Resourcen-Verbrauch mit N ICs
Resource ohne SPI mit SPI
AVR-Peripherie 3 I/O-Ports SPI + 1 I/O-Port
Expander 74*595, CD4094, ... N
maximaler Datendurchsatz
in kByte pro Sekunde und MHz
10 37

Mit einer CPU-Frequenz von 16MHz hat man also mit der Hardware-Variante einen maximalen Durchsatz von ca. 590 kByte/Sekunde, und 160kByte/Sekunde mit der reinen Software-Variante.

Kleinkram:

  • evtl. Pullup/Pulldown-Widerstand: 20kΩ
  • Widerstände zum Entkoppeln vom ISP: einige kΩ
  • evtl. Kondensatoren von 100pF zum Entstören der Datenleitungen
  • Strom für die Versorgung im Bereich von µA bis wenige mA (je nach Expander-Typ, Anzahl und Frequenz)

Schaltplan

Anschlussplan
Portexpander 74595 an AVR.png
Das umstrichelte Modul
kann einfach so oft nach rechts wiederholt werden, bis es soviele Ausgänge hat, wie gewünscht. Die Bits wandern über Pin 14 (SER) in den Expander. Acht Takte später erscheint das Bit wieder an Pin 9 (QH*) und damit am SER-Eingang des folgenden Expanders.
R1
ist ein Pullup-Widerstand, der während des ISP-Programmierens dafür sorgt, daß RCK nicht floatet, denn während der Programmierung sind die AVR I/O-Leitungen hochohmig. Dadurch bleiben die Ausgänge der Expander stabil (MOSI und SCK wackeln natürlich beim Programmierern).
R2, R3
entkoppeln den ISP-Adapter. Ansonsten stören sie nicht weiter, denn beim Programmieren muss praktisch kein Strom fliessen – abgesehen vom minimalen Leckstrom der Ports und Füllen der Portkapazität von ein paar pF.
Eingang G (Pin13)
ist hier auf LOW verdrahtet. Falls gewünscht, kann er verwendet werden, um die Ausgänge der Expander hochohmig zu schalten (high-Z). Dann wird natürlich einen weiteren µC-Port benötigt, um das zu tun. Falls an den Expandern LEDs zum Einsatz kommen sollen, kann G auch mit einem PWM-Ausgang des µC verdrahtet werden, um die Anzeige dimmen zu können. Im Falle eines PWM-Betriebs ist darauf zu achten, daß durch das gleichzeitige Schalten vieler Ausgänge/Lasten die Betriebsspannung "sauber" bleibt, indem man etwa auf ausreichend große Abblock-Kondensatoren an den Expandern achtet oder andere Maßnahmen zur hinreichenden Stabilisierung der Versorgungsspannung ergreift.

Ports

Ohne Nutzung der SPI-Hardware gibt es die freie Auswahl, welche Ports verwendet werden sollen. Natürlich ist auch die Verwendung der SPI/ISP-Ports in jeder beliebigen Anordnung möglich und das Signal "SCK" muss nicht an Port "SCK" angeschlossen sein. Einzig auf das Signal RCK sollte man achten, denn falls es zugleich durch den ISP verwendet wird, flattern beim Programmieren möglicherweise die Expander-Ausgänge.

Bei der Hardware-Version ist man auf die SPI-Pins MOSI (Master Out, Slave IN) und SCK (SPI Clock) festgelegt, mit Ausnahme von RCK. Das kann irgendein Port sein (ausser MISO, das bei aktiviertem SPI immer Input ist). Im Beispiel ist RCK an SS (SPI Slave Select) angeschlossen.

Falls SS nicht in dieser Weise verwendet wird, muss auf jeden Fall dafür gesorgt werden, daß SS entweder auf OUT steht, oder nie auf LOW geht, da sonst SPI in den Slave-Modus schaltet!

Signalfolge

Signalfolge-Portexpander.png

Nachdem das auszugebende Bit an SER/MOSI ausgegeben wurde, wird es mit einem low-Strobe an SCK ins Schieberegister übernommen und alle Bits wandern um eine Position weiter. Nachdem so alle Bits ausgegeben wurden und an ihrer Position sind, werden die Bits durch ein Strobe an RCK an die Ausgänge gelegt und bleiben dort, bis sie wieder überschrieben werden.

C-Code

Der folgende C-Code ist Pseudocode, was Setzen der Ports angeht. Die entsprechenden Befehle sind durch die richtigen C-Befehle für diese Ports zu ersetzen.

MAKE_OUT (X)
Schaltet X als Ausgang (DDR-Register)
SET (X)
Setzt Ausgang X auf HIGH (PORT-Register)
CLR (X)
Setzt Ausgang X auf LOW (PORT-Register)
Tabelle: Resourcen-Verbrauch mit N ICs
Resource ohne SPI mit SPI
Interrupts keine
Flash (Bytes mit -Os) 52 44
SRAM (statisch) N
SRAM (Stack) 2
Laufzeit serpa_out() 19 + 101*N 16 + 27*N
SCK-Frequenz ~fcpu/9 fcpu/2

Makros, Datenstrukturen, Funktionen

#define SERPA_SIZE
Define für Anzahl der auszugebenden Bytes
extern unsigned char serpa[SERPA_SIZE]
Das Array, dessen Bytes ausgegeben werden. serpa[0] landet in dem Portexpander-IC, das direkt am Controller sitzt. Bit0 erscheint jeweils an Ausgang QA, Bit7 erscheint am Ausgang QH, etc.
void serpa_init(void)
Initialisiert die Schnittstelle bzw. die verwendeten Ports
void serpa_out(void)
Gibt die SERPA_SIZE Bytes aus dem Array serpa aus.

serpa.h

/* SERiell nach PArallel (serpa) im SPI-Protokoll */
#ifndef SERPA_H
#define SERPA_H

/* 4 Bytes (32 Ports) */
#define SERPA_SIZE 4

extern unsigned char serpa[];
extern void serpa_out (void);
extern void serpa_init (void);

#endif /* SERPA_H */

Mit SPI-Hardware

Das Senden erfolgt, ohne den SPI-Interrupt zu nutzen. Allein der ISR-Prolog/Epilog dauert schon so lange, wie ein Schleifendurchlauf.

serpa.c

// SERiell nach PArallel (serpa) mit Hardware-Unterstuetzung 
#include <avr/io.h>
#include "serpa.h"

// Array fuer die Daten 
unsigned char serpa[SERPA_SIZE];

void serpa_init (void)
{
   MAKE_OUT (PORT_MOSI); 
   MAKE_OUT (PORT_SCK);
   MAKE_OUT (PORT_RCK); SET (PORT_RCK);

   // !!! SS muss OUT sein, damit SPI nicht in Slave-Mode wechselt !!! 
   // entfaellt, falls PORT_RCK = PORT_SS 
   MAKE_OUT (PORT_SS);

   // SPI als Master 
   // High-Bits zuerst 
   // SCK ist HIGH wenn inaktiv 
   SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL);
	
   // pullup an MISO vermeidet Floaten 
   SET (PORT_MISO);

   // maximale Geschwindigkeit: F_CPU / 2 
   SPSR |= (1 << SPI2X);
}

void serpa_out (void)
{
   unsigned char anz = SERPA_SIZE;
   unsigned char* serp = serpa+SERPA_SIZE;

   do
   {
      unsigned char data = *--serp;

      // SPDR schreiben startet Uebertragung 
      SPDR = data;

      // warten auf Ende der Uebertragung für dieses Byte 
      while (!(SPSR & (1 << SPIF)));

      // clear SPIF durch Lesen von SPDR 
      (void) SPDR;
   }
   while (--anz > 0);

   // Strobe an RCK bringt die Daten von den Schieberegistern in die Latches 
   CLR (PORT_RCK);
   SET (PORT_RCK);
}

Ohne SPI-Hardware

Dieser Code funktioniert auch für jeden anderen µC-Typ, der mindestend 3 digitale I/O-Ausgangsports hat, und mit einem Compiler für Standard-C übersetzt wird. Die Pseudocodes MAKE_OUT, SET und CLR sind auch hier an die jeweilige Schaltung/Architektur/Compiler/Controller anzupassen.

serpa.c

/* SERiell nach PArallel (serpa) via Software */
#include "serpa.h"

/* Array fuer die Daten */
unsigned char serpa[SERPA_SIZE];

void serpa_init (void)
{
    /* Verwendete Ports auf OUT */
    MAKE_OUT (PORT_SER);
    MAKE_OUT (PORT_SCK);
    MAKE_OUT (PORT_RCK);

    /* SCR und RCK auf definierten Level HIGH */
    SET (PORT_SCK);
    SET (PORT_RCK);
}

void serpa_out (void)
{
    unsigned char anz = SERPA_SIZE;
    unsigned char* serp = serpa+SERPA_SIZE;

    do
    {
        unsigned char bits;
        unsigned char data = *--serp;

        /* 8 Bits pro Byte rausschieben */
        for (bits = 8; bits > 0; bits--)
        {
            CLR (PORT_SER);
            if (data & 0x80)
            {
                SET (PORT_SER);
            }

            data <<= 1;
            /* Strobe an SCK schiebt Daten im Gaensemarsch */
            /* um 1 Position weiter durch alle Schieberegister */
            CLR (PORT_SCK);
            SET (PORT_SCK);
        }
    }
    while (--anz > 0);

    /* Strobe an RCK bringt die Daten von den Schieberegistern in die Latches */
    CLR (PORT_RCK);
    SET (PORT_RCK);
}

BASCOM-Code

Mit SPI-Hardware

serpa.bas

' SERiell nach PArallel (serpa) mit Hardware-Unterstuetzung
' Beispiel mit 2 Datenbytes

' SPI Bus (Hardware) als Master konfiguiren
Config SPI = Hard , Master = Yes

' SPI Bus initialisieren
' setzt das DDR Register entsprechend
Spiinit

' Bytes für die Daten
Dim Serpa(2) As Byte
Serpa(1) = &B10101010
Serpa(2) = &B00000000

' Die Bytes auf den SPI Bus schieben
Spiout Serpa(1) , 2

Expander

Von den meisten Expandern gibt es auch Unterversionen, wie 74HC (Highspeed CMOS), 74HCT (Highspeed CMOS, TTL-Compatible), etc. Hier tut's z.B. 74HC. Pro Expander fallen Kosten von ca 30-40 Cent an (Reichelt). Ungelatchte Register wie 74*164 sind übrigens nicht zu empfehlen, weil bei deren Verwendung wäherend des Schiebens die Ausgänge flattern.

Die Verwendete SPI-Frequenz ist unkritisch und kann natürlich auch langsamer eingestellt werden. Taktfrequenzen von 50MHz sind für die ICs normalerweise kein Problem. Die steilen Flanken können aber ein Problem bei längeren Kabeln werden.

8-Bit Schieberegister mit Ausgangs-Latch
74*594
Shift Clear, Latch Clear, Tri-State
74*595
Shift Clear, Tri-State
74*596
Shift Clear, Open Collector/high-Z
CD4094, 74*4094
Tri-State
8-Bit Schieberegister mit Eingangs-Latch
74*589
Tri-State
74*597
Shift Clear

Siehe auch

Weblinks


LiFePO4 Speicher Test