<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gerry77</id>
		<title>RN-Wissen.de - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gerry77"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Gerry77"/>
		<updated>2026-04-11T22:39:40Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Portexpander_am_AVR&amp;diff=5725</id>
		<title>Portexpander am AVR</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Portexpander_am_AVR&amp;diff=5725"/>
				<updated>2006-01-30T21:53:17Z</updated>
		
		<summary type="html">&lt;p&gt;Gerry77: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;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&amp;amp;sup2;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. &lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
= Pro &amp;amp; Contra =&lt;br /&gt;
&lt;br /&gt;
;Vorteile:&lt;br /&gt;
* schnell&lt;br /&gt;
* preiswert&lt;br /&gt;
* einfach anzusteuern (auch ohne Hardware-Unterstützung, deutlich einfacher als I&amp;amp;sup2;C)&lt;br /&gt;
* Ansteuerung ohne Interrupt-Programmierung&lt;br /&gt;
* modular aufgebaut und erweiterbar&lt;br /&gt;
* '''alle''' Ports können '''gleichzeitig''' geschaltet werden, auch 100 Stück&lt;br /&gt;
* SPI-Interface und [[In System Programming|ISP-Pins]] (die oft ungenutzt bleiben) können verwendet werden&lt;br /&gt;
* Bus hat nur 3 Leitungen, dadurch kein kompliziertes Layout mit vielen Leitungen&lt;br /&gt;
* Hardware bzw. Code der Version ohne Hardware-Unterstützung ist auch auf anderen Controllertypen als AVR verwendbar (sofern die Ausgangspegel passen).&lt;br /&gt;
* Test der Schaltung direkt am PC möglich, falls man Zugriff auf den Parallelport oder [[RS232]] ('''Pegelanpassung erforderlich!''' z.B MAX232, Widerstände &amp;amp; [[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.&lt;br /&gt;
&lt;br /&gt;
;Nachteile&lt;br /&gt;
* bei dieser Version nur Ausgabe möglich&lt;br /&gt;
* soll ein Ausgangs-Port geändert werden, müssen ''alle'' Daten neu gesendet werden &lt;br /&gt;
* bei der Variante mit SPI-Hardware liegt MISO brach bzw ist nicht so einfach nutzbar zu machen&lt;br /&gt;
&lt;br /&gt;
=Resourcen=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Resourcen-Verbrauch mit'''&amp;amp;nbsp;''N''&amp;amp;nbsp;'''ICs'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!| Resource                      || ohne SPI || mit SPI&lt;br /&gt;
|-&lt;br /&gt;
| AVR-Peripherie                 || 3 I/O-Ports    || SPI + 1 I/O-Port&lt;br /&gt;
|- &lt;br /&gt;
| Expander 74*595, CD4094, ...   || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot;| ''N''&lt;br /&gt;
|- &lt;br /&gt;
| maximaler Datendurchsatz&amp;lt;br/&amp;gt; in kByte pro Sekunde und MHz &lt;br /&gt;
| 10 || 37&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''Kleinkram:'''&lt;br /&gt;
* evtl. Pullup/Pulldown-Widerstand: 20k&amp;amp;Omega;&lt;br /&gt;
* Widerstände zum Entkoppeln vom ISP: einige k&amp;amp;Omega;&lt;br /&gt;
* evtl. Kondensatoren von 100pF zum Entstören der Dateinleitungen&lt;br /&gt;
* Strom für die Versorgung im Bereich von µA bis wenige mA (je nach Expander-Typ, Anzahl und Frequenz)&lt;br /&gt;
&lt;br /&gt;
=Schaltplan=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Anschlussplan'''&lt;br /&gt;
| [[Bild:Portexpander_74595_an_AVR.png]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
;Das umstrichelte Modul: kann einfach so oft nach rechts wiederholt werden bis man so viele Ausgänge hat wie gewünscht.&lt;br /&gt;
;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).&lt;br /&gt;
;R2, R3: entkoppeln den ISP-Adapter. Ansonsten stören sie nicht weiter, denn beim Proggen muss praktisch kein Strom fliessen &amp;amp;ndash; abgesehen vom minimalen Leckstrom der Ports und Füllen der Portkapazität von ein paar pF.&lt;br /&gt;
; 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.&lt;br /&gt;
&lt;br /&gt;
=Ports=&lt;br /&gt;
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 &amp;quot;SCK&amp;quot; muss nicht an Port &amp;quot;SCK&amp;quot; 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.&lt;br /&gt;
&lt;br /&gt;
Bei der Hardware-Version ist man auf die SPI-Pins &lt;br /&gt;
'''MOSI''' (Master Out, Slave IN) und&lt;br /&gt;
'''SCK''' (SPI Clock)&lt;br /&gt;
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. &lt;br /&gt;
{{FarbigerRahmen |&lt;br /&gt;
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!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=Signalfolge=&lt;br /&gt;
[[Bild:Signalfolge-Portexpander.png|center]]&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=C-Code=&lt;br /&gt;
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.&lt;br /&gt;
;MAKE_OUT (X): Schaltet X als Ausgang (DDR-Register)&lt;br /&gt;
;SET (X): Setzt Ausgang X auf HIGH (PORT-Register)&lt;br /&gt;
;CLR (X): Setzt Ausgang X auf LOW (PORT-Register)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Resourcen-Verbrauch mit'''&amp;amp;nbsp;''N''&amp;amp;nbsp;'''ICs'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!| Resource                      || ohne SPI || mit SPI&lt;br /&gt;
|-&lt;br /&gt;
| Interrupts                     || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot;| keine&lt;br /&gt;
|- &lt;br /&gt;
| Flash (Bytes mit &amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;) || 52                || 44&lt;br /&gt;
|- &lt;br /&gt;
| SRAM (statisch)                || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot;| ''N''&lt;br /&gt;
|- &lt;br /&gt;
| SRAM (Stack)                   || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot;| 2&lt;br /&gt;
|-&lt;br /&gt;
| Laufzeit &amp;lt;tt&amp;gt;serpa_out()&amp;lt;/tt&amp;gt;  || 19 + 101*''N''    || 16 +  27*''N''&lt;br /&gt;
|-&lt;br /&gt;
| SCK-Frequenz                   ||  ~''f''&amp;lt;sub&amp;gt;cpu&amp;lt;/sub&amp;gt;/9 || ''f''&amp;lt;sub&amp;gt;cpu&amp;lt;/sub&amp;gt;/2&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Makros, Datenstrukturen, Funktionen==&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SERPA_SIZE&amp;lt;/tt&amp;gt;: Define für Anzahl der auszugebenden Bytes&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern unsigned char serpa[SERPA_SIZE]&amp;lt;/tt&amp;gt;: Das Array, dessen Bytes ausgegeben werden. &amp;lt;tt&amp;gt;serpa[0]&amp;lt;/tt&amp;gt; landet in dem Portexpander-IC, das direkt am Controller sitzt. Bit0 erscheint jeweils an Ausgang QA, Bit7 erscheint am Ausgang QH, etc.&lt;br /&gt;
;&amp;lt;tt&amp;gt;void serpa_init()&amp;lt;/tt&amp;gt;: Initialisiert die Schnittstelle bzw. die verwendeten Ports&lt;br /&gt;
;&amp;lt;tt&amp;gt;void serpa_out()&amp;lt;/tt&amp;gt;: Gibt die &amp;lt;tt&amp;gt;SERPA_SIZE&amp;lt;/tt&amp;gt; Bytes aus dem Array &amp;lt;tt&amp;gt;serpa&amp;lt;/tt&amp;gt; aus.&lt;br /&gt;
&lt;br /&gt;
'''serpa.h'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* SERiell nach PArallel (serpa) im SPI-Protokoll */&lt;br /&gt;
#ifndef _SERPA_H_&lt;br /&gt;
#define _SERPA_H_&lt;br /&gt;
&lt;br /&gt;
/* 4 Bytes (32 Ports) */&lt;br /&gt;
#define SERPA_SIZE 4&lt;br /&gt;
&lt;br /&gt;
extern unsigned char serpa[];&lt;br /&gt;
extern void serpa_out();&lt;br /&gt;
extern void serpa_init();&lt;br /&gt;
&lt;br /&gt;
#endif /* _SERPA_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mit SPI-Hardware == &lt;br /&gt;
&lt;br /&gt;
Das Senden erfolgt ohne den SPI-Interrupt zu nutzen. Allein der ISR-Prolog/Epilog dauert schon so lange wie ein Schleifendurchlauf.&lt;br /&gt;
&lt;br /&gt;
'''serpa.c'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// SERiell nach PArallel (serpa) mit Hardware-Unterstützung&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;serpa.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// Array für die Daten&lt;br /&gt;
unsigned char serpa[SERPA_SIZE];&lt;br /&gt;
&lt;br /&gt;
void serpa_init()&lt;br /&gt;
{&lt;br /&gt;
   MAKE_OUT (PORT_MOSI); &lt;br /&gt;
   MAKE_OUT (PORT_SCK);&lt;br /&gt;
   MAKE_OUT (PORT_RCK); SET (PORT_RCK);&lt;br /&gt;
&lt;br /&gt;
   // !!! SS muss OUT sein, damit SPI nicht in Slave-Mode wechselt !!!&lt;br /&gt;
   // entfällt, falls PORT_RCK = PORT_SS  &lt;br /&gt;
   MAKE_OUT (PORT_SS);&lt;br /&gt;
&lt;br /&gt;
   // SPI als Master&lt;br /&gt;
   // High-Bits zuerst&lt;br /&gt;
   // SCK ist HIGH wenn inaktiv&lt;br /&gt;
   SPCR = (1 &amp;lt;&amp;lt; SPE) | (1 &amp;lt;&amp;lt; MSTR) | (1 &amp;lt;&amp;lt; CPOL);&lt;br /&gt;
	&lt;br /&gt;
   // pullup an MISO vermeidet Floaten&lt;br /&gt;
   SET (PORT_MISO);&lt;br /&gt;
&lt;br /&gt;
   // maximale Geschwindigkeit: F_CPU / 2	 &lt;br /&gt;
   SPSR |= (1 &amp;lt;&amp;lt; SPI2X);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void serpa_out ()&lt;br /&gt;
{&lt;br /&gt;
   unsigned char anz = SERPA_SIZE;&lt;br /&gt;
   unsigned char* serp = serpa+SERPA_SIZE;&lt;br /&gt;
&lt;br /&gt;
   do&lt;br /&gt;
   {&lt;br /&gt;
      unsigned char data = *--serp;&lt;br /&gt;
&lt;br /&gt;
      // SPDR schreiben startet Übertragung&lt;br /&gt;
      SPDR = data;&lt;br /&gt;
&lt;br /&gt;
      // warten auf Ende der Übertragung für dieses Byte&lt;br /&gt;
      while (!(SPSR &amp;amp; (1 &amp;lt;&amp;lt; SPIF)));&lt;br /&gt;
&lt;br /&gt;
      // clear SPIF	&lt;br /&gt;
      data = SPDR;&lt;br /&gt;
   }&lt;br /&gt;
   while (--anz &amp;gt; 0);&lt;br /&gt;
&lt;br /&gt;
   // Strobe an RCK bringt die Daten von den Schieberegistern in die Latches&lt;br /&gt;
   CLR (PORT_RCK);&lt;br /&gt;
   SET (PORT_RCK);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ohne SPI-Hardware == &lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''serpa.c'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* SERiell nach PArallel (serpa) via Software */&lt;br /&gt;
#include &amp;quot;serpa.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/* Array für die Daten */&lt;br /&gt;
unsigned char serpa[SERPA_SIZE];&lt;br /&gt;
&lt;br /&gt;
void serpa_init ()&lt;br /&gt;
{&lt;br /&gt;
    /* Verwendete Ports auf OUT */&lt;br /&gt;
    MAKE_OUT (PORT_SER);&lt;br /&gt;
    MAKE_OUT (PORT_SCK);&lt;br /&gt;
    MAKE_OUT (PORT_RCK);&lt;br /&gt;
&lt;br /&gt;
    /* SCR und RCK auf definierten Level HIGH */&lt;br /&gt;
    SET (PORT_SCK);&lt;br /&gt;
    SET (PORT_RCK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void serpa_out ()&lt;br /&gt;
{&lt;br /&gt;
    unsigned char anz = SERPA_SIZE;&lt;br /&gt;
    unsigned char* serp = serpa+SERPA_SIZE;&lt;br /&gt;
&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        unsigned char bits;&lt;br /&gt;
        unsigned char data = *--serp;&lt;br /&gt;
&lt;br /&gt;
        /* 8 Bits pro Byte rausschieben */&lt;br /&gt;
        for (bits = 8; bits &amp;gt; 0; bits--)&lt;br /&gt;
        {&lt;br /&gt;
            CLR (PORT_SER);&lt;br /&gt;
            if (data &amp;amp; 0x80)&lt;br /&gt;
            {&lt;br /&gt;
                SET (PORT_SER);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            data &amp;lt;&amp;lt;= 1;&lt;br /&gt;
            /* Strobe an SCK schiebt Daten im Gänsemarsch      */&lt;br /&gt;
            /* um 1 Position weiter durch alle Schieberegister */&lt;br /&gt;
            CLR (PORT_SCK);&lt;br /&gt;
            SET (PORT_SCK);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--anz &amp;gt; 0);&lt;br /&gt;
&lt;br /&gt;
    /* Strobe an RCK bringt die Daten von den Schieberegistern in die Latches */&lt;br /&gt;
    CLR (PORT_RCK);&lt;br /&gt;
    SET (PORT_RCK);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Expander=&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
;8-Bit Schieberegister mit Ausgangs-Latch:&lt;br /&gt;
:;74*594: Shift Clear, Latch Clear, Tri-State&lt;br /&gt;
:;74*595: Shift Clear, Tri-State&lt;br /&gt;
:;74*596: Shift Clear, [[Open Collector]]/high-Z &lt;br /&gt;
:;CD4094, 74*4094: Tri-State&lt;br /&gt;
&lt;br /&gt;
;8-Bit Schieberegister mit Eingangs-Latch:&lt;br /&gt;
:;74*589: Tri-State&lt;br /&gt;
:;74*597: Shift Clear&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[avr-gcc]]&lt;br /&gt;
* [[Bezugsquellen]]&lt;br /&gt;
* [[I2C|I&amp;amp;sup2;C-Bus]]&lt;br /&gt;
* [[SPI|SPI-Bus]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Kommunikation]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;br /&gt;
[[Kategorie:Projekte]]&lt;/div&gt;</summary>
		<author><name>Gerry77</name></author>	</entry>

	</feed>