Forum: Mikrocontroller und Digitale Elektronik Probleme mit UART AT90CAN128


von ManuelV. (Gast)


Lesenswert?

Hallo Leute,

ich habe ein großes Problem mit der UART-Schnittstelle meines
AT90CAN128. Ich bekomme Sie nicht ans laufen finde aber leider auch den 
Fehler nicht. Vielleicht könnt ihr mir weiterhelfen. Es sollen einfach 
nur einen Zeichen mit Hterm vom PC auf den AT90CAN128 übertragen werden.

Bin blind für den Fehler!

Hier den Code:
1
#define F_CPU 16000000
2
#define UART_MAXSTRLEN 10
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
7
volatile uint8_t uart_str_complete = 0;     // 1 .. String komplett empfangen
8
volatile uint8_t uart_str_count = 0;
9
volatile char uart_string[UART_MAXSTRLEN + 1] = "";
10
enum E_MODE{Error,no_Error};
11
12
13
E_MODE set_BAUD(uint16_t BAUD){
14
  uint16_t UBRR0_value;
15
  UBRR0_value=((F_CPU+BAUD*8)/(16*BAUD))-1;//calculate the count value 
16
  UBRR0H = (UBRR0_value>>8)&0xFF;
17
  UBRR0L = UBRR0_value&0xFF;
18
  return no_Error;
19
}
20
21
E_MODE init_UART0(uint16_t BAUD){
22
  if(Error==set_BAUD(BAUD)){
23
    return Error;
24
  }
25
  else{
26
  //disable multiprocessor mode and double asynchronous mode
27
  UCSR0A &= ~((1<<MPCM0)|(1<<U2X0));
28
  UCSR0B &= ~(1<<UCSZ02);          //select frame size 8 bit
29
  UCSR0C |= ((1<<UCSZ00)|(1<<UCSZ01));  //select frame size 8 bit
30
  UCSR0C &= ~((1<<UPM00)|(1<<UPM01));  //select no parity mode
31
  UCSR0C &= ~(1<<USBS0);    //select one stop bit
32
  UCSR0C &= ~(1<<UMSEL0);            //select asynchronous mode
33
  UCSR0B |= ((1<<RXEN0)|(1<<TXEN0));  //enable reciever, transmitter
34
  UCSR0A |= (1<<RXCIE0);    //enable receive complete interrupt
35
  return no_Error;
36
  }
37
}
38
39
void lamp_control(){
40
  if(uart_str_complete==1){
41
    if(uart_string[0]=='x') PORTA=3;
42
    if(uart_string[0]=='y') PORTA=1;
43
    uart_str_complete=0;
44
  }
45
}
46
47
48
49
ISR(USART0_RX_vect)
50
{
51
  unsigned char nextChar;
52
  // Daten aus dem Puffer lesen
53
  nextChar = UDR0;
54
  if( uart_str_complete == 0 ) {
55
    if( nextChar != '\n' &&
56
    nextChar != '\r' &&
57
    uart_str_count < UART_MAXSTRLEN ) {
58
      uart_string[uart_str_count] = nextChar;
59
      uart_str_count++;
60
    }
61
    else {
62
      uart_string[uart_str_count] = '\0';
63
      uart_str_count = 0;
64
      uart_str_complete = 1;
65
    }
66
  }
67
}
68
69
70
int main(void)
71
{
72
  DDRA=0xFF;
73
  init_UART0(9600);
74
    while(1)
75
    {
76
       lamp_control();  
77
    }
78
  return 0;
79
}

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>  UCSR0A |= (1<<RXCIE0);    //enable receive complete interrupt

Wenn du es so

Beitrag "Re: Verständnisproblem UART bei AT90CAN128"

gemacht hättest, wäre es vielleicht nicht passiert. RXCIE0 befindet sich 
in UCSR0B nicht in UCSR0A.

MfG Spess

von Rudolph (Gast)


Lesenswert?

Ist ja toll, wenn der Code universell ist, bei den paar Zeilen schaue 
ich aber lieber mal ins Datenblatt, man benutzt ja wieder auch nicht 
ständig andere Controller mit ständig anderen Quarzen.

Ohne Gewähr:

