Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem UART bei AT90CAN128


von ManuelVolk (Gast)


Lesenswert?

Hallo,

ich versuche in Rahmen einer Hausarbeit innerhalb meines Studiums die 
UART-Schnittstelle eines AT90CAN128 in Betrieb zu nehmen.

Nun zu der Frage an dem mein Verständnis zerbricht. Wie ist es möglich, 
dass das Datenregister UDR0 gleichzeitig für Eingang und Ausgang 
zuständig ist. So wie ich es aus dem Datenblatt erlesen habe muss man um 
Daten zu senden diese in das Datenregister UDR0 schreiben und bei 
empfang diese aus UDR0 lesen. Wie wird nun unterschieden ob man lesen 
oder schreiben will?

Ich füge noch meine ini und ISR bei, vielleicht habe ich hier schon 
einen Fehler der mein Unverständnis erklärt. Die Daten werden jeweils in 
einem FIFO abgelegt. Beim Senden aus dem FIFO gelesen und in das 
Datenregister eingetragen. Beim Empfangen aus dem Datenregister gelesen 
und in das FIFO eingetragen. Die Interrupts würden dafür in einer 
zusätzlichen Funktion freigegeben.

Danke schon mal für alle Antworten.


#ifndef fCPU
#define fCPU 16000000
#endif

//global variables
enum E_MODE {Error,no_Error};
volatile uint8_t uart_str_complete = 0;  // 1 .. String komplett 
empfangen


E_MODE set_BAUD(uint16_t BAUD){
  double BAUD_real, Error_value;
  uint16_t UBRR0_value;

  UBRR0_value=fCPU/(16*BAUD)-1;                //calculate the count 
value
  BAUD_real=double(fCPU)/(16*(UBRR0_value+1));//calculate the real baud
  Error_value=(1-(BAUD_real/BAUD))*100;        //calculate the error
  if(0.5 <= Error_value){  //if the error to high return error
    return Error;
  }
  else{      //else write the count value to the UBRR0 register
    UBRR0H = (UBRR0_value>>8)&0xFF;
    UBRR0L = UBRR0_value&0xFF;
    return no_Error;
  }
}


E_MODE init_UART0(uint16_t BAUD){
  if(Error==set_BAUD(BAUD)){
    return Error;
  }
  else{
    //disable multiprocessor mode and double asynchronous mode
    UCSR0A &= ~((1<<MPCM0)|(1<<U2X0));
    UCSR0B &= ~(1<<UCSZ02);            //select frame size 8 bit
    UCSR0C |= ((1<<UCSZ00)|(1<<UCSZ01));  //select frame size 8 bit
    UCSR0C &= ~((1<<UPM00)|(1<<UPM01));    //select no parity mode
    UCSR0C &= ~(1<<USBS0);      //select one stop bit
    UCSR0C &= ~(1<<UMSEL0);      //select asynchronous mode
    UCSR0B |= ((1<<RXEN0)|(1<<TXEN0));    //enable Receiver, Transmitter
    return no_Error;
  }
}


ISR(USART0_RX_vect){  //Interrupt service routine for receive data
  unsigned char temp;
  cli();
  temp = UDR0;
  if(uart_str_complete==0){
    Write_UART_Fifo_RXD(temp);
    if('\n'==temp){
      uart_str_complete = 1;
      Write_UART_Fifo_RXD(uint8_t('\0'));
      UCSR0A &= ~(1<<RXCIE0);  //disable receive complete interrupt
    }
  }
  sei();
}


ISR(USART0_UDRE_vect){  //Interrupt service routine for transmitte data
  unsigned char temp;
  cli();
  if('\0'==temp){
    UDR0=temp;
    uart_str_complete = 1;
    UCSR0A &= ~(UDRIE0);   //disable data register empty interrupt
  }
  else{
    Read_UART_Fifo_TXD(temp);
    UDR0=temp;
  }
  sei();
}

von ManuelVolk (Gast)


Lesenswert?

Falls ich noch relevante Informationen vergessen habe sollte schreibt
bitte was Ihr für eine Antwort noch benötigt.

Gruß

Manuel

von spess53 (Gast)


Lesenswert?

Hi

>    UCSR0A &= ~((1<<MPCM0)|(1<<U2X0));
>    UCSR0B &= ~(1<<UCSZ02);            //select frame size 8 bit
>    UCSR0C |= ((1<<UCSZ00)|(1<<UCSZ01));  //select frame size 8 bit
>    UCSR0C &= ~((1<<UPM00)|(1<<UPM01));    //select no parity mode
>    UCSR0C &= ~(1<<USBS0);      //select one stop bit
>    UCSR0C &= ~(1<<UMSEL0);      //select asynchronous mode
>    UCSR0B |= ((1<<RXEN0)|(1<<TXEN0));    //enable Receiver, Transmitter

Gehts irgendwie noch komplizierter? Außer UCSZn1 und UCSZn0 in UCSR0C 
sind alle Bits in UCSRnA, UCSRnB und UCSRnC nach einem Reset = 0.

MfG Spess

von AVRuser (Gast)


Lesenswert?

Hallo,

> Wie ist es möglich, dass das Datenregister UDR0 gleichzeitig für Eingang
> und Ausgang zuständig ist

Weil es sich physikalisch um 2 Register handelt: eines, das geschrieben 
wird (Senden), und ein weiteres, das gelesen wird (Empfangen). Sie 
werden lediglich über die gleiche Adresse angesprochen.

Übrigens ist es in der ISR nicht notwendig, Interrupts mittels cli() und 
sei() zu manipulieren. Beim Aufruf einer ISR werden von der AVR-CPU 
standardmässig alle weiteren Interrupts so lange gesperrt, bis die 
Routine verlassen wird.

Zum UART-Handling von AVR's gibt es hier im Forum auch ein Tutorial; 
dort einfach mal reinschauen.

von ManuelVolk (Gast)


Lesenswert?

Hallo,

Danke für die schnelle Antwort.
Das erhellt mein Horizont deutlich.
Wegen der Komplexität, ja ist kompliziert aber wird so verlangt.
Sonst argumentiert der Prof, dass ja möglicherweise durch einen 
vorherigen Zugriff die Register schon verändert wurden und wenn man dann 
nicht alles nötige auf 0 setzt funktioniert es nicht.

Habe das zumindest mal so erlebt.

von spess53 (Gast)


Lesenswert?

Hi

>Sonst argumentiert der Prof, dass ja möglicherweise durch einen
>vorherigen Zugriff die Register schon verändert wurden und wenn man dann
>nicht alles nötige auf 0 setzt funktioniert es nicht.

Und was ist mit einem hartem

UCSR0B = ((1<<RXEN0)|(1<<TXEN0))

Dann spart man sich diese Weicheierprogrammierung wie

UCSR0B &= ~(1<<UCSZ02);

MfG Spess

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.