K (→Resourcen) |
|||
Zeile 1: | Zeile 1: | ||
− | + | Bietet ein Controller nicht genügend I/O-Leitungen, ist eine Möglichkeit, dem zu begegnen, Portexpander zu 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. Dabe 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. | |
+ | |||
+ | = Pro & Contra = | ||
;Vorteile: | ;Vorteile: | ||
Zeile 5: | Zeile 7: | ||
* preiswert | * preiswert | ||
* einfach anzusteuern (auch ohne Hardware-Unterstützung) | * einfach anzusteuern (auch ohne Hardware-Unterstützung) | ||
+ | * Ansteuerung ohne Interrupt-Programmierung | ||
* modular aufgebaut und erweiterbar | * modular aufgebaut und erweiterbar | ||
* '''alle''' Ports können '''gleichzeitig''' geschaltet werden, auch 100 Stück | * '''alle''' Ports können '''gleichzeitig''' geschaltet werden, auch 100 Stück | ||
− | * SPI-Interface und ISP-Pins können verwendet werden | + | * 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 | * Bus hat nur 3 Leitungen, dadurch kein kompliziertes Layout mit vielen Leitungen | ||
Zeile 24: | Zeile 27: | ||
|- | |- | ||
| AVR-Peripherie || 3 I/O-Ports || SPI + 1 I/O-Port | | AVR-Peripherie || 3 I/O-Ports || SPI + 1 I/O-Port | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| Expander 74*595, CD4094, ... || colspan="2" align="center"| ''N'' | | Expander 74*595, CD4094, ... || colspan="2" align="center"| ''N'' | ||
Zeile 70: | Zeile 61: | ||
;CLR (X): Setzt Ausgang X auf LOW (PORT-Register) | ;CLR (X): Setzt Ausgang X auf LOW (PORT-Register) | ||
− | ==Makros,Datenstrukturen,Funktionen== | + | <center> |
+ | {| {{Blauetabelle}} | ||
+ | |+ '''Tabelle: Resourcen-Verbrauch mit''' ''N'' '''ICs''' | ||
+ | |- {{Hintergrund1}} | ||
+ | !| Resource || ohne SPI || mit SPI | ||
+ | |- | ||
+ | | Interrupts || colspan="2" align="center"| keine | ||
+ | |- | ||
+ | | Flash (Bytes mit <tt>-Os</tt>) || 52 || 44 | ||
+ | |- | ||
+ | | SRAM (statisch) || colspan="2" align="center"| ''N'' | ||
+ | |- | ||
+ | | SRAM (Stack) || colspan="2" align="center"| 2 | ||
+ | |- | ||
+ | | Laufzeit <tt>serpa_out()</tt> || 19 + 101*''N'' || 16 + 27*''N'' | ||
+ | |- | ||
+ | | SCK-Frequenz || ~''f''<sub>cpu</sub>/9 || ''f''<sub>cpu</sub>/2 | ||
+ | |} | ||
+ | </center> | ||
+ | |||
+ | ==Makros, Datenstrukturen, Funktionen== | ||
;<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. | ||
Zeile 93: | Zeile 104: | ||
== 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. | ||
'''serpa.c''' | '''serpa.c''' | ||
Zeile 116: | Zeile 129: | ||
// High-Bits zuerst | // High-Bits zuerst | ||
// SCK ist HIGH wenn inaktiv | // SCK ist HIGH wenn inaktiv | ||
− | SPCR = | + | SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL); |
// pullup an MISO vermeidet Floaten | // pullup an MISO vermeidet Floaten | ||
Zeile 122: | Zeile 135: | ||
// maximale Geschwindigkeit: F_CPU / 2 | // maximale Geschwindigkeit: F_CPU / 2 | ||
− | SPSR |= | + | SPSR |= (1 << SPI2X); |
} | } | ||
Zeile 206: | Zeile 219: | ||
} | } | ||
</pre> | </pre> | ||
+ | |||
+ | =Expander= | ||
+ | |||
+ | Von den meisten Expandern gibt es auch Untersersionen, 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. | ||
+ | |||
+ | 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. | ||
+ | |||
+ | ;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 | ||
+ | |||
+ | =Siehe auch= | ||
+ | * [[avr-gcc]] | ||
+ | * [[Bezugsquellen]] | ||
+ | * [[I2C|I²C-Bus]] | ||
[[Kategorie:Microcontroller]] | [[Kategorie:Microcontroller]] |
Version vom 10. Januar 2006, 14:38 Uhr
Bietet ein Controller nicht genügend I/O-Leitungen, ist eine Möglichkeit, dem zu begegnen, Portexpander zu werwenden. Dadurch hat man 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. Dabe 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.
Inhaltsverzeichnis
Pro & Contra
- Vorteile
- schnell
- preiswert
- einfach anzusteuern (auch ohne Hardware-Unterstützung)
- 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
- 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
Resourcen
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 Dateinleitungen
Schaltplan
- Das umstrichelte Modul
- kann einfach so oft nach rechts wiederholt werden bis man so viele Ausgänge hat wie gewünscht.
- 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 – 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.
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)
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()
- Initialisiert die Schnittstelle bzw. die verwendeten Ports
- void serpa_out()
- 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(); extern void serpa_init(); #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-Unterstützung */ #include <avr/io.h> #include "serpa.h" // Array für die Daten unsigned char serpa[SERPA_SIZE]; void serpa_init() { 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 !!! // entfällt, 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 () { unsigned char anz = SERPA_SIZE; unsigned char* serp = serpa+SERPA_SIZE; do { unsigned char data = *--serp; // SPDR schreiben startet Übertragung SPDR = data; // warten auf Ende der Übertragung für dieses Byte while (!(SPSR & (1 << SPIF))); // clear SPIF data = 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
serpa.c
/* SERiell nach PArallel (serpa) via Software */ #include "serpa.h" // Array für die Daten unsigned char serpa[SERPA_SIZE]; void serpa_init () { // 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 () { 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 Gänsemarsch // 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); }
Expander
Von den meisten Expandern gibt es auch Untersersionen, 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 (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.
- 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