www.mikrocontroller.net

Forum: Compiler & IDEs USART Routine von ATMEL


Autor: Matthias (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe auf der Atmel Seite unter
http://www.atmel.com/dyn/products/app_notes.asp?fa...
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 ////////////////////////////////

#define USART_RX_BUFFER_SIZE 128
#define USART_TX_BUFFER_SIZE 128
#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )
#define USART_TX_BUFFER_MASK ( USART_TX_BUFFER_SIZE - 1 )

#if (USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK)
  #error RX buffer size is not a power of 2
#endif
#if (USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK)
  #error TX buffer size is not a power of 2
#endif

static unsigned char USART_RxBuf[USART_RX_BUFFER_SIZE];
static volatile unsigned char USART_RxHead;
static volatile unsigned char USART_RxTail;
static unsigned char USART_TxBuf[USART_TX_BUFFER_SIZE];
static volatile unsigned char USART_TxHead;
static volatile unsigned char USART_TxTail;

void USART_Init ( unsigned int baudrate );
unsigned char USART_Receive ( void );
void USART_Transmit ( unsigned char data );


// Das ist das kurze Hauptprogramm ////////////////////////////////

#include "USART.h"
#include <avr/Interrupt.h>

int main ( void )
{
  USART_Init( 11 );

  sei();

  while(1)
  {
    USART_Transmit( USART_Receive() );
  }
  
  return 0;  
}


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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
void USART_Init ( unsigned int baudrate )
{
  unsigned char x;

  UBRRH = (unsigned char) (baudrate>>8);
  UBRRL = (unsigned char) baudrate;

  UCSRB |= ( (1 << RXCIE) | (1 << RXEN)  | (1 << TXEN)  );
  UCSRC |= (1<<URSEL) | (1<<USBS) | (1<<UCSZ1) | (1<<UCSZ0);

  x = 0;

  USART_RxTail = x;
  USART_RxHead = x;
  USART_TxTail = x;
  USART_TxHead = x;
}



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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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)?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, sind die Standardeinstellungen der STK 500

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: xyz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du kein Englisch?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: xyz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo wird in deinem Programm die Baudrate eingestellt?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

??

USART_RxBuf[tmphead] = data;

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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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....

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wo wird in deinem Programm die Baudrate eingestellt?

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

  

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: xyz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welchen Wert hat die Variable -> baudrate?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

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

#define USART_RX_BUFFER_SIZE 128
#define USART_TX_BUFFER_SIZE 128
#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )
#define USART_TX_BUFFER_MASK ( USART_TX_BUFFER_SIZE - 1 )

#if (USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK)
  #error RX buffer size is not a power of 2
#endif
#if (USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK)
  #error TX buffer size is not a power of 2
#endif

static unsigned char USART_RxBuf[USART_RX_BUFFER_SIZE];
static volatile unsigned char USART_RxHead;
static volatile unsigned char USART_RxTail;
static unsigned char USART_TxBuf[USART_TX_BUFFER_SIZE];
static volatile unsigned char USART_TxHead;
static volatile unsigned char USART_TxTail;

void USART_Init ( unsigned int baudrate );
unsigned char USART_Receive ( void );
void USART_Transmit ( unsigned char data );
unsigned char DataInReceiveBuffer ( void );

void USART_Init ( unsigned int baudrate )
{
  unsigned char x;

  UBRRH = (unsigned char) (baudrate>>8);
  UBRRL = (unsigned char) baudrate;

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

  x = 0;

  USART_RxTail = x;
  USART_RxHead = x;
  USART_TxTail = x;
  USART_TxHead = x;
}

ISR(SIG_UART_RECV)
{
  unsigned char data;
  unsigned char tmphead;

  data = UDR;

  tmphead = ( USART_RxHead + 1 ) & USART_RX_BUFFER_MASK;
  USART_RxHead = tmphead;

  if( tmphead == USART_RxTail )
  {
    // Buffer overflow
  }

  USART_RxBuf[tmphead] = data;
}

ISR(SIG_UART_DATA)
{
  unsigned char tmptail;

  if( USART_TxHead != USART_TxTail )
  {
    tmptail = ( USART_TxTail +1 ) & USART_TX_BUFFER_MASK;
    USART_TxTail = tmptail;

    UDR = USART_TxBuf[tmptail];
  }
  else
  {
    UCSRB &= ~(1<<UDRIE);
  }
}

unsigned char USART_Receive ( void )
{
  unsigned char tmptail;

  while( USART_RxHead == USART_RxTail );
  tmptail = ( USART_RxTail +1 ) & USART_RX_BUFFER_MASK;

  USART_RxTail = tmptail;

  return USART_RxBuf[tmptail];
}

void USART_Transmit ( unsigned char data )
{
  unsigned char tmphead;
  
  tmphead = ( USART_TxHead +1 ) & USART_TX_BUFFER_MASK;
  while ( tmphead == USART_TxTail );
  
  USART_TxBuf[tmphead] = data;
  USART_TxHead = tmphead;

  UCSRB |= (1<<UDRIE);
}

unsigned char DataInReceiveBuffer ( void )
{
  return ( USART_RxHead != USART_RxTail );
}


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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sry hab die Main vergessen:
int main ( void )
{
  USART_Init( 11 );

  sei();

  while(1)
  {
    USART_Transmit( USART_Receive() );
  }
  
  return 0;  
}

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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab aber schon alle möglichen Werte ausprobiert (mit DB)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sind das die CKSEL Fuses

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Freut mich!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.