Forum: Mikrocontroller und Digitale Elektronik Schieberegister mit SPI kaskadieren


von Thomas J. (rrurr)


Lesenswert?

Hallo an alle,

aktuell bin ich dabei mit Schieberegsistern ein wenig herum zu spielen. 
Jedoch möchte es mir nicht so ganz gelingen. Ich habe folgendes Problem:

In diesem Thread (Beitrag "LED-Matrix mit Atmega8 (16Mhz) Wieivele Schieberegiste in Reihe?") konnten 
die Probleme des Aufbaus einer 16*8-Bit-Matrix gelöst werden.
Die LEDs sollen also über 16 Schieberegister angesprochen werden, welche 
alle hintereinander geschaltet sind. Die Schieberegister sollen wiederum 
von dem SPI des Atmega8 angesprochen werden.

Jetzt habe ich mir mal probehalber auf einem Breadboard 2 
Schieberegister, wie auf diesem Bild: 
http://www.mikrocontroller.net/attachment/169521/spi.png 
zusammengesteckt.

Mir fehlt jedoch der passende C Code. Im AVR-Schieberegister-Tutorial 
ist alles nur in Assembler angegeben, womit ich nicht wirklich klar 
komme.

Perfekt wäre es, wenn ich eine Funktion hätte, die alles nötige 
initialisiert und eine, der ich einen 8-Bit-Wert (z.B. 0b01100110) 
übergebe, welcher dann in das erste Register geschoben wird. Beim 
zweiten Aufruf würde dann der erste Wert in das zweite Register 
geschoben werden und der zweite Wert (z.B. 0b10011001) in das erste 
Register.

So dass ich die Fuktion theoretisch für beliebig viele Register nutzen 
könnte. Ist das möglich? Bzw. weiß jemand wo ich dafür die nötigen 
Infos/Codeschnippsel herbekomme?

Gruß

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas J. schrieb:

> Mir fehlt jedoch der passende C Code. Im AVR-Schieberegister-Tutorial
> ist alles nur in Assembler angegeben, womit ich nicht wirklich klar
> komme.

Naja, wenn du ein Hardware-SPI hast, dann greift der code doch
nur auf die paar SPI-Register zu.  Ob man das nun in Assembler oder
C aufschreibt, ist kein großer Unterschied.

> Perfekt wäre es, wenn ich eine Funktion hätte, die alles nötige
> initialisiert

Du musst das MSTR-Bit in SPCR setzen und ggf. die Taktrate.

> und eine, der ich einen 8-Bit-Wert (z.B. 0b01100110)
> übergebe, welcher dann in das erste Register geschoben wird.

Das ist einfach nur ein Schreibvorgang auf SPDR.  Braucht man dafür
eine Funktion?

Ach so, vorher musst du noch schauen, ob die vorhergehende
Transaktion bereits beendet ist (SPIF-Bit muss wieder 1 sein).

> Beim
> zweiten Aufruf würde dann der erste Wert in das zweite Register
> geschoben werden und der zweite Wert (z.B. 0b10011001) in das erste
> Register.

Ja, genau so funktionieren kaskadierte Schieberegister.

Allerdings würde ich (anders als im von dir gezeigten Bild) den
Ladeeingang der Schieberegister nicht fest auf Vcc verdrahten,
sondern auf einen Portpin legen.  Andernfalls "wackeln" alle
angeschlossenen Ausgänge während der Aktualisierung mit (da werden
die einzelnen Bytes ja durch die Register hindurch geschoben).
Wenn man fertig ist und alle Register mit ihren Werten geladen sind,
gibt man einfach einen kurzen Impuls an den Ladeeingang der '595.
Erst durch diesen Impuls übernehmen die parallelen Ausgänge die
Information aus dem seriellen Register.

von Falk B. (falk)


Lesenswert?

@  Thomas J. (rrurr)

>Mir fehlt jedoch der passende C Code. Im AVR-Schieberegister-Tutorial
>ist alles nur in Assembler angegeben, womit ich nicht wirklich klar
>komme.

Das ist eine gute Einstiegsaufgabe. Entweder "per Hand" und 
Bitmanipulation oder direkt mit dem SPI Modul. Das ist nicht 
schwer zu benutzen.

>So dass ich die Fuktion theoretisch für beliebig viele Register nutzen
>könnte. Ist das möglich?

Ja.

> Bzw. weiß jemand wo ich dafür die nötigen
> Infos/Codeschnippsel herbekomme?

"Nur selber denken macht geistig fett". Gerade als Anfänger muss man 
eigentlich alles mal selber gemacht haben, um dabei was zu lernen.

von Thomas J. (rrurr)


Lesenswert?

Jörg Wunsch schrieb:
> Allerdings würde ich (anders als im von dir gezeigten Bild) den
> Ladeeingang der Schieberegister nicht fest auf Vcc verdrahten,
> sondern auf einen Portpin legen.  Andernfalls "wackeln" alle
> angeschlossenen Ausgänge während der Aktualisierung mit (da werden
> die einzelnen Bytes ja durch die Register hindurch geschoben).
> Wenn man fertig ist und alle Register mit ihren Werten geladen sind,
> gibt man einfach einen kurzen Impuls an den Ladeeingang der '595.
> Erst durch diesen Impuls übernehmen die parallelen Ausgänge die
> Information aus dem seriellen Register.

