Forum: Mikrocontroller und Digitale Elektronik UART mit Atmega 2560


von Andreas (Gast)


Lesenswert?

Hallo zusammen,
Bin gerade am verzweifeln. Habe einen MyAVR Stamp 256k (Da ist ein 
Atmega 2560 drauf) hier und versuche ihn dazu zu bekommen mittels UART 
mit HTerm zu kommunizieren. Habe dazu ein einfaches C-Programm 
geschrieben, dass mir meine Eingabe auf dem Terminal direkt wieder 
zurückgeben soll. Leider produziert dies jedoch nur Datenmüll. Gebe ich 
hallo ein kommt hynlo zurück. Wenn mir jemand einen Tipp geben könnte 
was mein Fehler ist wäre ich euch dankbar. Verschiedene Baudraten habe 
ich schon getestet.

#include <avr/io.h>
#include <inttypes.h>


#define BAUD        2400UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)

// USART initialisieren
void
uart_init(void)
{
    // Baudrate einstellen (Normaler Modus)
    UBRR3H = (uint8_t) (UBRR_BAUD>>8);
    UBRR3L = (uint8_t) (UBRR_BAUD & 0x0ff);


    // Aktivieren von receiver und transmitter
    UCSR3B = (1<<RXEN3)|(1<<TXEN3);

    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    UCSR3C = (1<<UCSZ31)|(1<<UCSZ30);
}

int
main(void)
{
    uint8_t buffer;

    // USART initialisieren
    uart_init();

    while (1)
    {
        // Warten bis Daten empfangen wurden
        while ( !(UCSR3A & (1<<RXC3)) )
            ;

        // Empfangsregister auslesen
        buffer = UDR3;

        // Warten bis der Sendepuffer frei ist
        while ( !( UCSR3A & (1<<UDRE3)) )
            ;

        // Daten in den Puffer schreiben und damit senden
        UDR3 = buffer;
    }
}

von Cyrill M. (kerik)


Lesenswert?

Habe disen Code bei mir getestet (nur Register an ATMega8 angepasst), 
und alles funktionierte einwandfrei.
Vielleicht wurde die F_CPU nicht richtig definiert, oder in 
HTerm-Einstellungen irgendwas übersehen - bei BAUD oder Databits.

MfG
Kerik

von Andreas (Gast)


Lesenswert?

Hallo,
Danke für die Antwort. Mit einem Atmega 8 hats bei mir auch 
funktioniert. Nachdem ich das Programm aber für nen Atmega 2560 
umgeschrieben hab gehts nicht mehr. Kann es daran liegen, dass der 2560 
mit 16Mhz läuft und ich deshalb einen Fehler in der Baudrate von 0,2% 
habe?

Andreas

von Michael (Gast)


Lesenswert?

An einem Fehler von 0,2 % liegt es mit Sicherheit nicht. Das ist 
unproblematisch zulässig.

von Cyrill M. (kerik)


Lesenswert?

Versuchen Sie mal eine andere Formel für die Berechnung des UBRR Wertes! 
Die Formel ist auch bei AVR-Tutorial hier auf der Seite angegeben.

UBRR = (((F_CPU+BAUD*8)/(16UL*BAUD))-1)

Vielleicht wurde bei der ersten Formel unglücklich gerundet. So nur eine 
Vermutung!

MfG
Kerik

von Andreas (Gast)


Lesenswert?

Dann weiß ich langsam auch nicht mehr weiter. Hab mal manuell versucht 
UBBR zu verändern. Bei 103 kommt nach Eingabe hallo das schon erwähnt 
hynlo. Bei 104 gibt hterm hyllo aus und bei 102 hqnlo

von Andreas (Gast)


Lesenswert?

Hatte die Bausrate auf 9600 gesetzt für die Sachen die ich im letzten 
Post geschrieben habe.
Wenn ich das mit der Formel ausrechne komme ich auf 103,666. 104 wäre 
also demnach am nächsten dran

von Dietrich L. (dietrichl)


