mikrocontroller.net

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


Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Rolf Magnus (Gast)
Datum:

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

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: TravelRec. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch für niedrige Baudraten ist der interne Oszillator zu ungenau für
UART.

...

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Robert Teufel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: cazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@crazy horse:

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

...

Autor: Jadeclaw (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: cazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jadeclaw (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: mkmk (Gast)
Datum:

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

MfG

Autor: cazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: cazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
;-)

Autor: Ronny Schulz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beispiel:
http://www.the-starbearer.de/Praxis/datenfunk/manc...

Implementiert in Atmels SAM7S Controllern.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ronny Schulz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

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.