Was meinst du mit "Ladeeingang"? Den Pin "SCL"? Da habe ich mich an das 
Tutorial gehalten 
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_Schieberegister#Ansteuerung_per_SPI-Modul), 
in dem es heißt: "Hier wird der Pin SCL nicht benutzt, da das praktisch 
keinen Sinn hat. Er muss also fest auf VCC gelegt werden."

Was ich auch nicht ganz verstanden habe ist der folgende Abschnitt:
"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. ..."

Heißt das, dass ich zwischen SS-Pin des AVR und dem RCK des Registers 
einen 10k-Wiederstand nach Masse legen soll?

von Falk B. (falk)


Lesenswert?

@  Thomas J. (rrurr)

>Was meinst du mit "Ladeeingang"? Den Pin "SCL"? Da habe ich mich an das
>Tutorial gehalten

Ist OK, das war eine Irrtum.

>(http://www.mikrocontroller.net/articles/AVR-Tutori...),
>in dem es heißt: "Hier wird der Pin SCL nicht benutzt, da das praktisch
>keinen Sinn hat. Er muss also fest auf VCC gelegt werden."

Passt. Das Pin löscht das Schieberegister, eine Funktion, die man 
praktisch nie braucht. Einfach 0x00 reinschieben tut's auch.

>Heißt das, dass ich zwischen SS-Pin des AVR und dem RCK des Registers
>einen 10k-Wiederstand nach Masse legen soll?

Nicht ZWISCHEN, die Verbindung ist direkt. Aber zwischen dem Pin und VCC 
kommt zusätzlich ein Widerstand, Pull-Up genannt.

von Thomas J. (rrurr)


Angehängte Dateien:

Lesenswert?

Also ich habe das mit dem 10k-Widerstand nun so gelöst:


Pin SS: o------------------o Pin RCK
auf              |           auf
dem              |           dem
AVR              |           Register
                [ ]
                [ ] 10k
                [ ]
                 |
                 |
                 v
                VCC (5V)


Im Anhang mal mein Programm-Code für ein Register. Der Code läuft auch 
soweit, allerdings nicht ganz stabil, das heißt, dass die LEDs mal 
angehen und nach ein paar Sek wieder aus. Jedoch nicht schlagartig, 
sondern Regel sich (wie bei PWM) runter...
Hat jemand 'ne Anhnung woran das liegen könnte?

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Thomas J. schrieb:

> Hat jemand 'ne Anhnung woran das liegen könnte?

Gewöhn dir an, dass du in main() immer eine Hauptschleife hast. Wenn es 
in der Hauptschleife nichts mehr zu tun gibt, dann ist die halt leer. 
Aber Hauptschleife willst du haben! Immer. Du willst nicht, dass main() 
jemals verlassen wird.

in setAllOut möchtest du einen sauberen Puls erzeugen.
D.h. Pin auf High setzen, Pin auf Low setzen.
Dann hast du einen korrekten Puls. Pin nur auf High setzen ist kein 
Puls.

1
void setAllOut(void)
2
{
3
  PORTB |= (1<<SS);
4
  PORTB &= ~(1<<SS);
5
}
6
7
int main(void)
8
{
9
  init();
10
  transmit(0b11111111);
11
  setAllOut();
12
13
  while( 1 )
14
  {
15
  }
16
 
17
  return(0);

von Thomas J. (rrurr)


Angehängte Dateien:

Lesenswert?

Die Methode "void setAllOut(void)" habe ich geändert, ergibt schon Sinn 
was du geschrieben hast. Danke für den Hinweis.

Die Schleife habe ich ebenfalls eingebaut. Tortzdem löst das mein 
Problem leider nicht.

Abgesehen, davon, dass die LEDs einfach ausgehen, habe ich noch den 
folgenden Effekt beobachtet (siehe Anhang).

von Karl H. (kbuchegg)


Lesenswert?

Sieht mir nach einem Wackelkontakt oder zumindest einem schlechten 
Kontakt irgendwo aus.

von Thomas J. (rrurr)


Lesenswert?

Scheint in der Tat nur ein Wackelkontakt zu sein. Naja, für einen 
Prototypen nicht so tragisch. Die LED-Matrix wird dann fest verlötet 
sein.

Damit wäre jetzt alle Probleme behoben und ich kann mit dem Löten 
beginnen.

Ich danke euch für die Hilfestellungen und Tipps!

Gruß

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
>>Was meinst du mit "Ladeeingang"? Den Pin "SCL"? Da habe ich mich an das
>>Tutorial gehalten
>
> Ist OK, das war eine Irrtum.

Danke für die Korrektur, Falk.  Ich hatte dann gestern keine Zeit
mehr, mir das nochmal genau anzusehen, und hatte aufgrund des "CL"
auf "clock" getippt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.