Forum: Mikrocontroller und Digitale Elektronik Verknüpfung UART und manueller Portpin


von Ronny Schulz (Gast)


Lesenswert?

Ich möchte einen ATmega128 und einen ATtiny12 miteinander verbinden. Der
ATmega128 ist Empfänger und der Tiny12 ist der Sender. Ich dachte mir,
dass ganze über einen serielle Verbindung laufen zu lassen. Der Mega128
wird einen RXD opfern und der Tiny12 einen Pin, den ich als Ausgang
definiere. ICh nutze auf dem ATmega128 die UART-Lib von Peter Fleury.
Nun kommen die Zeichen aber nicht wirklich an oder zumindest ist das
Error-Flag immer gesetzt. Senden tue ich Start-Bit (0), 8 Datenbits und
1 Stopp-Bit (1). Ist das grundsätzlich so korrekt oder ist da schon ein
gedanklicher Fehler drin?

von Rolf Magnus (Gast)


Lesenswert?

Welche Baudrate benutzt du denn? Hälst du die auch auf beiden Seiten
genau ein? RS232 ist da recht empfindlich.

von Ronny Schulz (Gast)


Lesenswert?

Extra nicht so viel: 9600 Baud. Auf der ATmega-Seite ist das ja kein
Problem, da ich den Hardware-UART nehme. Auf der Tiny-Seite habe ich
mal durchgerechnet und durchlaufen lassen. Auch unter AVR-Studio in der
Simulation nochmal die Zeit gemessen. 104us muss ein Bit anliegen, was
so um ca. 1us differiert. Wäre das zu viel?

Auf der anderen Seite, weiss ich natürlich nicht, ob der Takt des
ATtiny12 (1.2 MHz) wirklich exakt stimmt. Ich habe das Calibration-Byte
ausgelesen und gesetzt, was vom Hersteller ja schon voreingestellt ist.

von TravelRec. (Gast)


Lesenswert?

Versuch mal, den Tiny mit Quarz zu takten, dann weißt Du schon mal, daß
Dein Takt immer annähernd genau ist. Serieller Datentransfer mit
internem RC-Oszillator ist nicht zu empfehlen.

von Ronny Schulz (Gast)


Lesenswert?

Zum testen könnte ich mir einen Oszillator besorgen. Grundsätzlich geht
es aber nicht, da ich alle 6 Portpins benötige. Evtl. sollte ich erst
einmal eine niedrigere Baudrate verwenden (evtl. 2400?). Das reicht
auch. Weil ich immer nur 5 Bytes pro Sekunde übertragen will. Durch den
FIFO im ATMEGA128 habe ich auch keine Pollingzeiten zum abholen.

von Hannes L. (hannes)


Lesenswert?

Auch für niedrige Baudraten ist der interne Oszillator zu ungenau für
UART.

...

von Rolf Magnus (Gast)


Lesenswert?

Also ich hab hier einen Mega8 laufen, dessen USART mit der RS232 des PCs
verbunden ist. Getaktet ist das Ding mit den internen 1MHz, und die
Übertragung mit 4800 Baud läuft fehlerfrei.
Und dabei läuft der Controller spannungsmäßig sogar außerhalb der
Spezifikation (3,3V - der Mega8 ohne L geht laut Datenblatt eigentlich
erst ab 4,5V). Extra Kalibrierung hab ich da auch keine gemacht. Also
ganz so schlimm kann's wohl nicht sein.

von Benedikt (Gast)


Lesenswert?

>Auch für niedrige Baudraten ist der interne Oszillator zu ungenau für
UART.

Wenn die Kurven im Datenblatt korrekt sind, dann ist diese Aussage
falsch:
Ist die Spannung stabilisiert, und man läd den OSCCAL mit einem Wert,
so dass der AVR bei etwa 35°C mit der Sollfrequenz läuft, dann bleibt
man im Bereich von etwa 0-70°C innerhalb von +/-2°

Ich verwende seit Jahren einen mega8 der Daten mit 500kBit/s überträgt,
und zwar immer 512kByte auf einmal. Mit dem internen Oszillator kein
problem, solange man die Schaltung nur im Haus betreibt. Hier hat man
nämlich nie weniger als 0°C oder mehr als 60°C.

von Ronny Schulz (Gast)


Lesenswert?

Da ist u.U. auch schon meine Fehler. Die Betriebsspannung kommt direkt
vom PC-Netzteil und liefert etwa 5.2 V. Wirkt sich das auf den RC
Oscillator aus?

von Robert Teufel (Gast)


Lesenswert?

Ronny,

