Forum: Compiler & IDEs USART Routine von ATMEL


von Matthias (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe auf der Atmel Seite unter
http://www.atmel.com/dyn/products/app_notes.asp?family_id=607
eine wie ich finde sehr gute USART Interrupt gesteuerte Routine in C 
gefunden. Diese habe ich nun für meinen ATMEGA8 umgeschrieben. Leider 
kommt nichts zurück. In HTerm und HTerminal stelle ich folgendes ein:

Baudrate 19,2 k
Databits = 8
Stopbits = 1

Ich habe den CHip auf der STK500 und verbinde ihn mit meinem Laptop über 
die 2te Rs-232 Schnittstelle.

// Das ist die Headerfile USART.h ////////////////////////////////
1
#define USART_RX_BUFFER_SIZE 128
2
#define USART_TX_BUFFER_SIZE 128
3
#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )
4
#define USART_TX_BUFFER_MASK ( USART_TX_BUFFER_SIZE - 1 )
5
6
#if (USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK)
7
  #error RX buffer size is not a power of 2
8
#endif
9
#if (USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK)
10
  #error TX buffer size is not a power of 2
11
#endif
12
13
static unsigned char USART_RxBuf[USART_RX_BUFFER_SIZE];
14
static volatile unsigned char USART_RxHead;
15
static volatile unsigned char USART_RxTail;
16
static unsigned char USART_TxBuf[USART_TX_BUFFER_SIZE];
17
static volatile unsigned char USART_TxHead;
18
static volatile unsigned char USART_TxTail;
19
20
void USART_Init ( unsigned int baudrate );
21
unsigned char USART_Receive ( void );
22
void USART_Transmit ( unsigned char data );

// Das ist das kurze Hauptprogramm ////////////////////////////////
1
#include "USART.h"
2
#include <avr/Interrupt.h>
3
4
int main ( void )
5
{
6
  USART_Init( 11 );
7
8
  sei();
9
10
  while(1)
11
  {
12
    USART_Transmit( USART_Receive() );
13
  }
14
  
15
  return 0;  
16
}

// und die USART.c liegt im Anhang
Grüsse
Matthias

von Matthias (Gast)


Lesenswert?

Ok jetzt hab ich meinen Kopf aus dem "A..." gezogen und auf der STK die 
Leitungen verbunden. Hatte ich gestern abgesteckt, argh !

So nun  kommt was an aber nicht das gewünschte.

Im HTerminal hab ich folgende Einstellungen:

Baudrate 19,2 k
Databits = 8
Stopbits = 2

Und die USART_Init hab ich folgendermassen abgeändert.
1
void USART_Init ( unsigned int baudrate )
2
{
3
  unsigned char x;
4
5
  UBRRH = (unsigned char) (baudrate>>8);
6
  UBRRL = (unsigned char) baudrate;
7
8
  UCSRB |= ( (1 << RXCIE) | (1 << RXEN)  | (1 << TXEN)  );
9
  UCSRC |= (1<<URSEL) | (1<<USBS) | (1<<UCSZ1) | (1<<UCSZ0);
10
11
  x = 0;
12
13
  USART_RxTail = x;
14
  USART_RxHead = x;
15
  USART_TxTail = x;
16
  USART_TxHead = x;
17
}

Wenn ich (1<<URSEL) nicht auf eins setze bevor ich UCSRC beschreibe 
krieg ich kein Signal, ist ja auch so im DB beschrieben. Ich bekomme im 
Hterminal eigentlich immer ein "@" Zeichen oder für die meisten ASCII 
Zeichen ein "0xC0".

Grüsse
Matthias

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Baudrate 19,2 k
> USART_Init( 11 );

bedeutet, dass du mit 3,6864 MHz Prozessortakt arbeiten willst. Hast du 
das STK500 auch so eingestellt (XTAL1, OSCSEL Jumper und Einstellung im 
AVR Studio)?

von Matthias (Gast)


Lesenswert?

Ja, sind die Standardeinstellungen der STK 500

von Matthias (Gast)


Lesenswert?

Vielleicht kann das noch weiterhelfen.

Der Compiler gibt mir folgende Warnung raus:

"USART_RxBuf defined but not used"
"USART_TxBuf defined but not used"

Versteh das nicht ?

Grüsse
Matthias

von Matthias (Gast)


Lesenswert?

Also ich bin ehct ratlos, habe jetzt den Polling Modus gemacht, da geht 
auch nichts, versteh das einfach nicht, jetzt kommen immer nur die 
Zeichen 0xC0 oder 0xF8 an. Echt frustrierend und hier weiss anscheinend 
auch keiner Bescheid.

Grüsse
Matthias

von xyz (Gast)


Lesenswert?

Kannst du kein Englisch?

von Johannes M. (johnny-m)


Lesenswert?

Matthias wrote:
> Der Compiler gibt mir folgende Warnung raus:
>
> "USART_RxBuf defined but not used"
> "USART_TxBuf defined but not used"
>
> Versteh das nicht ?
Was ist daran nicht zu verstehen? Es sind zwei Puffer-Arrays definiert, 
die in Deinem Programm aber nicht benutzt werden...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Den ATmega8 hast du auch umgestellt vom 1-MHz-RC-Oszillator auf
externen Takt, ja?

UCSRC brauchst du übrigengs nicht anfassen, wenn du das
Standardframing 8N1 benutzt.

von xyz (Gast)


Lesenswert?

Wo wird in deinem Programm die Baudrate eingestellt?

von Matthias (Gast)


Lesenswert?


??

USART_RxBuf[tmphead] = data;

in USART.c wird in der ISR verwendet.. und
USART_TxBuf auch.

von Matthias (Gast)


Lesenswert?

>Den ATmega8 hast du auch umgestellt vom 1-MHz-RC-Oszillator auf
>externen Takt, ja?

? Hab den internen Takt der STK 500 mit 3,86....

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias wrote:

> USART_RxBuf[tmphead] = data;
>
> in USART.c wird in der ISR verwendet.. und
> USART_TxBuf auch.

Sind aber in USART.c "static" deklariert und damit nur innerhalb
dieses Moduls sichtbar.  Die ISR liegt offenbar woanders.  Aber
solange du uns keinen geschlossen compilierbaren Code zeigst,
kann man hier nur die Kristallkugel befragen.

von Matthias (Gast)


Lesenswert?

>Wo wird in deinem Programm die Baudrate eingestellt?

Na in der USART_Init
1
  UBRRH = (unsigned char) (baudrate>>8);                  
2
  UBRRL = (unsigned char) baudrate;

  

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias wrote:

>>Den ATmega8 hast du auch umgestellt vom 1-MHz-RC-Oszillator auf
>>externen Takt, ja?

> ? Hab den internen Takt der STK 500 mit 3,86....

Woher weiß das aber dein ATmega8?  Den interessiert das einfach
gar nicht, was an seinem XTAL1 passiert, solange du ihm nicht die
low fuse änderst.

von xyz (Gast)


Lesenswert?

Welchen Wert hat die Variable -> baudrate?

von Matthias (Gast)


Lesenswert?

>Aber solange du uns keinen geschlossen compilierbaren Code zeigst,
>kann man hier nur die Kristallkugel befragen.

Naja also die USART.C mit USART.h und dem MainProgramm ist doch normale 
C-Syntax.

Zusammen würde das dann so lauten:
1
#include <avr/Interrupt.h>
2
#include <avr/io.h>
3
4
#define USART_RX_BUFFER_SIZE 128
5
#define USART_TX_BUFFER_SIZE 128
6
#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )
7
#define USART_TX_BUFFER_MASK ( USART_TX_BUFFER_SIZE - 1 )
8
9
#if (USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK)
10
  #error RX buffer size is not a power of 2
11
#endif
12
#if (USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK)
13
  #error TX buffer size is not a power of 2
14
#endif
15
16
static unsigned char USART_RxBuf[USART_RX_BUFFER_SIZE];
17
static volatile unsigned char USART_RxHead;
18
static volatile unsigned char USART_RxTail;
19
static unsigned char USART_TxBuf[USART_TX_BUFFER_SIZE];
20
static volatile unsigned char USART_TxHead;
21
static volatile unsigned char USART_TxTail;
22
23
void USART_Init ( unsigned int baudrate );
24
unsigned char USART_Receive ( void );
25
void USART_Transmit ( unsigned char data );
26
unsigned char DataInReceiveBuffer ( void );
27
28
void USART_Init ( unsigned int baudrate )
29
{
30
  unsigned char x;
31
32
  UBRRH = (unsigned char) (baudrate>>8);
33
  UBRRL = (unsigned char) baudrate;
34
35
  UCSRB |= ( (1 << RXCIE) | (1 << RXEN)  | (1 << TXEN)  );
36
  UCSRC |= (1<<URSEL) | (3<<UCSZ0);
37
38
  x = 0;
39
40
  USART_RxTail = x;
41
  USART_RxHead = x;
42
  USART_TxTail = x;
43
  USART_TxHead = x;
44
}
45
46
ISR(SIG_UART_RECV)
47
{
48
  unsigned char data;
49
  unsigned char tmphead;
50
51
  data = UDR;
52
53
  tmphead = ( USART_RxHead + 1 ) & USART_RX_BUFFER_MASK;
54
  USART_RxHead = tmphead;
55
56
  if( tmphead == USART_RxTail )
57
  {
58
    // Buffer overflow
59
  }
60
61
  USART_RxBuf[tmphead] = data;
62
}
63
64
ISR(SIG_UART_DATA)
65
{
66
  unsigned char tmptail;
67
68
  if( USART_TxHead != USART_TxTail )
69
  {
70
    tmptail = ( USART_TxTail +1 ) & USART_TX_BUFFER_MASK;
71
    USART_TxTail = tmptail;
72
73
    UDR = USART_TxBuf[tmptail];
74
  }
75
  else
76
  {
77
    UCSRB &= ~(1<<UDRIE);
78
  }
79
}
80
81
unsigned char USART_Receive ( void )
82
{
83
  unsigned char tmptail;
84
85
  while( USART_RxHead == USART_RxTail );
86
  tmptail = ( USART_RxTail +1 ) & USART_RX_BUFFER_MASK;
87
88
  USART_RxTail = tmptail;
89
90
  return USART_RxBuf[tmptail];
91
}
92
93
void USART_Transmit ( unsigned char data )
94
{
95
  unsigned char tmphead;
96
  
97
  tmphead = ( USART_TxHead +1 ) & USART_TX_BUFFER_MASK;
98
  while ( tmphead == USART_TxTail );
99
  
100
  USART_TxBuf[tmphead] = data;
101
  USART_TxHead = tmphead;
102
103
  UCSRB |= (1<<UDRIE);
104
}
105
106
unsigned char DataInReceiveBuffer ( void )
107
{
108
  return ( USART_RxHead != USART_RxTail );
109
}

Das heisst ich muss dem ATMEGA8 noch sagen, dass er den Takt von XTAL1 
nehmen soll und nicht einen eigenen Takt. Meinst du das so, dass hab ich 
nicht gewusst. Dachte Standardeinstellung wäre das ein uC auf XTAL1 
hört.

von Matthias (Gast)


Lesenswert?

Sry hab die Main vergessen:
1
int main ( void )
2
{
3
  USART_Init( 11 );
4
5
  sei();
6
7
  while(1)
8
  {
9
    USART_Transmit( USART_Receive() );
10
  }
11
  
12
  return 0;  
13
}

>Welchen Wert hat die Variable -> baudrate?
USART_Init( 11 ); => 11

von Matthias (Gast)


Lesenswert?

Hab aber schon alle möglichen Werte ausprobiert (mit DB)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias wrote:

> Das heisst ich muss dem ATMEGA8 noch sagen, dass er den Takt von XTAL1
> nehmen soll und nicht einen eigenen Takt. Meinst du das so,

Ja.

> dass hab ich
> nicht gewusst.

RTFDatasheet.

> Dachte Standardeinstellung wäre das ein uC auf XTAL1
> hört.

Wie hieß der Spruch früher so schön?  ,,Überlass das Denken den
Pferden, die haben einen größeren Kopf.'' ;-)

