Difference between revisions of "AVR Embedded Tutorial - SPI Shiftregister/de"
(11 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | {{ | + | {{LanguageBar}} |
+ | |||
=Schieberegister 74HC595 über SPI= | =Schieberegister 74HC595 über SPI= | ||
Line 8: | Line 9: | ||
Die folgenden Funktionen, sind in folgenden Tutorials beschrieben: | Die folgenden Funktionen, sind in folgenden Tutorials beschrieben: | ||
+ | |||
* [[AVR Embedded Tutorial - Simple GPIO on and off output/de|GPIO - Aus / Ein-gabe]] - Wie mache ich einen GPIO-Zugriff am AVR. | * [[AVR Embedded Tutorial - Simple GPIO on and off output/de|GPIO - Aus / Ein-gabe]] - Wie mache ich einen GPIO-Zugriff am AVR. | ||
* [[AVR Embedded Tutorial - SPI/de|SPI]] - Nutzung der Hardware-SPI-Schnittstelle. | * [[AVR Embedded Tutorial - SPI/de|SPI]] - Nutzung der Hardware-SPI-Schnittstelle. | ||
== Beispiel Atmega328 / Arduino Uno/Nano == | == Beispiel Atmega328 / Arduino Uno/Nano == | ||
+ | |||
=== Konstanten === | === Konstanten === | ||
+ | |||
Pins welche an PORTB für SPI benötigt werden. | Pins welche an PORTB für SPI benötigt werden. | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
const | const | ||
SPI_SlaveSelect = 2; | SPI_SlaveSelect = 2; | ||
− | + | SPI_MOSI = 3; | |
SPI_Clock = 5; | SPI_Clock = 5; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Schreiben eines Pins === | === Schreiben eines Pins === | ||
+ | |||
Beschreiben eines Pins von PORTB, wird für SlaveSelect und für die Softwareversion gebraucht. | Beschreiben eines Pins von PORTB, wird für SlaveSelect und für die Softwareversion gebraucht. | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
procedure WritePortB(Pin: byte; Value: boolean); | procedure WritePortB(Pin: byte; Value: boolean); | ||
begin | begin | ||
Line 37: | Line 44: | ||
=== Schreiben der Zeichenkette === | === Schreiben der Zeichenkette === | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
procedure WriteDataHardSPI(p: PByte; len: byte); | procedure WriteDataHardSPI(p: PByte; len: byte); | ||
var | var | ||
Line 53: | Line 61: | ||
=== Hauptprogramm === | === Hauptprogramm === | ||
+ | |||
Die Register von SPI wird auf die höchst mögliche Geschwindigkeit gestellt. | Die Register von SPI wird auf die höchst mögliche Geschwindigkeit gestellt. | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
+ | var | ||
+ | z: uint16; | ||
begin | begin | ||
// Alle Pins auf Output. | // Alle Pins auf Output. | ||
− | DDRB := (1 shl | + | DDRB := (1 shl SPI_MOSI) or (1 shl SPI_Clock) or (1 shl SPI_SlaveSelect); |
// SPI-Register einstellen. | // SPI-Register einstellen. | ||
Line 74: | Line 86: | ||
== Beispiel ATTiny2313 == | == Beispiel ATTiny2313 == | ||
− | Der '''ATTiny2313''' besitzt keine direkte SPI-Schnittstelle, dafür gibt es die universelle '''USI'''-Schnittstelle, welche hier für '''SPI''' verwendet wird. Dies ist beim Beschreiben ein wenig komplizierter als bei der direkte SPI-Schnittstelle des Atmega. | + | |
− | '''Hinweis:''' Der '''ATTiny2313''' hat auch'''MOSI''' und '''MISO'''-Anschlüsse, diese habe aber nur für den Programmer Verwendung. Dafür sind '''DO''' und '''DI''' vorhanden, welche aber genau in der umgekehrten Reihenfolge arbeiten. | + | Der '''ATTiny2313''' besitzt keine direkte SPI-Schnittstelle, dafür gibt es die universelle '''USI'''-Schnittstelle, welche hier für '''SPI''' verwendet wird. Dies ist beim Beschreiben ein wenig komplizierter als bei der direkte SPI-Schnittstelle des Atmega. |
− | + | ||
− | Pins welche an PORTB für SPI benötigt werden. | + | '''Hinweis:''' Der '''ATTiny2313''' hat auch '''MOSI''' und '''MISO'''-Anschlüsse, diese habe aber nur für den Programmer Verwendung. Dafür sind '''DO''' und '''DI''' vorhanden, welche aber genau in der umgekehrten Reihenfolge arbeiten. |
+ | |||
+ | === Deklarationen === | ||
+ | |||
+ | Pins welche an PORTB für SPI benötigt werden. | ||
+ | |||
Dafür wir ein '''bitpacked record''' verwendet, somit kann man '''direkt''' auf die Pins zugreifen. | Dafür wir ein '''bitpacked record''' verwendet, somit kann man '''direkt''' auf die Pins zugreifen. | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
type | type | ||
TSPIGPIO = bitpacked record | TSPIGPIO = bitpacked record | ||
Line 87: | Line 105: | ||
var | var | ||
SPI_PORT: TSPIGPIO absolute PORTB; | SPI_PORT: TSPIGPIO absolute PORTB; | ||
− | SPI_DDR: TSPIGPIO absolute DDRB;</syntaxhighlight> | + | SPI_DDR: TSPIGPIO absolute DDRB; |
+ | </syntaxhighlight> | ||
+ | |||
+ | Ein Funktion welche eine Zeichenkette an den SPI-Port sendet. | ||
+ | === Schreiben der Zeichenkette === | ||
− | + | <syntaxhighlight lang="pascal"> | |
− | |||
− | <syntaxhighlight> | ||
procedure SPIWriteData(p: PByte; len: byte); | procedure SPIWriteData(p: PByte; len: byte); | ||
var | var | ||
Line 110: | Line 130: | ||
end; | end; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | === Hauptprogramm === | ||
Diese Beispiel zeigt da Beschreiben von 2 kaskadierten Schieberegister. | Diese Beispiel zeigt da Beschreiben von 2 kaskadierten Schieberegister. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Es wird einfach einen Integer Wert ausgegeben. | |
− | Es wird einfach einen Integer Wert ausgegeben. | + | |
− | Man sieht auch das keine Konfiguration von '''USI''' am Anfang notwendig ist, ausser die Ports auf Ausgabe stellen. | + | Man sieht auch das keine Konfiguration von '''USI''' am Anfang notwendig ist, ausser das man die Ports auf Ausgabe stellen muss. |
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
var | var | ||
− | z: | + | z: uint16 = 0; |
begin | begin | ||
− | SPI_DDR.DataOut := True; | + | SPI_DDR.DataOut := True; |
− | SPI_DDR.Clock := True; | + | SPI_DDR.Clock := True; |
SPI_DDR.SlaveSelect := True; | SPI_DDR.SlaveSelect := True; | ||
Line 138: | Line 155: | ||
==Software Version== | ==Software Version== | ||
− | Das man SPI sehr gut auch | + | |
− | Dies ist aber um etwa den Faktor 10 langsamer als die Hardwareversion des Atmega328, dafür kann man beliebige Ports nehmen. | + | Das man SPI sehr gut auch Softwareemuliert machen kann, zeige ich es hier auch. |
+ | |||
+ | Dies ist aber um etwa den Faktor 10 langsamer als die Hardwareversion des Atmega328, dafür kann man beliebige Ports nehmen. | ||
+ | |||
Die Software-Version hat den Vorteil, sie läuft auf jedem AVR und kann auch benutzt werden, wen man mehrere SPI-Schnittstellen braucht. | Die Software-Version hat den Vorteil, sie läuft auf jedem AVR und kann auch benutzt werden, wen man mehrere SPI-Schnittstellen braucht. | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
procedure WriteDataSoftSPI(p: PByte; len: byte); | procedure WriteDataSoftSPI(p: PByte; len: byte); | ||
var | var | ||
Line 152: | Line 172: | ||
for i := 7 downto 0 do begin | for i := 7 downto 0 do begin | ||
if (p[j] and (1 shl i)) <> 0 then begin | if (p[j] and (1 shl i)) <> 0 then begin | ||
− | WritePortB( | + | WritePortB(SPI_MOSI, True); |
end else begin | end else begin | ||
− | WritePortB( | + | WritePortB(SPI_MOSI, False); |
end; | end; | ||
WritePortB(SPI_Clock, True); | WritePortB(SPI_Clock, True); | ||
Line 165: | Line 185: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | = Siehe auch = | ||
− | |||
* Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]] | * Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]] | ||
* [[AVR Embedded Tutorial - Shiftregister/de|Schieberegister]] - Wie steuere ich Schieberegister an. | * [[AVR Embedded Tutorial - Shiftregister/de|Schieberegister]] - Wie steuere ich Schieberegister an. | ||
Line 173: | Line 193: | ||
Autor: [[User:Mathias|Mathias]] | Autor: [[User:Mathias|Mathias]] | ||
− | [[Category: | + | [[Category:AVR/de]] |
− | [[Category: | + | [[Category:Arduino/de]] |
− | [[Category: | + | [[Category:Embedded/de]] |
+ | [[Category:Tutorials/de]] | ||
+ | {{AutoCategory}} |
Latest revision as of 14:58, 27 February 2020
│ Deutsch (de) │ English (en) │
Schieberegister 74HC595 über SPI
Vorwort
Es können auch andere Schieberegister angesteuert werden.
Die SPI Version hat einen grossen Vorteil gegenüber einem normalen Schieberegister, das sie etwa den Faktor 10 schneller ist (ATmega328). Dies macht sich bei einem grösseren Multiplex bemerkbar.
Die folgenden Funktionen, sind in folgenden Tutorials beschrieben:
- GPIO - Aus / Ein-gabe - Wie mache ich einen GPIO-Zugriff am AVR.
- SPI - Nutzung der Hardware-SPI-Schnittstelle.
Beispiel Atmega328 / Arduino Uno/Nano
Konstanten
Pins welche an PORTB für SPI benötigt werden.
const
SPI_SlaveSelect = 2;
SPI_MOSI = 3;
SPI_Clock = 5;
Schreiben eines Pins
Beschreiben eines Pins von PORTB, wird für SlaveSelect und für die Softwareversion gebraucht.
procedure WritePortB(Pin: byte; Value: boolean);
begin
if Value then begin
PORTB := PORTB or (1 shl Pin);
end else begin
PORTB := PORTB and not (1 shl Pin);
end;
end;
Ein Funktion welche eine Zeichenkette an den SPI-Port sendet.
Schreiben der Zeichenkette
procedure WriteDataHardSPI(p: PByte; len: byte);
var
i: byte;
begin
WritePortB(SPI_SlaveSelect, False);
for i := len - 1 downto 0 do begin
SPDR := p[i];
while (SPSR and (1 shl SPIF)) = 0 do begin
end;
end;
WritePortB(SPI_SlaveSelect, True);
end;
Hauptprogramm
Die Register von SPI wird auf die höchst mögliche Geschwindigkeit gestellt.
var
z: uint16;
begin
// Alle Pins auf Output.
DDRB := (1 shl SPI_MOSI) or (1 shl SPI_Clock) or (1 shl SPI_SlaveSelect);
// SPI-Register einstellen.
SPCR := (1 shl SPE) or (1 shl MSTR) or (%00 shl SPR);
SPSR := (1 shl SPI2X);
repeat
// Zähler hochzählen, bei Überlauf wieder auf 0.
Inc(z);
// SPI-Port beschrieben.
WriteDataHardSPI(@z, 2); // 2 Byte schreiben.
until 1 = 2;
end.
Beispiel ATTiny2313
Der ATTiny2313 besitzt keine direkte SPI-Schnittstelle, dafür gibt es die universelle USI-Schnittstelle, welche hier für SPI verwendet wird. Dies ist beim Beschreiben ein wenig komplizierter als bei der direkte SPI-Schnittstelle des Atmega.
Hinweis: Der ATTiny2313 hat auch MOSI und MISO-Anschlüsse, diese habe aber nur für den Programmer Verwendung. Dafür sind DO und DI vorhanden, welche aber genau in der umgekehrten Reihenfolge arbeiten.
Deklarationen
Pins welche an PORTB für SPI benötigt werden.
Dafür wir ein bitpacked record verwendet, somit kann man direkt auf die Pins zugreifen.
type
TSPIGPIO = bitpacked record
p0, p1, p2, p3, SlaveSelect, DataInt, DataOut, Clock: boolean;
end;
var
SPI_PORT: TSPIGPIO absolute PORTB;
SPI_DDR: TSPIGPIO absolute DDRB;
Ein Funktion welche eine Zeichenkette an den SPI-Port sendet.
Schreiben der Zeichenkette
procedure SPIWriteData(p: PByte; len: byte);
var
i: byte;
begin
SPI_PORT.SlaveSelect := False;
for i := len - 1 downto 0 do begin
USIDR := p[i];
USISR := 1 shl USIOIF;
repeat
USICR := (%01 shl USIWM) or (%10 shl USICS) or (1 shl USICLK) or (1 shl USITC);
until (USISR and (1 shl USIOIF)) <> 0;
end;
SPI_PORT.SlaveSelect := True;
end;
Hauptprogramm
Diese Beispiel zeigt da Beschreiben von 2 kaskadierten Schieberegister.
Es wird einfach einen Integer Wert ausgegeben.
Man sieht auch das keine Konfiguration von USI am Anfang notwendig ist, ausser das man die Ports auf Ausgabe stellen muss.
var
z: uint16 = 0;
begin
SPI_DDR.DataOut := True;
SPI_DDR.Clock := True;
SPI_DDR.SlaveSelect := True;
repeat
Inc(z);
SPIWriteData(@z, 2); // Integer ausgeben.
until 1 = 2;
end.
Software Version
Das man SPI sehr gut auch Softwareemuliert machen kann, zeige ich es hier auch.
Dies ist aber um etwa den Faktor 10 langsamer als die Hardwareversion des Atmega328, dafür kann man beliebige Ports nehmen.
Die Software-Version hat den Vorteil, sie läuft auf jedem AVR und kann auch benutzt werden, wen man mehrere SPI-Schnittstellen braucht.
procedure WriteDataSoftSPI(p: PByte; len: byte);
var
i, j: byte;
begin
WritePortB(SPI_SlaveSelect, False);
for j := 0 to len - 1 do begin
for i := 7 downto 0 do begin
if (p[j] and (1 shl i)) <> 0 then begin
WritePortB(SPI_MOSI, True);
end else begin
WritePortB(SPI_MOSI, False);
end;
WritePortB(SPI_Clock, True);
WritePortB(SPI_Clock, False);
end;
WritePortB(SPI_SlaveSelect, True);
end;
end;
Siehe auch
- Übersichtseite AVR Embedded Tutorial
- Schieberegister - Wie steuere ich Schieberegister an.
- SPI - Nutzung der Hardware-SPI-Schnittstelle bei einem ATmega328 / Arduino.
Autor: Mathias