hast du ein Oszi?  Einfach mal messen wenn du die ganze zeit 0x55
sendest wie lange ein bit tatsaechlich ist.
RC Oscillatoren sind je nach Bauart mehr temperatur oder mehr
spannungsempfindlich. Es gibt fuer beides interne
Kompensationsmoeglichkeiten aber die kosten Chipflaeche und Chipflaeche
kostet Geld. Die AVR sind sehr preisguenstig und das ist einer der
Punkte an denen gespart wurde. Versuch mal zu messen, falls der Puls zu
kurz ist einfach um ein Inkrement in deinem Software UART verlangsamen.


Das waere ueberhaupt noch eine Moeglichkeit, programmier den Tiny so,
dass er deiner Meinung nach ca. 5% zu schnell ist, dann mach ihn mit
jedem Schleifendurchlauf etwas langsamer, solange bis die richtigen
Daten empfangen werden, dann mach ihn weiter langsamer bis die Daten
wieder Schrott sind. Von den richtigen Daten nimm den Mittelwert.
Hoffentlich war das jetzt nicht zu kryptisch.

Gruss, Robert

von cazy horse (Gast)


Lesenswert?

Uart und RC-Osz - das ist einfach nicht tot zu hauen. Immer wieder
diesselbe Geschichte, einer hat Probleme damit, wers schon durchhat
oder drüber nachdenkt, sagt, dass das nicht richtig funktioniert - es
kommen aber auch immer wieder Leute: geht problemlos, seit Jahren, nie
Fehler. Und so hält sich das ewig...

von Hannes L. (hannes)


Lesenswert?

@crazy horse:

Danke... - Ich dachte schon, ich stehe mit Meiner Meinung als Depp
da...

...

von Jadeclaw (Gast)


Lesenswert?

5 Bytes pro Sekunde?
Ich würde mit dem Tempo heruntergehen, z.B. auf 110Baud.
Da ist dan der Teilerfaktor so gross, dass auch ein stark driftender
RC-Oszillator kaum noch Probleme macht.
Ich behaupte mal, so ein ATTiny ist immer noch frequenzstabiler als ein
mechanischer Fernschreiber.
Und die hatten bei dem Tempo keine Probleme fehlerfrei mitzuschreiben.

Gruss
Jadeclaw.

von cazy horse (Gast)


Lesenswert?

Ja bitte - was ändert das denn am Problem? Da kannst du teilen, bis du
auf 1Bit/Tag bist, das wird kein Stückchen besser dadurch.

von Jadeclaw (Gast)


Lesenswert?

Denk mal scharf nach: Was passiert wohl, wenn der Oszillator um einen
bestimmten Betrag wandert?
Und dann überlege mal, welchen Auswirkung diese Drift bei 9k6 hat und
welche Wirkung diese Drift bei 110 Baud hat.
Und du wirst erkennen, dass eine Oszillatordrift, die bei 9k6 noch
Probleme bereitet, sich bei 110 Baud überhaupt nicht mehr bemerkbar
macht.

Gruss
Jadeclaw.

von Ronny Schulz (Gast)


Lesenswert?

@Robert:
Hab ich verstanden. Super erklärt. Ich probiere da mal einiges von aus.
Vielleicht ist die günstigste Lösung eine automatische Anpassung der
Baudraten...

Ich sehe gerade einiger sind der Meinung, dass es garnicht geht..... In
diesem Fall sollte ich mir ein anderes Protokoll ausdenken, was nicht so
stark auf Timings basiert. So 1 Wire, wie beim DS1820 wäre ja auch eine
Möglichkeit.

von Hagen (Gast)


Lesenswert?

Also ich vermute mal:

1.) OSCAL Wert ?
2.) Baudrate falsch ?
3.) Soft-UART im Tiny12 fehlerhaft ?
4.) HW-fehler ?

und dann erst das bei 9600 der interne RC Proleme macht. Auch wenn ich
der Meinung bin mit Quarz ist auf der sicheren Seite zu sein, so muß
ich denoch bestätigen das alle meine UARTs zuerstmal mit dem internen
RC-Osz. ohne Probleme liefen. Das ist zwar kein Beweis aber ein Indiz.
Dabei spielte die Baudrate ansich nicht die größte Rolle.

Gruß Hagen

von mkmk (Gast)


Lesenswert?

Serienproduktion: Atmega8, interner Osci (4 MHz), Baudrate 9600.
Nie irgendwelche Fehler registriert.
Voraussetzung: Register OSCAL bei jedem einzelnen MCU sehr exakt
setzen.

MfG

von cazy horse (Gast)


Lesenswert?