Lesenswert?

Andreas schrieb:
> // Aktivieren von receiver und transmitter
>     UCSR3B = (1<<RXEN3)|(1<<TXEN3);
>
>     // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
>     UCSR3C = (1<<UCSZ31)|(1<<UCSZ30);

Tauche mal die Reihenfolge: erst Datenformat, dann Enable.
Bei einem anderen AVR hat das schon mal geholfen...

Gruß Dietrich

von Andreas (Gast)


Lesenswert?

Hi,
Das Tauschen und die andere Formel haben leider nicht geholfen. Bekomme 
bei einem gesendeten Hallo ein Hqllo zurück
Andreas

von Andreas (Gast)


Lesenswert?

Komme einfach nicht drauf wo der Fehler liegen könnte.
Kann es passieren, dass der Quarz eine andere Frquenz liefert als 
angegeben ist?

von Karl H. (kbuchegg)


Lesenswert?

Andreas schrieb:
> Komme einfach nicht drauf wo der Fehler liegen könnte.
> Kann es passieren, dass der Quarz eine andere Frquenz liefert als
> angegeben ist?

Dein Quarz hat sicher nicht exakt 16000000 Hz. Aber er ist nahe genug 
drann, dass das kein Problem sein sollte. Hast du schon mal in die 
andere Richtung den UBRR Wert verändert: 102, 101

von Andreas (Gast)


Lesenswert?

Ja, hab ich auch schon. Dann kommt allerdings nur noch Müll.
Probiere es gleich nochmal aus und poste dann was genau ankommt

von Andreas (Gast)


Lesenswert?

Also bei 104 bekomme ich Hqllo zurück, darunter Hynlo und irgendwann nur 
noch Müll

von Uwe S. (de0508)


Lesenswert?

Hallo,

Andreas schrieb:
> #define BAUD        2400UL
> #define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)

ich verwende nun nur noch diesen schönen Trick mit Rundung:
1
#define BAUDRATE 9600U
2
#define UBRR_BAUD (uint16_t)((F_CPU) *1.0 / ((BAUDRATE) * 16l) - 0.5)

Ich erhalte mit F_CPU=16MHz und 9600 Baud UBRR_BAUD:=103.

von Andreas (Gast)


Lesenswert?

Ja, die 103 habe ich auch raus. Damit kommt aber leider nur Müll. Also 
bei Hallo gesendet Hynlo. Bei 1 kommt 9, bei 2 ein : und bei 3 kommt 3.

von Uwe S. (de0508)


Lesenswert?

ist schon der Tipp mit dem 1/8 Teiler, den man auch per Fuse-Bits ein 
und ausschalten kann, gekommen?

Solche Probleme hallte ich letztens nur mal mit einem Software Uart mit 
FIFO bei 9600 Baud.
Da waren 1MHz dann doch zu langsam und mit 8 MHz lief das gesamte 
Programm schnell genug.

von Andreas (Gast)


Lesenswert?

Der Teiler ist in den Fuses nicht gesetzt

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Hast du mal die anderen UARTs probiert?
Kannst du dir die Signale vielleicht mal auf einem Oszilloskop 
anschauen?

Hier mal ein Stück Code wie er bei mir auf einem ATmega2560 läuft.
1
// set baudrate
2
UBRR3 = (uint16_t)(F_CPU / (baudrate * 16L) - 1);
3
4
// set paritymode & number of databits
5
UCSR3C = ((parity & 0x05) << UPM30) | ((stopbits & 0x01) << USBS3) | ((databits & 0x07) << UCSZ30);
6
7
// enable RX/TX & interrupts
8
if ( databits == DATABITS_9 )
9
    UCSR3B = (1 << RXCIE3) | (1 << UDRIE3) | (1 << RXEN3) | (1 << TXEN3) | (1 << UCSZ32);
10
else
11
    UCSR3B = (1 << RXCIE3) | (1 << UDRIE3) | (1 << RXEN3) | (1 << TXEN3);

von Andreas (Gast)


Lesenswert?