Im Ernst: mit dem Datenblatt solltest du dich schon befassen.  In diesem
Falle mit dem Kapitel über die Takterzeugung.

von Matthias (Gast)


Lesenswert?

>Wie hieß der Spruch früher so schön?  ,,Überlass das Denken den
>Pferden, die haben einen größeren Kopf.'' ;-)

Das is aber nett von dir. Da die Pferde ja jetzt für mich denken, 
könntest du mir ja sagen in welchen Registern ich was zu setzen habe um 
das ganze mit dem internen Takt der STK 500 zu betreiben.

Grüsse
Matthias

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias wrote:

> Das is aber nett von dir.

Daher ja auch der Smiley.

> könntest du mir ja sagen in welchen Registern ich was zu setzen habe um
> das ganze mit dem internen Takt der STK 500 zu betreiben.

Du musst die low fuse passend einstellen.  Sie steht per default auf
0xe1.  Eine Möglichkeit, die das gewünschte Ziel errreicht ist, sie
auf 0xe0 zu setzen.

Und woher weißt du nun, wie du das beim nächsten Mal beim nächsten
AVR rausfindest wenn du dir gar nicht die Mühe machst, mal selbst ins
Datenblatt zu gucken?

von Matthias (Gast)


Lesenswert?

Ich hab das Datenblatt die ganze Zeit neben mir und werd jetzt nachsehen 
wo ich deine Lösung finden kann. Das hat mehr Wert, als ständig im 
Dunkel zu tappen. Worte wie "low fuse" sagen mir eben gerade nichts. 
Aber jetzt weiss ich wonach ich suchen muss.

