Forum: Mikrocontroller und Digitale Elektronik 8051 kommuniziert mit ATmega16


von Bernhard Friedel (Gast)


Angehängte Dateien:

Lesenswert?

Der 8051 zerstückelt eine long Variable in 4 einzelne Bytes, wobei das
höchstwertige Byte nicht benötigt und daher weggelassen wird.

Diese 3 Bytes werden dann nacheinander am Port des 8051 ausgegeben.

Hier die Ausgabe Routine (Keil C Compiler):

P0_0=0;    //Ruheposition für Enable-Bit
P0_1=1;    //Ruheposition für Bit, dass den INT0 beim ATmega16 auslöst
P5=0;

acc=freq_einst/0.10596381293403;  //Berechnung
b1=acc&0xff;        //Byte1 (niederwertigstes Byte)
b2=(acc>>8)&0xff;      //Byte2
b3=(acc>>16)&0xff;      //Byte3

//Übergabe Routine

P0_1=0;  //INT0 auslösen
P0_1=1;

P5_0=1;  //Mitteilen, dass Byte1 übergeben wird
P5=b1;  //Byte1 am Port ausgeben
P0_0=1;  //mega16 übernimmt das Byte
P0_0=0;
P5=0;

P5_1=1;  //Byte2 wird übergeben
P5=b2;  //usw ...
P0_0=1;
P0_0=0;
P5=0;

P5_2=1;
P5=b3;
P0_0=1;
P0_0=0;
P5=0;

Umrechnung funktioniert (testweise am LCD angezeigt), jedoch nimmt der
mega16 die Daten nicht an.

ATmega16 asm Code:

int0_isr:
  sbic PINA,0
    rjmp r24_load
  sbic PINA,1
    rjmp r25_load
  sbic PINA,2
    rjmp r26_load
  rjmp int0_isr

r24_load:
  sbis PIND,3
  rjmp r24_load
  in r24,PINA
wait_r24:
  sbic PIND,3
  rjmp wait_r24
  rjmp int0_isr

r25_load:
  sbis PIND,3
  rjmp r25_load
  in r25,PINA
wait_r25:
  sbic PIND,3
  rjmp wait_r25
  rjmp int0_isr

r26_load:
  sbis PIND,3
  rjmp r26_load
  in r26,PINA
  reti

Am Anfang wartet er darauf welches Register geladen werden soll
(r24,r25,r26), dann wird in die jeweilige Routine gewechselt und die
Daten sollten danach eingelesen werden, dann springt er zurück in die
INT0_ISR und wartet wieder.

Abgeschlossen wird die ISR mit dem r26_load.

Bei dem 8051 handelt es sich um einen AT89C51ED2, der mit 24MHz
betrieben wird.
Der mega16 wird mit 16MHz getaktet.

Beide führen ihre Hauptaufgaben ohne Probleme durch, jedoch scheitert
das Ganze noch an der Übergabe :-(

Als Anhang ist ein JPG File dabei, das die Verbindung der 2 µC zeigt.


Ich bin für jeden noch so kleinen Hinweis sehr dankbar :-)

von thkais (Gast)


Lesenswert?

Dir fehlt die Synchronisation.
Ich habe von C keine Ahnung, aber soweit ich das interpretiere, sendest
Du über den "Datenbus" P5 zuerst eine Adresse, wohin das Byte soll
(1,2 oder 3) und dann das Datenbyte selbst direkt hinterher. Zwischen
der Mitteilung, welches Byte übergeben wird und dem Byte selbst mußt Du
irgendein Signal generieren, das die Adresse von den Daten trennt, sonst
liest der Mega-16 Mist. Dementsprechend muß der Mega16 auf der anderen
Seite auf dieses Signal warten. Du hast doch 2 Steuerleitungen
vorgesehen, ich würde es folgendermaßen machen: Steuerleitung 1 ist das
A/D (Adresse / Daten), Steuerleitung 2 ist das Strobe (Übernahme von
Daten bei steigender oder fallender Flanke). Schau Dir mal die
Anbindung von RAM / Displays an einen Daten/Adressbus an.
In Pseudocode könnte das so aussehen:

A/D = 0 (Adresse)
Datenbus = Byte-Nr.
Strobe
A/D = 1 (Daten)
Datenbus = Datenbyte
Strobe

Du könntest auch auf das Adressbyte ganz verzichten, wenn Du die
Reihenfolge festlegst und immer die gleiche Anzahl Daten überträgst.

von Bernhard Friedel (Gast)


Lesenswert?

Damit ich dem mega16 mitteile, dass die Daten gültig sind ist der
Ausgang P0.0 da. Also dieser geht auf High, der mega16 liest ein und
wartet bis es wieder auf Low geht, dann gehts zurück in die ISR, wo er
wieder wartet bis die nächste Adresse kommt.

Ich bin davon ausgegangen, dass der mega16 schneller als der 8051
arbeitet - deswegen wartet nur der mega16 und der 8051 sendet alles
nacheinander.

Wahrscheinlich hab ich das Ganze etwas komplizierter gemacht als es
eigentlich sein sollte, aber Assembler ist nicht so mein Ding.

von Michael (Gast)


Lesenswert?

da beide controller nach dem einschalten unterschiedlich lange brauchen,
um den programmteil zu erreichen, ist es wahrscheinlich, daß der atm 16
nich das erste byte als erstes empfängt, sondern byte 2 oder 3. ads
meinte bernhard mit der synchronisation.

mfg
michael

von Rahul (Gast)


Lesenswert?

Du solltest wirklich am besten zwischen der Adressausgabe und der
Datenausgabe einen Synchonisationsimpuls erzeugen.
Wie wäre es denn, wenn Du erst die Adresse an den Port ausgibst, dann
die ISR des ATmega durch den L-H-Übergang an P0_1 triggerst, damit der
ATmega merkt, welches Byte als nächstes übertragen wird?
Die Adresse ist dann solange gültig, wie H-Pegel am INT0-Pin anliegt.
Sobald L-Pegel anliegt, handelt es sich um Daten.
Damit würde man sogar einen Handshake-Pin sparen.
INT0 könnte man doch auch zustandsgesteuert auslösen lassen, oder?
Sonst halt die L-H-Flanke (oder anders herum).
Bei Eintreffen einer Flanke oder Anliegen von H-Pegel weiss der ATmega
dann, dass eine Adresse anliegt.
Gruß Rahul

von Rahul (Gast)


Lesenswert?

Hab gerade festgestellt, dass es sich bei deiner Flanke um eine fallende
handelt. Also alles umgekehrt:
Bei L-Pegel liegt die Adresse an, bei H Daten.

Nach meiner Einschätzung sollte das so funktionieren (habe es nicht
ausprobiert).
Was sein kann, ist, dass zwischen den Umschaltvorgängen eine gewisse
Zeit vergehen muss, wegen der Port-Kapazitäten. Notfalls mehrfach den
Port abfragen (ähnlich dem Tastenenprellen).

Gruß Rahul

von Peter D. (peda)


Lesenswert?

P5_0=1;  //Mitteilen, dass Byte1 übergeben wird
P5=b1;  //Byte1 am Port ausgeben

Das kann doch nicht gehen !

Du überschreibst ja P5_0 sofort wieder.

Du must ein Handshake machen, wo der M16 mitteilen kann, daß er die
aktion gelesen hat und dann erst der 8051 den nächsten wert ausgeben
kann.


Peter

von thkais (Gast)


Lesenswert?

Sag ich doch.

von Rahul (Gast)


Lesenswert?

Ausserdem wird der ATmega beim Programm in dieser Form nicht erkennen,
ob es sich um eine Adresse oder Daten handelt.
Gruß Rahul

von Bernhard Friedel (Gast)


Lesenswert?

Ich hab jetzt die Version von Rahul mal ausprobiert.
Keiner der controller hängt sich mehr auf, jedoch übernimmt der mega
anscheinend irgendwelche Daten, nur nicht die Richtigen.

