Forum: Mikrocontroller und Digitale Elektronik ATmega8 SPI für 74HC595 funktioniert nicht. Code?


von Stammgast (Gast)


Lesenswert?

Hi!

Beschäftige mich noch nicht so lange mit den "nackten" AVRs, habe aber 
davor etwas mit Arduino gemacht.

Nun steht das Ansteuern eines 74HC595 Schieberegisters an, dies 
funktioniert aber nicht, hoffentlich kann mir einer von euch 
weiterhelfen.

Ich denke, dass es am Code liegt.
Diesen habe ich aus dem Datenblatt bzw. aus dem Roboternetzartikel und 
die Befehle zum setzen eines Bits angepasst.

Am 74HC595 hängen an den Ausgängen a bis h LEDs mit Vorwiderständen.
Verbindung mit dem AVR ist genau wie im AVR-Tutorial unter "Ansteuerung 
per SPI-Modul".

Komisch ist auch, dass ich den ATmega nicht per ISP Flashen kann, wenn 
das Schieberegister verbunden ist. Normal?

So sieht der Code aus, es soll an den LEDs binär hochgezählt werden...
1
#include <avr/io.h>
2
#define F_CPU 1000000UL
3
#include <util/delay.h>
4
5
int data = 0x00;
6
7
void SPI_MasterInit (void)
8
{
9
  //Komplett aus dem Datenblatt übernommen
10
  DDRB = (1 << PB3);
11
  DDRB = (1 << PB5);
12
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
13
}
14
15
int main(void)
16
{
17
  while(1)
18
  {
19
    // SPDR schreiben startet Uebertragung
20
    SPDR = data;
21
22
    // warten auf Ende der Uebertragung für dieses Byte
23
    while (!(SPSR & (1 << SPIF)));
24
    
25
    
26
    // Strobe an RCK bringt die Daten von den Schieberegistern in die Latches
27
    PORTD = (0 << PB2);
28
    PORTD = (1 << PB2);
29
    
30
    data++;
31
    _delay_ms(1000);
32
  }
33
}

Liebe Grüße und schonmal danke für die Hilfe!

von Stefan (Gast)


Lesenswert?

Schaltplan fehlt

von Eumel (Gast)


Lesenswert?

Stammgast schrieb:
> PORTD = (0 << PB2);
>     PORTD = (1 << PB2);

Ist nicht als Ausgang gesetzt.

von Thomas E. (thomase)


Lesenswert?

Stammgast schrieb:
> Komisch ist auch, dass ich den ATmega nicht per ISP Flashen kann, wenn
> das Schieberegister verbunden ist. Normal?
>
Nicht normal. Überprüf mal deine Hardware.

Stammgast schrieb:
>> PORTD = (0 << PB2);
>>     PORTD = (1 << PB2);

> Ist nicht als Ausgang gesetzt.

Vor allen Dingen muss /SS als Ausgang geschaltet werden.

mfg.

von Stammgast (Gast)


Lesenswert?

Hi!

Thomas Eckmann schrieb:
> Vor allen Dingen muss /SS als Ausgang geschaltet werden.

Gute Idee ;-) Habe die Zeile
1
DDRD = (1 << PB2); //SS als Ausgang
hinzugefügt.

Dass man die Funktion "SPI_MasterInit()" dann auch noch aufrufen muss 
hab' ich natürlich auch verplant. Zum Glück studier' ich das nicht, aber 
ein Semester C war wohl bisher zu wenig :D

Habe jetzt nochmal folgendes ausprobiert:
Eine Led samt Vorwiderstand gegen GND hängt an PD6. Diese soll am Anfang 
der Übertragung eingeschaltet werden und danach wieder ausgeschaltet 
werden, damit man sieht, ob der Controller nicht irgendwo hängt.

Dabei sind mir mehrere Dinge aufgefallen:
Sobald ich die Zeile
1
DDRD = (1 << PB2); //SS als Ausgang
auskommentiere, wird die SPI_MasterInit() problemlos durchlaufen.
Wenn nicht, bleibt die LED aus.

Wenn folgende Codezeilen mit drinnen sind, geht die LED an, aber nicht 
aus. Der Controller bleibt dort irgendwie hängen?
1
// warten auf Ende der Uebertragung für dieses Byte
2
while (!(SPSR & (1 << SPIF)));
3
     
4
// Strobe an RCK bringt die Daten von den Schieberegistern in die Latches
5
PORTD = (0 << PB2);
6
PORTD = (1 << PB2);

Grüße!

von Stammgast (Gast)


Lesenswert?

Hatte ich vorhin vergessen - Flashen mit dem AVR ISP MKII über die ISP 
Schnittstelle funktioniert jetzt, keine Ahnung was da nicht gepasst hat.

Hat sonst noch einer eine Idee, woran das liegen könnte?

Grüße!

von Karl H. (kbuchegg)


Lesenswert?

Zeig halt mal deinen kompletten Code, so wie er jetzt aussieht.
Es ist immer ein wenig fehleranfällig, wenn man hier von einem 
fehlerhaften Programm ausgehend, gedanklich alle textuell beschriebenen 
Änderungen einsetzen soll und dann auch noch rausfinden soll was noch 
übersehen wurde.

von Karl H. (kbuchegg)


Lesenswert?

> DDRD = (1 << PB2); //SS als Ausgang

DDRD?
Wieso DDRD?

SS ist doch nicht am Port D


> PORTD = (0 << PB2);
> PORTD = (1 << PB2);

so macht man das aber nicht.
die erste Operation ist gleichwertig zu
PORTD = 0
die zweite Operation beeinflusst alle anderen Bits an diesem Port 
ebenso.