Hallo,
Wollte mich für die vielen Vorschläge bedanken. Habe jetzt einen 
Codeschnipsel gefunden mit dem ichs zum laufen bekommen habe. Was genau 
falsch war muss ich morgen mal schaun.

Hier ist mein jetztiger Quellcode: (Noch nicht schön aufgeräumt, aber er 
funktioniert erstmal)
#include <avr/io.h>
#include <inttypes.h>


#define BAUD        9600UL
#define UBRR_BAUD   (103)

// USART initialisieren
void
uart_init(void)
{
    UBRR3H=0x00;
    UBRR3L=UBRR_BAUD;
    //---------------------------
    UCSR3A=0x00;    // U2X auf LO
    //---------------------------
    UCSR3B=0x00;
    UCSR3B|=0x80;   // Rx Interrupt enable
    UCSR3B|=0x10;   // Rx enable
    UCSR3B|=0x08;   // Tx enable
    //---------------------------
    UCSR3C=0x00;    // asyncron, no parity, 1stopbit
    UCSR3C|=0x04;   // 8datenbits
    UCSR3C|=0x02;   // 8datenbits
}

int
main(void)
{
    uint8_t buffer;

    // USART initialisieren
    uart_init();

    while (1)
    {
        // Warten bis Daten empfangen wurden
        while ( !(UCSR3A & (1<<RXC3)) )
            ;

        // Empfangsregister auslesen
        buffer = UDR3;

        // Warten bis der Sendepuffer frei ist
        while ( !( UCSR3A & (1<<UDRE3)) )
            ;

        // Daten in den Puffer schreiben und damit senden
        UDR3 = buffer;
    }
}

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Andreas schrieb:
> UCSR3B|=0x80;   // Rx Interrupt enable

Ich hoffe du hast auch irgendwo den die passende ISR!
Könnte sonst zu komischen Effekten kommen, wenn du irgend wann mal die 
Interrupts frei schaltest.

von Andreas (Gast)


Lesenswert?

In dem Programm noch nicht, brauche es aber dafür was ich im weiteren 
damit vorhabe. Trotzdem danke für den Hinweis ;-)

von Mathis Jacobi (Gast)


Lesenswert?

Hallo,

hatte das selbe Problem beim ATmega 2560.
Wenn UBRR definieren will und es mit der Formel ausrechnen lässt kommt 
nur Mist. Erst wenn man den UBRR-Wert direkt einträgt (in diesem Fall 
"103") klappt es. So ist es nämlich auch in dem 'Codeschnipsel' der 
gegen Ende des Threads gezeigt wird auch. Deshalb funktioniert er dann 
auch.

Etwas spät aber vielleicht hilft es ja trotzdem noch ein paar Leuten.

von Oliver S. (oliverso)


Lesenswert?

Man könnte allerdings auch der Räucherkerzen anzünden, und fünf mal 
„UBBR“ rufen. Dann geht es auch, aus den selben Gründen.

Oliver

von Stefan F. (Gast)


Lesenswert?

Warum verwendet ihr die Standard-Bibliothek zur Berechnung?
https://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html

von Spess53 (Gast)


Lesenswert?

Hi

>Wenn UBRR definieren will und es mit der Formel ausrechnen lässt kommt
>nur Mist. Erst wenn man den UBRR-Wert direkt einträgt (in diesem Fall
>"103") klappt es.

Dann ist der GCC anscheinend dämlicher als der Atmel-Assembler. Bei dem 
bekomme ich problemlos die 0x67 (103) heraus.

MfG spess

Beitrag #6642547 wurde von einem Moderator gelöscht.
Beitrag #6642617 wurde von einem Moderator gelöscht.
Beitrag #6642632 wurde von einem Moderator gelöscht.
Beitrag #6642810 wurde von einem Moderator gelöscht.
von Norman P. (norman_p)


Angehängte Dateien:

Lesenswert?