Um dem mega etwas Zeit zum einlesen zu geben, hab ich Warteschleifen
beim 8051 eingefügt, hat aber auch nichts geändert.


Danke für alle Beiträge :-))

---------------------

    P0_1=1;
    P5=0xff;

    b1=0xDD;
    b2=0x24;
    b3=0x00;


    P5_0=0;           //Adresse
       for(x=0;x<1000;x++);
    P0_1=0;   //fallende Flanke => Int.
       for(x=0;x<1000;x++);
    P5=b1;          //byte ausgeben
       for(x=0;x<1000;x++);
    P0_1=1;         //wieder auf High
       for(x=0;x<1000;x++);
    P5=0xff;

    P5_1=0;
       for(x=0;x<1000;x++);
    P0_1=0;
       for(x=0;x<1000;x++);
    P5=b2;
       for(x=0;x<1000;x++);
    P0_1=1;
       for(x=0;x<1000;x++);
    P5=0xff;

    P5_2=0;
       for(x=0;x<1000;x++);
    P0_1=0;
       for(x=0;x<1000;x++);
    P5=b3;
       for(x=0;x<1000;x++);
    P0_1=1;
       for(x=0;x<1000;x++);
    P5=0xff;

---------------------

int0_isr:

  sbic PINA,0
    rjmp r24_load
  sbic PINA,1
    rjmp r25_load
  sbic PINA,2
    rjmp r26_load
  rjmp int0_isr
  reti

r24_load:
  sbis PIND,2       ;Warten bis wieder auf High
  rjmp r24_load
  in r24,PINA        ;einlesen
  out PORTC,r0
  reti


r25_load:
  sbis PIND,2
  rjmp r25_load
  in r25,PINA
  reti

r26_load:
  sbis PIND,2
  rjmp r26_load
  in r26,PINA
  reti

von Peter D. (peda)


Lesenswert?

Was hast du denn bloß gegen ein Handshake ?

Und wenn Du soviel Warteschleifen einbaust, warum nimmst Du nicht
gleich SPI, wäre dann sogar schneller.


Peter

von Peter D. (peda)


Lesenswert?

Und Quellcode immer als Anhang, sonst muß man sich ja totscrollen.

Peter

von Rahul (Gast)


Lesenswert?

Hallo Bernhard!
So wie ich dein Programm verstehe, gibts du am Port 5 Adressen und
Daten aus. Ich bin jetzt nicht mehr wirklich fit in Bezug auf 8051,
aber wieso gibst du die Adresse invertiert aus? Liefert der 8051 bei
Ausgabe von 0xFF am Ausgang 0V?
Ich würde halt P5=0 für Adresse 0, P5=1 für Adresse 1 und P5=2 für
Adresse 2 ausgeben. Mein 8051-Wissen ist etwas eingestaubt...

Würde mich freuen, wenn es nur an so einer simpler Sache liegen
würde...

Gruß Rahul

von Bernhard Friedel (Gast)


Lesenswert?

>Würde mich freuen, wenn es nur an so einer simpler Sache liegen
>würde...

Du darfst dich freuen.
Einfach P5=1 / P5=2 / P5=4 und es funktionierte.

  Danke!!!


Achja, die Warteschleifen sind egal, der Controller hätte sowieso
nichts zu tun.

von Rahul (Gast)


Lesenswert?

Naja, auf diese Art und Weise kannst Du zwar maximal 8 Byte übertragen,
aber wenigstens funktioniert es erst mal.
Herzlichen Glückwunsch!

Damit das System flexibler würde, könnte man jetzt doch den Vorschlag
von thkais anwenden (und verändern):
Mit dem einen Kanal P0_0 anzeigen, dass Daten geschickt werden
(Enable), und mit P0_1 die Daten rübertakten.
Solange P0_0 gesetzt ist, werden bei jeder fallenden Flanke die
anliegenden Daten in ein Feld übernommen.
So stelle ich mir das vor.
Gute Nacht!
Gruß Rahul

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.