Forum: Compiler & IDEs UART Ausgabe


von Michael K. (michael1104)


Lesenswert?

Hi,
ich hab ein Probelem, ich arbeite gerade dass tutorial durch, und habe 
eine frage zur UART Ausgabe... Ich will testweise einfach nur ein x 
ausgeben. Ich habe den ATMega8 und hab auch schon ins Datenblatt 
geschaut, komme aber nicht weiter..

Hier mein Code
#ifndef F_CPU


#define F_CPU 4000000UL
#endif

#define BAUD 9600UL


#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)

#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu 
hoch!
#endif

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


void uart_init()
{
    UCSRB |= (1<<TXEN);
    UCSRC |= (1<<URSEL)|(3<<UCSZ0);

    UBRRH = UBRR_VAL >> 8;
    UBRRL = UBRR_VAL & 0xFF;
}


int main(void)
{
  uart_init();
    while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich 
*/
    {
    }

    UDR = 'x';


}


Vielen Dank schonmal

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bitte.

Michael Kuehn wrote:
> Hi,
> ich hab ein Probelem, ich arbeite gerade dass tutorial durch, und habe
> eine frage zur UART Ausgabe... Ich will testweise einfach nur ein x
> ausgeben. Ich habe den ATMega8 und hab auch schon ins Datenblatt
> geschaut, komme aber nicht weiter..
>
> Hier mein Code

Vielleicht hülft's, die Frage auch zu stellen ;-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Und wo genau ist das Problem?

Du kannst die AVR Checkliste abarbeiten. da steht einiges 
Hilfreiches  zu UART Problemen und mehr drin.

Ich habe bei deinem Code derzeit nur den Verdacht, dass es Probleme mit 
der Taktquelle gibt. Die Definition von F_CPU deutet auf eine externe 
Taktquelle hin, die natürlich 1. vorhanden und richtig angeschlossen 
sein muss und 2. per richtig eingestellte AVR Fuses ggf. zum 
Schwingen gebracht werden muss. Erst dann hat die Angabe F_CPU eine 
Chance im folgenden Quellcode richtig interpretiert zu werden.

In deinem Code wird auch nur ein einzelnes x gesendet. Stelle das doch 
mal auf "Dauerfeuer" um:
1
int main(void)
2
{
3
  uart_init();
4
  for(;;)
5
  {
6
    while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
7
    {
8
    }
9
    UDR = 'x';
10
  }
11
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1) In den AVR-Sheets wird UBRRx vor UCSRx gesetzt. Warum änderst du 
dieses Prozedere?

2) Schreibe hier korrekter, klarer und kürzer
1
UCSRx = ...
anstatt
1
UCSRx |= ...

3) AFAIK sollte man eine Toleranz von +/- 0.2 % einhalten. Ob dein Prog 
richtig rechnet (sieht zumindest mal so aus), kannst zB hier 
gegenkontrollieren:

http://www.gjlay.de/helferlein/avr-uart-rechner.html

Hier noch ne funktionierende init-Funktion:
1
#define F_CPU 4000000
2
#define BAUDRATE 9600
3
#define U2X_BIT 1
4
5
void uart_init(void)
6
{
7
    unsigned short ubrr = -.6 + F_CPU/((16L-8*U2X_BIT)*BAUDRATE);
8
9
    UBRRH = ubrr>>8;
10
    UBRRL = ubrr;
11
12
    UCSRA = (U2X_BIT << U2X) | (1 << TXC);
13
14
    // Enable UART Receiver, Transmitter
15
    // Data mode 8N1, asynchronous
16
17
    UCSRB = (1 << RXEN) | (1 << TXEN);
18
    UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
19
20
    // Flush Receive Buffer
21
    do
22
        UDR;
23
    while (UCSRA & (1 << RXC));
24
}

von Michael K. (michael1104)


Lesenswert?

Das Problem ist, dass ich das gesendete Zeichen nicht auf der seriellen 
Schnittstelle empfange, sondern nur kryptischen Muell...
#define F_CPU 3686400


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