von Matthias (Gast)


Lesenswert?

Sind das die CKSEL Fuses

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias wrote:

> Sind das die CKSEL Fuses

Ja, das sind die entscheidenden dabei, die unteren 4 Bits der low
fuse.  Im Prinzip kannst du auch beliebige Varianten von internem
Quarzoszillator einstellen, da diese auch alle ihren Takt an XTAL1
einlesen, aber 0xe0 (also CKSEL = 0) ist die offizielle Variante
für den externen Takt.

von Matthias (Gast)


Lesenswert?

Ist das OSCCAL Register dann das richtige.

Wenn ja würde ja ein

[c]

OSCCAL = 0xE0;

[c/]

richtig sein. Allerdings bringt das nicht den gewünschten Effekt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Ist das OSCCAL Register dann das richtige.

Das ist nur für den internen RC-Oszillator interessant, aber gerade
den willst du ja nicht nehmen.

Die Fuses sind keine Register.   Die stehen im Abschnitt "Memory
programming", weil man sie nur über die Programmierschnittstelle
einstellen kann.  Das laufende Programm kann die Fuses nicht
ändern.

von Matthias (Gast)


Lesenswert?

Bin hier fündig geworden
http://www.mikrocontroller.net/articles/AVR_Fuses
das werd ich jetzt mal in aller Ruhe durchlesen

von Matthias (Gast)


Lesenswert?

Habn nun folgenden Satz in der STK 500 ANleitung gefunden:

"When using the STK500 software-generated clock system as main clock, 
the target
AVR microcontroller fuses should be configured for “external clock” as 
clock source."

Also als normaler externer Clock einstellen, was für die low-Bits 0000 
bedeuten würde. Start-TIme hätte ich auf 10 gesetzt, um Fehler zu 
vermeiden.

von Matthias (Gast)


Lesenswert?

So nun wieder in der Arbeit, alles an der STK eingestellt und siehe da. 
Das Programm funktioniert 1 a. Ich danke dir  Jörg für die Geduld und 
die Hilfe. Und das mit den Fuses hab ich auch theoretisch und in diesem 
Fall jetzt auch praktisch kapiert.

Grüsse
Matthias

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Freut mich!

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.