Hi Leute,
hat jemand alle vier oder mindestens zwei UART's des ATM2560 mit RX und 
TX Interrupt gleichzeitig am Laufen? Bei mir funktionieren die UART's 
einzeln. Wenn man Auf der UART COM3 schreibt/liest und danach auf COM2 
und dann... COM1 und dann Com0 geht alles super. Wenn man dann aber 
wieder auf eine höhere COMx wechselt, dann werden die RX bzw. 
TX-Interrupts nicht mehr ausgelöst. Wenn man direkt auf UDRx 
schreibt/ließt, sind die Zeichen da. Also irgendwas macht bei der 
Priorisierung der Interrupts Probleme.

Coding schließe ich aus, weil AVRStudio 6 und 7 gleiche Resultate 
erzeugen.
Auf ATM128 gabs mit dem Source nie Probleme.

Im Quellcode kann man mit $OK oder mit $X mit abschließenden CR eine 
Antwort von der jeweiligen UART erhalten. siehe KommandoX.c

THX

von jo mei (Gast)


Lesenswert?

Norman P. schrieb:
> Also irgendwas macht bei der
> Priorisierung der Interrupts Probleme.

Kannst du mal erläutern warum du den Watchdog bemühst und
zu jeder beliebigen Tag- und Nachtzeit ihn wieder resetten
musst. Das "nervt" ungemein und verbrät auch Rechenzeit,
zumal du da jedes mal eine Funktion dafür aufrufst - mit
dem entsprechenden Overhead ....

Dann sehe ich es nicht ein Zeichen(ketten) im Interrupt-
Kontext zu senden. Denn beim Senden kann der Controller
gerade nicht auf Receive-Interrupts reagieren (sondern
erst danach) und es fällt für jedes Zeichen ein Interrupt-
Overhead (ISR: Register retten und wiederherstellen) an,
das läppert sich .... Ich habe Zeichen schon immer ohne
IRQ gesendet und war immer glücklich damit.

Habe mich nicht weiter bemüht den ganzen Code zu verstehen,
dazu war ich aufgrund der bisherigen "Macken" nicht
motiviert.

Aber im allgemeinen empfiehlt es sich das Problem auf ein
Minimal-Programm zu reduzieren damit es auch jeder gleich
versteht.

von Norman P. (norman_p)


Lesenswert?

Hi,
der Watchdog überwacht nur den korrekten Lauf des Programms. Wenn ich 
eine Schleife habe, aus der der Kontroller nicht wieder herauskommt, 
erfolgt nach dem Watchdog-Zeitintervall ein Reset des Kontrollers. Somit 
muß im Programmablauf immer der Watchdog-Timer mit seiner Reset-Funktion 
aufgerufen werden. Gut, man kann auch Inline-Code dafür aufrufen, 
anstatt ein (CALL, WDT-Reset, Return). Es gibt immer elegantere 
Lösungen.

Wenn ich das Senden per Einzelschreibbefehle mit Warten auf Puffer-Leer 
durchführe, dann packe ich halt in der MAIN die While-Schleife mit dem 
Sendealgorithmus zu. Das ist aber nicht Sinn der Übung. Die 
Kommunikation soll quasi nebenher im Interrupt-Modus erfolgen und in der 
Main-Schleife will ich dann auf Nachrichten reagieren und Berechnungen 
etc. durchführen.

Wegen der Rechenzeit mache ich mir keine Sorgen. Bei 9k6 Baudrate und 
dem gelegentlichen Eintreffen von ein paar kurzen Nachrichten, schlafen 
die ISR die meiste Zeit. Notfalls kann man den Ringpuffer vergrößern 
oder noch eine Stringliste mit den Nachrichten einfügen. Das ist aber 
nicht das Problem!

Der gepostete Source hat bei mir auf ATM 128 mit 2 UARTs funktioniert, 
nur eben jetzt auf dem ARD-MEGA250PRO Board mit ATM 2560 geht es nicht 
mehr. Man
kann auch die Anzahl der unterstützten UARTs auf zwei reduzieren. Das 
Problem, wenn mit UART0 gesendet wurde, dann empfängt UART1 oder 2 oder 
3 nichts mehr und das Senden über diese UARTs ist ebenfalls über die ISR
blockiert. Das direkte Füllen von UDR1 oder UDR2,3 geht und wird auch 
gesendet. Nur eben nicht per ISR.