void USART_Init()
{
unsigned int baud = 1200;
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;


UCSRB = (1<<RXEN)|(1<<TXEN);
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

void USART_Transmit()
{



while ( !( UCSRA & (1<<UDRE)) );

UDR = 'x';
}


int main ()
{
  USART_Init();

  for(;;)
  {
  USART_Transmit();
  }
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das ist falsch:

unsigned int baud = 1200;
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;

So kannst du die Baudrate nicht setzen. Im Datenblatt ist eine Tabelle, 
in der steht, welche Werte bei welcher Baudrate in die Register UBRRL 
und UBRRH müssen. Und im AVR GCC Tutorial ist eine Formel, die die Werte 
aus der Wunschbaudrate und der Taktrate berechnet und sogar meldet, wenn 
ein zu grosser Baudratenfehler auftreten würde.


UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
                       ^^^^
Warum hast du das dazu genommen? Das erfordert eine andere Einstellung 
im Terminalprogramm auf dem PC (dem Empfänger): 2 Stoppbits!

Im allerersten Posting hattest du #define F_CPU 4000000UL und jetzt hast 
du #define F_CPU 3686400. Hast du inzwischen die externe Taktquelle 
gewechselt (anderer Quarz?). Wenn du eine externe Taktquelle hast 
(welche?), kannst du mal die Fuses auslesen, einen Screenshot machen und 
hier anhängen. Ich möchte nachsehen, ob die Taktquelle richtig 
eingestellt ist.

von Michael K. (michael1104)


Lesenswert?

So,
das mit den 2 Stoppbits, ist ok, dass habe ich bewusst gewählt und auch 
im Terminalprogramm eingestellt.

Der Takt, wird ja von extern vorgegeben, über einen Quarz der mit 
3,6864MHz läuft...
Wie kann ich die Fuses auslesen? Ich benutze AVRStudio4 und das myavr 
Board

Für 2400baud kann ich die Register so setzen?

UBRRH = 0x50;  //2400
UBRRL = 0x0f;

gemäß Tabelle Datenblatt

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Michael Kuehn wrote:

> UBRRH = 0x50;  //2400
> UBRRL = 0x0f;

Nee. Ich lese im Datenblatt Tabelle 61 den Wert 95. Damit wäre die 
Zeile:

UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen
UBBR = 0x5F; // Alternativ

Oder:

UBRRH = 0; // Selbst 2 8-Bit Zugriffe machen
UBRRL = 95;

Alternativ:

UBRRH = 0; // Selbst 2 8-Bit Zugriffe machen
UBRRL = 0x5F;

> Ich benutze AVRStudio4 und das myavr Board

Die Angabe hilft bereits. Wenn der originale AVR drauf ist, brauchst du 
keine Fuses einzustellen. Das ist dann wohl schon ab Entwickler/Verkauf 
gemacht. Jedenfalls sehe ich keinen Fuses-Einstellschritt in der 
myAVR-Doku.

von Michael K. (michael1104)


Lesenswert?

Vielen Dank für deine Hilfe, es funktioniert...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan B. wrote:

> UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen
> UBBR = 0x5F; // Alternativ

räusper

Wie soll das denn gehen???

&UBRRH = 0x40
&UBRRL = 0x29

Fällt was auf...?

Michael Kuehn wrote:
> #define BAUD 9600UL

Michael Kuehn wrote:
> unsigned int baud = 1200;

Michael Kuehn wrote:
> Für 2400baud kann ich die Register so setzen?

Etwas unentschlossen. Steht das Terminal immer noch richtig?
Flusskontrolle aus?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Johann L. wrote:

> Stefan B. wrote:
>> UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen
>> UBBR = 0x5F; // Alternativ
>
> *räusper*
>
> Wie soll das denn gehen???
>
> &UBRRH = 0x40
> &UBRRL = 0x29
>
> Fällt was auf...?

Nein auf Anhieb nicht. Habe ich das Makro für den 16-Bit Zugriff auf das 
UBRR IO-Register falsch geschrieben?

ADD: Ah, jetzt ja ;-)

Beim Atmega8 liegen die beiden 8-Bit IO-Register nicht nebeneinander im 
Speicher. Wahrscheinlich habe ich das falsch von anderen IO-Registern 
übertragen (ADC?). Es gibt kein einzelnes UBRR Register. Man muss 
getrennt mit UBRRL und UBRRH arbeiten. Danke, ich glaube das werde ich 
nimmer vergessen, rotwerd ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan B. wrote:

> ADD: Ah, jetzt ja ;-)
>
> Beim Atmega8 liegen die beiden 8-Bit IO-Register nicht nebeneinander im
> Speicher. Wahrscheinlich habe ich das falsch von anderen IO-Registern
> übertragen (ADC?). Es gibt kein einzelnes UBRR Register. Man *muss*
> getrennt mit UBRRL und UBRRH arbeiten. Danke, ich glaube das werde ich
> nimmer vergessen, rotwerd ;-)

Ich hab's net ausprobiert, aber eigentlich müsste der Compiler 
warnen/der Linker mackern, daß er UBRR nicht kennt, wenn man diesen 
Zugriff versucht.
Kann mir nämlich kaum vorstellen, daß das Makro in den Headern drinne 
ist (zumindest nicht für ATmega8).

Keine Ahnung, warum Atmel das so seltsam gemacht hat, zudem zusammen mit 
UBSRC als Shadow. Ist wohl ein Silicon-Hack das...

Jepp, ADC packt man besser via 16-Bit-Zugriff an, zumal die Reihenfolge 
auf lo/hi nicht egal ist.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Jetzt hast du mich mit runtergelassenen Hosen erwischt: Ich habe es 
nämlich auch nicht im Compiler ausprobiert, sondern einfach 
hingeschrieben. Wie gesagt, was falsch im Kopp drin ist, kommt nur durch 
Fehlermachen (und einen der es merkt) raus.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan B. wrote:
> Jetzt hast du mich mit runtergelassenen Hosen erwischt:
Und das bei den Temperaturen ... brrr

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.