www.mikrocontroller.net

Forum: Compiler & IDEs Atmega8 mit MAX7221 über SPI


Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ist bin ein totaler Anfänger im Bereich Microprozessoren.
Ich will mit einem Atmega8 und einem Max7221 eine LED-Lichtleichte
realisieren. Von der Hardware ist alles Fertig.
Die Verdrahtung:

Atmega8             MAX7221
PIN17 PB3(MOSI) -> PIN1 DIN
PIN19 PB5 (CLK) -> PIN13 CLK
PIN16 PB2 (SS)  -> PIN12 LOAD(CS)

Strom und der Rest ist alles Klar.
So nun habe ich verschiedene Varianten hier gefunden wie man Daten
senden kann aber irgendwie kommt nichts an an dem MAX7221 der Atmel
sendet nix. Wenn ich den Atmel mit PonyProg beschreibe kann ich mit
meinem Messgerät Spannungsschankungen feststellen am MOSI aber der
Atmel selbt sendet nichts.

Das ist mein derzeitiger Code:
_______________________________________________________
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

int main()
{
 DDRB = (1<<PB3)|(1<<PB5); // MOSI,SCK als Output, MISO als Input
 SPCR = (1<<SPE)|(1<<MSTR); // SPI enable, Master Mode

 for(;;)
 {
  SPDR = Fxff; // 10101010
  while(!(SPSR & (1<<SPIF))); // warte bis Byte gesendet
 }
};
_______________________________________________________

Ich hoffe ihr könnt mir helfen. Hab echt keinen plan was ich genau
machen soll.

Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir keiner helfen?

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Du musst bei der SPI-Schnittstelle den SS-Pin per Hand bedienen. Also:

* vor der Übertragung SS auf Low
* Daten in SPDR schreiben
* warten, bis SPI fertig ist
* SS wieder auf High

Damit überträgst Du EIN Byte an den 7221. Kann sein, dass der 7221
mehrere Bytes hintereinander braucht (->Datenblatt), dann muss das SS
während der ganzen Zeit auf High bleiben.

Was soll bitte diese Zeile:
  SPDR = Fxff; // 10101010
Hast Du Fxff irgendwo definiert - und wie?
Oder hast Du Dich verschrieben und meinst 0xFF? Warum übersetzt dann
gcc korrekt? Wenn Du 0xff ausgibst, dann ändert sich (natürlich) nichts
am MOSI-Pin, der bleibt dann die ganze Zeit High. Bei anderen Werten
wird Messgerät wohl eine konstante Gleichspg anzeigen.

Gruß, Stefan

Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke. das ist mein code zurzeit es scheint sogar was zu passieren =)
Aber die Anzeige zeigt noch nicht das an was ich will.

________________________________________________________
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

void spi_senden(unsigned);

int main()
{
 DDRB = (1<<PB3)|(1<<PB5)|(1<<PB2); // MOSI,SCK als Output
 PORTB =(1<<PB2); //SS auf High
 SPCR = (1<<SPE)|(1<<MSTR); // SPI enable, Master Mode

  spi_senden(0x0F00); // Displaytest ausschalten , Tabelle 9 / 2
  spi_senden(0x0B07); // Anzahl Digits (Segmetbausteine ) Tabelle 7
  spi_senden(0x0C01); // Display auf Normal Operation , Tabelle 3
  spi_senden(0x0900); // Decode-Mode (BCD-CODE für die mitleren 4)
Tabelle 4

 for(;;)
 {
  spi_senden(0x0100);
 }
};


void spi_senden(unsigned daten)
{
  PORTB =(1<<PB2);
  SPDR = daten;
  while(!(SPSR & (1<<SPIF))); // warte bis Byte gesendet
  PORTB =(0<<PB2);
}

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Aber die Anzeige zeigt noch nicht das an was ich will.

Hmm - daraus ergeben sich gleich 2 Fragen:
* was willst Du?
* was zeigt sie tatsächlich an?
-> Fehler- und Unfallmeldungen immer möglichst präzise ...

Nachdem ich mal im Datenblatt geschaut habe:

der 7221 erwartet 16 Bit SPI-Daten. D.h. Du musst:
* vor der Übertragung SS auf Low
* Daten(high) in SPDR schreiben
* warten, bis SPI fertig ist
* Daten(low) in SPDR schreiben
* warten, bis SPI fertig ist
* SS wieder auf High

Entweder Du übergibst Deinem spi_senden also 2 8-Bit-Werte (High und
Low), was einfacher zu programmieren ist, einen 16-Bit-Wert und trennst
diesen in spi_senden in High- und Low auf.


Etwas ganz anderes:

> PORTB =(1<<PB2);

Im Moment ist es wohl (noch) nicht Dein Problem, aber es kann später zu
einem werden:
Diese Zeile setzt den GESAMTEN Port B, und zwar auf 0000 0100 binär.
Sobald Du die anderen Pins auch benutzst, hast Du ein Problem.
Deshalb:
* zu Setzen eines Portpins verODERn:
  PORTB |= (1<<PB2);
* zum Löschen eines Portpins verUNDen:
  PORTB &= ~(1<<PB2);

Beispiel 1: Portpin setzen
angenommen, PORTB ist 1111 0000 binär.
1 << PB2  entspricht 0000 0100 binär (nämlich 1 um 2 Binärstellen links
geschoben).
PORTB |= (1<<PB2) entspricht:      1111 0000 (Annahme von oben)
                              ODER 0000 0100 (1 << PB2)
                                 = 1111 0100 (neuer Portzustand)

Beispiel 2: Portpin löschen
angenommen, PORTB ist 1111 0100 binär.
(1 << PB2)  entspricht 0000 0100 binär (nämlich 1 um 2 Binärstellen
links geschoben).
~(1 << PB2) entspricht diesem Wert negiert, also 1111 1011 binär.

PORTB &= ~(1<<PB2) entspricht:     1111 0100 (Annahme von oben)
                               UND 1111 1011 ~(1 << PB2)
                                 = 1111 0000 (neuer Portzustand)

Gruß, Stefan

Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen Dank für deine Hilfe!

>der 7221 erwartet 16 Bit SPI-Daten. D.h. Du musst:
>* vor der Übertragung SS auf Low
>* Daten(high) in SPDR schreiben
>* warten, bis SPI fertig ist
>* Daten(low) in SPDR schreiben
>* warten, bis SPI fertig ist
>* SS wieder auf High

>Entweder Du übergibst Deinem spi_senden also 2 8-Bit-Werte (High und
Low), was einfacher zu programmieren ist, einen 16-Bit-Wert und
trennst
>diesen in spi_senden in High- und Low auf.
________________________________________
Mein Code:
void spi_senden(unsigned daten)
{
  PORTB &= ~(1<<PB2);
  SPDR = daten;
  while(!(SPSR & (1<<SPIF))); // warte bis Byte gesendet
  PORTB |=(1<<PB2);
}
________________________________________

ich weiss noch nicht genau was du meinst, dass der einmal high daten
braucht und dann low.?!?
meinst du das so?
________________________________________
Mein Code:
void spi_senden(unsigned daten, unsigned daten1)
{
  PORTB &= ~(1<<PB2);
  SPDR = daten;
  while(!(SPSR & (1<<SPIF))); // warte bis Byte gesendet
  SPDR = daten1;
  while(!(SPSR & (0<<SPIF))); // warte bis Byte gesendet
  PORTB |=(1<<PB2);
}
________________________________________

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PORTB &= ~(1<<PB2);
  SPDR = daten;
  while(!(SPSR & (1<<SPIF))); // warte bis Byte gesendet
  SPDR = daten1;
  while(!(SPSR & (0<<SPIF))); // warte bis Byte gesendet
  PORTB |=(1<<PB2);

Ja, so kannst Du das machen. Sollte eigendlich funktionieren?

Gruß, Stefan

Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

wo hast du das eigentlich gefunden im datenblatt mit dem einmal 8Bit
high und dann 8Bit low senden???

irgendwie klappt da nix.

Autor: peter dannegger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich benutze den MAX7219 mit Anzeigen mit gemeinsamer Anode.