Ich sehe momentan keine Grund, warum nicht alle UARTs per ISR senden und 
empfangen können sollten!!!

THX

von jo mei (Gast)


Lesenswert?

Norman P. schrieb:
> Wenn ich
> eine Schleife habe, aus der der Kontroller nicht wieder herauskommt

... dann hast du grob falsch programmiert. Endlos-Schleifen
überwacht man mit Status und sinnvollen Abbruch-Kriterien
damit man wieder herauskommt. Entweder ich bekomme ein Zeichen
oder nicht, beide Ereignisse kann ich gezielt behandeln und
muss nicht "aus Verzweiflung" einen Reset auslösen.

Ist dir bewusst dass ein Watchdog-Reset dein Programm ganz von
vorne anfangen lässt und deine zeitaufwendige Neuinitialisierung
durchläuft? Kopfschüttel!

Die Magic Numbers die überall im Programm verststreut sind
macht hier niemanden Freude. Sie erfordern nämlich jedesmal
einen Blick ins Datenblatt ob das eine oder andere Bit
richtig gesetzt ist. Hier nur ein Auszug als Beispiel:
1
    while((UCSR0A & 0x40) == 0x40) //TXC  == 1 ?
2
    {
3
       watchdog_reset();
4
    }
5
    UDR0 = 0x0D;   //sende CR, damit TXC flag setzen
6
    SREG |= 0x80;  //global INT an

Warum wohl hat Atmel sinnvolle Namen für die Register-Bits
vergeben? Für meine Begriffe musst du deine Programmierung
überdenken und (fast) ganz von vorne anfangen.

Ich kann dir den Fehler auch nicht direkt nennen (ich habe keine
Lust mich mit derart vielen WD-Reset-Bedingungen herumzuschlagen)
aber mit dieser Programierung scheint mir das zu fehleranfällig
zu sein.

Nebenschauplatz: in den Sources sind wild Tabs und Spaces gemischt
sodass beim Zitiern von Codeschnipseln hier im Forum ein wildes
"Getabbe" entsteht. Im allgemeinen werden Tabs als eine grosse
Menge an Spaces interpretiert sodass es oft eine Qual wird die
Kommentare im Sourcecode zu lesen.

von jo mei (Gast)


Lesenswert?

jo mei schrieb:
> Ist dir bewusst dass ein Watchdog-Reset dein Programm ganz von
> vorne anfangen lässt

Ich meinte natürlich einen Reset den der Watchdog auslöst.

von Norman P. (norman_p)


Lesenswert?

OK, über den Sinn des Watchdog-Reset kann man streiten. Das tut aber 
nichts zum eigentlichen Problem. Im "Normalzustand" sollte der Watchdog 
niemals auslösen. Wenn man aber Medizinprodukte herstellt, sind ein 
externer Hardware- und ein interner Software-Watchdog notwendig!!! 
Weiterhin sind die Atmelstudio Includes äußerst kontraproduktiv, wenn es 
um Softwarevalidierung geht.
Aber egal ... - ein Programm sollte das Tun, was von ihm erwartet wird.
@Tabs: Ich benutze nur Privat das Atmelstudio und da schreibe ich den 
Source kein Zweites Mal. Ansonsten hat jeder seinen eigenen 
Programmierstil und in Unternehmen soll dieser dann vereinheitlicht 
werden. -> Einrückung, Klammern etc.

Nun zum Problem: Der ATM 128 mit 2 Uarts kann nur mit UART0 asynchrone 
Übertragung (lt. Datenblatt). Die UART1 geht dann nur als synchrone 
UART.
Bei ATXMega gehen alle UARTs asynchron, wie man dies erwarten würde.
Im Datenblatt des ATM2560 steht dazu nichts, daß nur UART0 asynchron 
betrieben werden kann und die restlichen UARTs nur im synchronen 
Betrieb. Offensichtlich ist dieses Feature hier auch zugegen, was die 
Nutzung der UARTs einschränkt.