"Denk mal scharf nach: Was passiert wohl, wenn der Oszillator um einen
bestimmten Betrag wandert?
Und dann überlege mal, welchen Auswirkung diese Drift bei 9k6 hat und
welche Wirkung diese Drift bei 110 Baud hat.
Und du wirst erkennen, dass eine Oszillatordrift, die bei 9k6 noch
Probleme bereitet, sich bei 110 Baud überhaupt nicht mehr bemerkbar
macht."

Vielleicht solltest du mal nachdenken..., und wenn du nicht
draufkommst,
rechne es einfach mal nach.

von cazy horse (Gast)


Lesenswert?


von Hannes L. (hannes)


Lesenswert?

;-)

von Ronny Schulz (Gast)


Angehängte Dateien:

Lesenswert?

So gesehen um alles auf einen Nenner zu bringen, sollte diese
Übertragung grundsätzlich funktionieren, wenn man die Baudrate wie oben
 von Robert beschrieben automatisch anpassen lässt.

Das habe ich auch ausprobiert. Aber irgendwie kommt bei mir nur Müll
an. Mit dem Oszilloskop gemessen habe ich. Und das sah ganz gut aus.
Ich machte bloss ne Schleife die immer 0x55 sendet. Die Datei ist im
Anhang. Unter C auf dem ATmega128 läuft dann folgende Prozedur:


void fan_rotation(void)
{
  unsigned int     data;
  char         cbuf[10];

  if (!((data = uart_getc()) & UART_NO_DATA)) {
    itoa((data>>8) & 0x00FF, cbuf, 16);
    if (cbuf[1] == '\0') {
      cbuf[1] = cbuf[0];
      cbuf[0] = '0';
      cbuf[2] = '\0';
    }
    uart1_puts(cbuf);
    itoa(data & 0x00FF, cbuf, 16);
    if (cbuf[1] == '\0') {
      cbuf[1] = cbuf[0];
      cbuf[0] = '0';
      cbuf[2] = '\0';
    }
    uart1_puts(cbuf);
    uart1_puts("  baud: ");
    itoa(fbaud, cbuf, 10);
    uart1_puts(cbuf);
    if (data == 0x55) uart1_puts(" OK!");
    uart1_puts("\r\n");

    if (fbaud < FAN_BAUD) {
      if (fbaud == FAN_BAUD - FAN_BAUD / 5) fbaud = FAN_BAUD + 1;
      fbaud -= 1;
    } else {
      if (fbaud == FAN_BAUD + FAN_BAUD / 5) fbaud = FAN_BAUD - 2;
      fbaud += 1;
    }
    uart_init(UART_BAUD_SELECT(fbaud, SYSCLOCK));
  }
  return;
}

Klar das vorher uart_init() schon aufgerufen wurde und die Routine hier
immer wieder angesprungen wird.

von Ronny Schulz (Gast)


Lesenswert?

Um das ganze nochmal aufzufrischen. Welche anderen Möglichkeiten der
Übertragung stehen mir denn offen, wenn ich nur einen Portpin zur
Verfügung habe? Theoretisch fiele mir dir eine Bit- für Bit-Übertragung
ein, wo ich jedes Bit einzeln anfordere, indem ich den "Master"
einfach auf Pullup setze und dann vom "Slave" innerhalb eine Zeit x
zurücklese.

Oder was meint ihr grundsätzlich?

von A.K. (Gast)


Lesenswert?

UART benötigt deshalb einen genauen Takt, weil nur im Startbit
synchronisiert wird, es also für 9 weitere Bits ausreichen muss. Mit
jedem Bit steigt jedoch die Fehlerwahrscheinlichkeit.

Alternative: Andere Codierung, bei der mit jedem Bit ein Takt mitläuft
(FM, Manchester, ...). Ist allerdings meist reine Software.

Im einfachsten Fall nimmt man Hardware-UARTs mit grob übereinstimmendem
Takt, überträgt aber pro Byte nur 1 Bit. Um 0 zu senden, sendet man
0xFE, um 1 zu senden 0xE0. Beim Empfänger kommt dann je nach
Taktrelation bei 0 irgendwas aus 0xFF,0xFE,0xFC an, bei 1 irgendwas aus
0xF8,0xF0,0xE0,0xC0,0x80,0x00.

von Ronny Schulz (Gast)


Lesenswert?

Das mit dem UART leuchet mir ein. Also send ich das ganze achtmal, um
mein Byte komplett zu übertragen. Also Startbit, Daten, Stoppbit:

0-x-1

Das werde ich auf alle Fälle mal ausprobieren.