Anbei ein Beispielcode.


Peter

Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

@Peter
Der MAX7219 hat doch kein SPI oder?

Irgendwie raf ich dein code auch net haste keine kurze version?

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Nook,

der MAX7219 ist der Vorgänger des MAX7221.

Die eigentliche Ausgaberoutine ist diese hier:
void display_write( u16 dc )
{
  u8 i;

  MAX7219_DDR |= 1<<MAX7219_DO;
  MAX7219_DDR |= 1<<MAX7219_SCK;
  MAX7219_DDR |= 1<<MAX7219_STB;
  MAX7219_PORT &= ~(1<<MAX7219_STB);

  for( i = 12; i; i-- ){
    MAX7219_PORT &= ~(1<<MAX7219_SCK);
    MAX7219_PORT |= 1<<MAX7219_DO;
    if( (dc & 0x0800) == 0 )
      MAX7219_PORT &= ~(1<<MAX7219_DO);
    dc <<= 1;
    MAX7219_PORT |= 1<<MAX7219_SCK;
  }

  MAX7219_PORT |= 1<<MAX7219_STB;
}


Der Rest ist nur Initialisierung und 7-Segment Wandlung.


Peter

Autor: Marian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan Kleinwort:

PORTB &= ~(1<<PB2);
  SPDR = daten;
  while(!(SPSR & (1<<SPIF))); // warte bis Byte gesendet
  SPDR = daten1;
>>  while(!(SPSR & (0<<SPIF))); // warte bis Byte gesendet
  PORTB |=(1<<PB2);

Muss in der 2. Whileschleife nicht eine 1 anstatt der 0 stehen? Man
wartet auch hier bis das SPI_flag gesetzt ist oder nicht?

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Marian:

ooops .. natürlich muss da eine 1 stehen, sorry.
Keine Ahnung, wie da die 0 hinkam ...

Viele Grüße, Stefan

Autor: Robert S. (razer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo an alle

ICh bin ebenfalls daran beschäftigt einen Max 7221 mit 6 LED
Segmentanzeigen zum laufen zu bringen Leider funktioniert es nicht. Es
werden immer alle Leds der Segmentanzeigen eingeschaltet. Und ich weiß
nicht warum :(

Hier der Code:

void spi_init (void)
{
  DDRB |= ((1 << PB3) | (1 << PB5) | (1 << PB2)); //MOSI, SCK, SS
Output, alle anderen Input
  SPCR |= ((1 << SPE) | (1 << MSTR));
}

void spi_senden (uint8_t adress, uint8_t data)
{
  PORTB &= ~(1 << PB2); //SS auf Low
  SPDR = adress;
  while (!(SPSR & (1 << SPIF))); //warten bis gesendet
  SPDR = data;
  while (!(SPSR & (1 << SPIF))); //warten bis gesendet
  PORTB |= (1 << PB2); //SS auf high
}

void segments_init(void)
{
  spi_senden(0x0B, 0x05); //6 Digits 0-5
  spi_senden(0x0F, 0x00); //Display Test ausschaltren
  spi_senden(0x0C, 0x01); //Normal Operation
  spi_senden(0x09, 0xFF); //BCD Code für alle Digits
}
void show_temp(void)
{
  spi_senden(0x01, 0x01);
  spi_senden(0x02, 0x02);
  spi_senden(0x03, 0x03);
  spi_senden(0x04, 0x04);
  spi_senden(0x05, 0x05);
  spi_senden(0x06, 0x06);
}

int main (void)
{
  spi_init();
  i2c_init();
  segments_init();

  spi_senden(0x0A, 0x0C); //Helligkeit
  show_temp();

  while(1)
  {
  }
  return 0;
}

Vielleicht kann mir wer helfen

Danke im Voraus

Gruß Robert

Autor: Nook (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab auch immer noch das selbe problem wie du auch.

Autor: Didi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute! Hab genau dasselbe Problem. Bei mir werden trotz richtiger 
Initialisierung auch immer alle LEDs angezeigt. Übertragung findet auch 
über SPI statt. Habt ihr schon ne Lösung?
Grüße,
Didi

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.