void init_USART0(void)
{
    UBRR0 = 103;   // 9600 Baud @ 16 MHz
    UCSR0A = 0x00;
    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); // 8N1
}

Die "103" ist einfach aus dem Datenblatt, die Tabelle ist ja umfangreich 
genug.

von Karl H. (kbuchegg)


Lesenswert?

Rudolph schrieb:
> Ist ja toll, wenn der Code universell ist, bei den paar Zeilen schaue
> ich aber lieber mal ins Datenblatt, man benutzt ja wieder auch nicht
> ständig andere Controller mit ständig anderen Quarzen.

und was bringt dir das?
wenn du mit falschen Ausgangs-Werten operierst, dann kommt da wie dort 
ein falches Ergebnis raus.
Oder traust du deinem Compiler nicht, dass er sowas popeliges wie
((F_CPU+BAUD*8)/(16*BAUD))-1
nicht korrekt ausrechnen kann.

Hinweis: deine heiß geliebten Tabellen im Datenblatt sind genau mit 
dieser Formel erstellt worden.
Alles was du tust, ist dir eine zusätzliche Möglichkeit für einen 
Ablesefehler in den Erstellungsprozess einzubauen.

von Karl H. (kbuchegg)


Lesenswert?

1
  UCSR0A &= ~((1<<MPCM0)|(1<<U2X0));
2
  UCSR0B &= ~(1<<UCSZ02);          //select frame size 8 bit
3
  UCSR0C |= ((1<<UCSZ00)|(1<<UCSZ01));  //select frame size 8 bit
4
  UCSR0C &= ~((1<<UPM00)|(1<<UPM01));  //select no parity mode
5
  UCSR0C &= ~(1<<USBS0);    //select one stop bit
6
  UCSR0C &= ~(1<<UMSEL0);            //select asynchronous mode
7
  UCSR0B |= ((1<<RXEN0)|(1<<TXEN0));  //enable reciever, transmitter
8
  UCSR0A |= (1<<RXCIE0);    //enable receive complete interrupt

das wundert mich nicht, dass du DA den Überblick verlierst. Würde ich 
auch.

Das sind 3(!) Register.
3 Zuweisungen in 3 Zeilen und gut ists. Drüber noch einen Kommentar, was 
eingestellt wird und dann passt das.

: Bearbeitet durch User
von Rudolph (Gast)


Lesenswert?

Karl Heinz schrieb:
> und was bringt dir das?

Viel weniger Text den man im Zweifel komplett durchgehen müsste.
Angefangen bei dem dann auch überflüssigem Define für F_CPU.

Und beim Wechsel der CPU, der Baudrate oder der Taktfrequenz bringt mich 
das dazu das Datenblatt zu öffnen.

von Karl H. (kbuchegg)


Lesenswert?

Rudolph schrieb:
> Karl Heinz schrieb:
>> und was bringt dir das?
>
> Viel weniger Text den man im Zweifel komplett durchgehen müsste.

Ne, muss man nicht. Denn der ist immer gleich.
Es gibt sogar ein #include File, in der diese Berechnung korrekt 
'versteckt' ist.

> Angefangen bei dem dann auch überflüssigem Define für F_CPU.

Dieses überflüssige #define hast du implizit genauso benutzt. Nämlich 
genau zu dem Zeitpunkt an dem du dir die Tabelle im Datenblatt 
rausgesucht hast.

> Und beim Wechsel der CPU, der Baudrate oder der Taktfrequenz bringt mich
> das dazu das Datenblatt zu öffnen.

Siehst du.
Ich setz einfach F_CPU auf den korrekten Wert, bzw. ein entsprechendes
#define BAUD 9600
auf den Wert den ich haben will und den Rest erledigt der Compiler für 
mich.

Das ist mir sogar recht angenehm, denn von F_CPU hängen im Programm 
meistens noch weitere Berechnungen ab, wie zb Wartezeiten beim LCD, wie 
zb Timerwerte, wie zb. Zeitkonstanten bei Zeitsteuerungen, etc., um die 
ich mich dann auch nicht kümmern muss, weil sie der Compiler für mich 
ausrechnet. Alles basierend auf dem Wert von F_CPU.

: Bearbeitet durch User
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.