BITTE weitere POSTs nur zum PROBLEM!

von Einer K. (Gast)


Lesenswert?

Norman P. schrieb:
> hat jemand alle vier oder mindestens zwei UART's des ATM2560 mit RX und
> TX Interrupt gleichzeitig am Laufen?

Ja!
Mein Arduino kann das....
Es ist also nicht unmöglich.

Jetzt wollte ich dein Programm testen, aber das scheitert schon an der 
unsäglichen Groß-Kleinschreibung der Dateinamen.

Also: Ich gebe auf.

von Spess53 (Gast)


Lesenswert?

Hi

>Nun zum Problem: Der ATM 128 mit 2 Uarts kann nur mit UART0 asynchrone
>Übertragung (lt. Datenblatt). Die UART1 geht dann nur als synchrone
>UART.

Wie kommst du auf dieses schmale Brett? Wenn mit ATM 128 der ATMega128 
gemeint ist besitzt dieser zwei identische USARTs. Beide können sowohl 
asynchron als auch synchron betrieben werden. Genau wie im Datenblatt 
beschrieben.

>Im Datenblatt des ATM2560 steht dazu nichts, daß nur UART0 asynchron
>betrieben werden kann und die restlichen UARTs nur im synchronen
>Betrieb. Offensichtlich ist dieses Feature hier auch zugegen, was die
>Nutzung der UARTs einschränkt.

Meinst du weshalb beim Ardudingsda Mega 2560 alle XCKn-Anschlüsse (die 
für synchronen Betrieb notwendig sind) unbelegt sind. So doof sind noch 
nicht mal die Arduidioten.

Kann es sein, daß du die Datenblätter etwas falsch verstehst
MfG Spess

von Norman P. (norman_p)


Lesenswert?

@AdurinoFanboy: Danke, da muß ich wohl den Ardurino Code mal 
inspizieren.

@Spess53: Es geht hier nicht um zu blöd, sondern daß es mir bei dem ARD 
ATM2560 Board einfach nicht gelungen ist, alle oder mind. 2 UARTS unabh. 
voneinander zu betreiben. Ich nutze den RX und den UDRE Interrupt. 
Vielleicht muß ich den TX-Interrupt nutzen und/oder dann in der ISR das 
entsprechende Interrupt-Flag zurücksetzen. Das was ich zum ATM128 
geschrieben habe, bezieht sich auf den Kompatibilitätsmode und steht 
auch so im Datenblatt. (Wenn das Fusebit M103 gesetzt ist.) Wenn es 
nicht gesetzt ist und der ATM im ATM128 Mode ist, sollten die beiden 
UARTS gleichwertig sein.
Ich suche jedenfalls nach einer Lösung für mein Problem. Dabei geht es 
nicht darum, ob jemand sich zu prasselig anstellt. Ich habe jedenfalls 
schon erlebt, das Chips nicht funktionierten und die Firma Microchip 
still und heimlich einen neuen Chip mit Upgrade unters Volk geschmissen 
hat.
(siehe CAN-Controller mit I2C-Interface)
Daher frage ich halt gern mal im Forum, ob ich weiter Zeit für die Suche 
/ Lösung meines Problems investieren sollte.

Falls jemand Ardurino Programmumgebung nutzt und mal den Source für die 
UARTs anschaut; wäre für mich hilfreich; ob und mit welchen Interrupts 
die die UARTs programmiert haben. Ansonsten suche ich mir das morgen 
selbst raus.


PS: Das Problem sitzt meist 30-60cm vorm Bildschirm ;-) (Ironie in 
eigener Sache)

von Einer K. (Gast)


Lesenswert?

Man, man ...
Selber kucken, macht selber schlau!

Google Tipp:
"Arduino Avr core github "

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.