Die andere Sache interessiert mich auch. Wie kann ich denn noch einen
Takt mitlaufen lassen, wenn ich nur eine Leitung habe. Bei 2 Leitungen
ist das ja einfach. Aber auf einer?

von A.K. (Gast)


Lesenswert?

Beispiel:
http://www.the-starbearer.de/Praxis/datenfunk/manchestercode.htm

Implementiert in Atmels SAM7S Controllern.

von A.K. (Gast)


Lesenswert?

Ach ja, nachdem eine der Seiten ein Controller ohne Hardware-UART ist:
Das ganze ist ja nichts anderes als eine Pulslängencodierung, auch als
PWM bekannt. Kurzer 0-Impuls steht hier für 0, ein langer für 1
(andersrum ist logischer).

Du musst also im Tiny12 keine Soft-UART dafür vergewaltigen, einfach
Pulse der richtigen Länge und in hinreichendem Abstand tun es auch, und
wenn noch ein PWM-Timer frei ist...

Da kannst Du nun, wie von dir beschrieben, das Protokoll einer
asynchronen Schnitstelle drauflegen, oder gänzlich eigene Phantasie
walten lassen.

von Ronny Schulz (Gast)


Lesenswert?

Ja das mit der Pulslängencodierung war so eine Idee. Das habe ich schon
im Protokoll vom DS1820 gesehen. Da wird das auch über Zeiten
geregelt.

Dennoch probiere ich es erstmal pber den Software-UART aus. Für mich
hat das den Vorteil, dass die Daten erstmal im Puffer landen, wenn die
reinkommen und ich die dann später auswerten kann. Der Hardware-UART
auf der anderen Seite kümmert sich eben komplett darum und entlastet in
dem Moment natürlich den Controller.

Und mit dem Manchestercode habe ich auch schon wieder was dazu gelernt.
Fallende und steigende Flanken definieren 1 oder 0.

von Ronny Schulz (Gast)


Lesenswert?

So ich könnte heute mal was von dem gesagten umsetzen. Ich werde da
sicher noch weiter machen,. aber für den ersten Test lief es ganz gut.
Ich sende jetzt jedes Bit als Byte. So dass es so aussieht:

Startbit -> 0
serial delay

Datenbit
serial delay * 8

Stoppbit -> 1
serial delay

Das ganze wird dann für jedes Bit wiederholt. Der Empfänger schaut
dann. Wenn 0 ankommt ist es 0, wenn was anderes kommt ist es 1.

von Ronny Schulz (Gast)


Lesenswert?

So vielen Dank nochmal. Das ganze Thema ist jetzt soweit gelöst, dass
die Version funktioniert in der ich nur ein Datenbit als Byte
verpacke.

Ich habe das ganze sogar heute noch optimiert, indem ich die Baudrate
nicht vorgebem sondern die vom Master setzen lasse. Der Master sendet
am Start einen Low-Impuls der genau so lang ist, wie ein delay in der
serial_send-Routine. Somit kann ich die Baudrate vom Master einstellen
lassen. Und egal, wie ungenau der Slave ist - es ist egal.

Wenn ich den Tiny13 mal zum laufen bekomme, könnte ich evtl. die
Genauigkeit so weit erhöhen (8 MHz), dass ich vielleicht auch richtig
senden kann. Dann liegt es am Master, wie genau das delay am Start ist.

von Ronny Schulz (Gast)


Angehängte Dateien:

Lesenswert?

Irgendwie funzt das doch nicht so recht. Ich habe schon den halben Tag
hier verbracht zu simulieren mit AVR-Studio und die Timings
nachzuprüfen. Aber anscheinend haben sich die AVRs zu zickig und wollen
nicht so mit der Genauigkeit. Besonders der Tiny13 macht Probleme.
Inzwischen läuft er und auch mit 9,6 MHz.

Meine Initialisierung am Master sieht so aus:

cli();
DDRE &= ~(1<<PE0);  /* set uart-pin to input */
PORTE &= ~(1<<PE0);  /* disable pullups */
DDRE |= 1<<PE0;    /* start synchronize */
delay_us(1000000 / FAN_BAUD);    /* synchronize delay */
DDRE &= ~(1<<PE0);
uart_init(UART_BAUD_SELECT(FAN_BAUD, SYSCLOCK)); /* init fan uart */

Extern hängt ein 10k-Pullup dran, damit ich da nicht in Schwierigkeiten
beim High-Pegel komme.

Grundsätzlich muss das ganze doch perfekt funktionieren, wenn ich die
Zeit vom Master schicken lasse. Also wo ist die Problematik? Schwankt
die Frequenzabweichung vielleicht beim AVR.

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.