von katastrophenheinz (Gast)


Lesenswert?

>// Strobe an RCK bringt die Daten von den Schieberegistern in die Latches
>PORTD = (0 << PB2);
>PORTD = (1 << PB2);
Sieht komisch aus:
 PORTD = (0 << PB2); Diese Anweisung setzt alle Bits auf 0
 PORTD = (1 << PB2); Setzt Bit2, alle andere werden auf Null gesetzt

Setzen/Rücksetzen von einzelnen Bits ohne Verändern der restlichen geht 
so:

PORTD &= ~( 1 << PD2 ); <- Setzt nur Bit2 auf 0
PORTD |=  ( 1 << PD2 ); <- Setzt nur Bit2 auf 1

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

DDRB = (1 << PB3);
  DDRB = (1 << PB5);
Wie soll DAS denn auch funktionieren?
Die zwete Operation überschreibt das Register wieder.

Bei SPCR hastes dann wieder richtig gemacht oder nur von irgendwo 
zusammenkopiert.

Also schreibe:
  DDRB |= (1 << PB3);
  DDRB |= (1 << PB5);

Weiteres hier:
http://www.mikrocontroller.net/articles/Bitmanipulation


@karl:
An PORTD hat er den RCK des 595 angeschlossen und der RCK hängt wohl ned 
an SS

von Karl H. (kbuchegg)


Lesenswert?

Martin Wende schrieb:

> @karl:
> An PORTD hat er den RCK des 595 angeschlossen und der RCK hängt wohl ned
> an SS

Mag sein.
Trotzdem sollte er PB2 auf Ausgang schalten. Sonst macht die SPI 
Hardware alles mögliche, nur nicht als Master arbeiten.

von Stammgast (Gast)


Lesenswert?

Servus!

Erstmal danke vorneweg für eure Antworten.

Wie gesagt dies sind meine ersten Versuche (Nach LED blinken, etc..) mit 
den AVRs, davor nur Arduino, das hat mich wahrscheinlich verdorben...

Karl Heinz Buchegger schrieb:
> Zeig halt mal deinen kompletten Code, so wie er jetzt aussieht.
Gerne!

Ich habe versucht, alle angesprochenen Fehler zu verbessern:
1
#include <avr/io.h>
2
#define F_CPU 1000000UL
3
#include <util/delay.h>
4
5
int data = 0x00;
6
7
void SPI_MasterInit (void)
8
{
9
  //aus dem Datenblatt übernommen
10
  DDRB |= (1 << PB3); //MOSI als Ausgang
11
  DDRB |= (1 << PB5); //SCK als Ausgang
12
  DDRD |= (1 << PD6); //LED an PD6
13
  DDRB |= (1 << PB2); //SS als Ausgang
14
  SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0);
15
}
16
17
int main(void)
18
{  
19
  SPI_MasterInit();
20
  while(1)
21
  {
22
    //LED an
23
    PORTD |= (1 << PD6);
24
    //SPDR schreiben startet Uebertragung
25
    SPDR = data;
26
27
    //warten auf Ende der Uebertragung für dieses Byte
28
    while (!(SPSR & (1 << SPIF)));
29
    
30
    //Strobe an RCK bringt die Daten von den Schieberegistern in die Latches
31
    PORTB &= ~( 1 << PB2 );
32
    PORTB |=  ( 1 << PB2 );
33
    
34
    data++;
35
    
36
    _delay_ms(50);
37
    PORTD &= ~(1 << PD6);
38
    _delay_ms(500);
39
  }
40
}

RCK vom Schieberegister ist schon an SS/PB2 angeschlossen. Hatte das nur 
irgendwie falsch :-/

Funktioniert leider immer noch nicht. Ich kann nur sagen, dass der Code 
zumindest schonmal durchläuft, die LED blinkt.
Ist dies eigentlich eine passende Art, zu prüfen ob das Programm 
einigermaßen tut was es soll? Oder gibt es da intelligentere Methoden?

Grüße!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

1
    //Strobe an RCK bringt die Daten von den Schieberegistern in die Latches
2
    PORTB |=  ( 1 << PB2 );   <----------------
3
    PORTB &= ~( 1 << PB2 );

Der Übergang Low-High sorgt dafür, dass die Daten ins Latch übernommen 
werden.

Was hast du eigentlich mit dem G Pin bzw. den restlichen Pins vom 595 
gemacht?

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
1
>     //Strobe an RCK bringt die Daten von den Schieberegistern in die 
2
> Latches
3
>     PORTB |=  ( 1 << PB2 );   <----------------
4
>     PORTB &= ~( 1 << PB2 );
5
>
>
> Der Übergang Low-High sorgt dafür, dass die Daten ins Latch übernommen
> werden.

Wobei:
Das sollte eigentlich egal sein. Bei dir ist dann eben RCLK auf High 
während Daten reingetaktet werden.

> Was hast du eigentlich mit dem G Pin bzw. den restlichen Pins vom 595
> gemacht?

D.h. das Programm sieht soweit gut aus.
Jetzt sollte man sich mal die Hardware ansehen.

von Stammgast (Gast)


Lesenswert?

Hi!

Sorry, dass ich mich so spät erst wieder zurückmelde, hatte sehr viel um 
die Ohren.

Habe nun den gesamten Aufbau nochmal neu aufgebaut.
Nun funktioniert auch alles ohne Probleme. Keine Ahnung was da genau der 
Fehler war, eventuell OE auf VCC oder so.

Trotzdem danke für eure Hilfe, weil im Code gab es ja auch einige 
Ungereimtheiten...


Grüße

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.