PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega32/STK500 -UART senden/empfangen klappt nicht



Leuchtturm
12.01.2007, 16:28
Hi,

ich hoffe, ich oute mich mit meinem ersten Posting nicht gleich als Volldödel

:oops:

ich bin was Mikrocontroller angeht ein blutiger Anfänger und hänge jetzt schon bei diesem Anfangsproblem fest und komme ohne Hilfe nicht weiter.

Aaaalso, hier die Beschreibung meines kleinen "Problemchen"

Ich habe mir von Reichelt das Entwicklerboard STK500 besorgt und mit einem Atmega32 bestückt.

Programmierumgebung ist AVR Studio 4 und WinAVR (beides frisch runter geladen), ich programmiere in C (ich versuch´s).

Ich stelle über das Terminalprogramm TerraTerm die Verbindung her und möchte ein Zeichen, welches ich an den AVR sende einfach nur zurück gesendet und auf der Terminalschirm dargestellt haben, mehr nicht. Leider klappt´s nicht.

Port A ist als Ausgang definiert, an dem LED´s hängen.

Grundsätzlich funktioniert die Kommunikation irgendwie schon, d.h. ich kann senden, der AVR empfängt was und schickt auch was zurück.
Allerdings nur, wenn ich im Terminalprogramm eine wesentlich geringere Baudrate (=1200) einstelle als eigentlich laut Programm vorgesehen (=9600). Komischerweise werden die nebeneinanderliegenden Tasten "n", "m", ";", ".""-",die Tasten "h", "j", "k","l" und noch einige andereTasten dann richtig zurück gesendet, der Rest aber nicht, z.B. für ein"b" bekomme ich ein "z" zurück geliefert.

Wo ich mir jetzt überhaupt nicht sicher bin, ist die Frage, ob die Initialisierung des UART so richtig ist, oder ob da noch was fehlt und ob der Programmablauf so funktionieren kann.

Könnte jemand mal ein Auge aufs Programm werfen?

Besten Dank im Voraus und ein schönes Wochenende!

Gruß
Leuchtturm



#include <avr/io.h>

/* CPU Frequenz */
#define F_CPU 3686400L

/* UART Baud Rate */
#define UART_BAUD_RATE 9600L

/* USART Registerdefinitionen*/
#define UBRRL _SFR_IO8(0x09)
#define UCSRB _SFR_IO8(0x0A)
#define UCSRA _SFR_IO8(0x0B)
#define UDR _SFR_IO8(0x0C)
#define UBRRH _SFR_IO8(0x20)
#define UCSRC UBRRH
#define URSEL 7

void uart_init(void)
{
uint16_t ubrr = (uint16_t) ((uint32_t)F_CPU/(16*UART_BAUD_RATE) - 1);
UBRRH = (uint8_t) (ubrr>>8);
UBRRL = (uint8_t) (ubrr);

UCSRB |= ( 1 << RXEN )| ( 1 << TXEN ); //Receive/transmit enablen
UCSRC =(1<<URSEL) |(1<<UCSZ1)|(1<<UCSZ0); //Frame 8/N/1
}

int main()
{
unsigned char test;
DDRA = 0xff;

uart_init();

while(1)
{
while (!(UCSRA & (1<<RXC))); // warten bis Zeichen verfuegbar

test=(unsigned char)UDR;
PORTA=test;

while (!(UCSRA & (1<<UDRE))); // warten bis UDR bereit für neuen Wert

UDR=test;
}
return 0;
}

p_mork
12.01.2007, 16:50
Hallo Leuchtturm,
die main scheint richtig zu sein, es liegt also wahrscheinlich an der uart_init. Ich weiss zwar nicht genau, was da falsch ist, aber vllt klapp es so:



void uart_init()
{
UBRRL=23;
UBRRH=0;
UCSRC=(1<<URSEL)|(3<<UCSZ0);
UCSRB=(1<<TXEN)|(1<<RXEN);
}


kann auch sein, dass die Baudrate beim Terminal irgendwiwe falsch generiert wird bzw andere Einstellungen wie Parity, Databits oder Stopbits nicht richtig eingestellt sind.

MfG Mark

MartinFunk
12.01.2007, 16:57
Hi Lechtturm,
schau mal im datenblatt unter usart da gibt es beispielfunktionen die auch funktionieren.

MfG Martin

robby-fant
12.01.2007, 16:59
http://www.mikrocontroller.net/forum/2

schau da oben hin, hier im forum ist das know how dafür nicht hoch genug. in dem anderen forum gibt es schon etliche beispiele für das board.

Leuchtturm
12.01.2007, 17:17
@Mark

Danke für den Versuch. Ich hab´s ausprobiert, bringt aber absolut keine Änderung.

Einstellungen im Terminalprogramm sind auch 8/N/1

@Martin

Du meinst im Datenblatt zum Atmega32? Hmmm, irgendwie sind das - für mich jedenfalls - alles nur unzusammenhänge Code-Schnipsel.

@robby-fant

Is ja nicht so, dass ich da nicht schon geschaut hätte. Aber wenn man sich mal die Antworten anschaut, die da kommen... boahh ey. Das mit dem "blutigen Anfänger" war ernst gemeint und in dem Forum sammeln sich irgendwie nur die Freaks. Ich dachte, ich finde hier eher jemanden, der sich auf gleichem bzw. angepasstem Niveau mit mir unterhält.

Vielleicht kommt ja noch jemand mit der Lösung.

MartinFunk
12.01.2007, 17:20
Nein Das sind keine codeschnipsel sondern funtionen.

MfG Martin

Leuchtturm
12.01.2007, 17:26
Na gut, dann eben keine Code-Schnipsel sondern Funktionen.

Die muss man aber auch erstmal zu einem funktionierenden Programm zusammen basteln.

Ich habe das oben gepostete Programm wenigstens soweit verstanden und nicht einfach nur zusammen kopiert. Ich will ja eigentlich nur wissen, warum´s nicht so läuft, wie ich´s mir gedacht habe.

Micro5
13.01.2007, 00:13
Hallo

also ich bin mir nicht so sicher, aber da ich mich vor kurzem auch mit der UART des Atmega32 beschäftigt habe, habe ich das ganze mal mit meinem Programm verglichen. Ich weis allerdings nicht, ob diese Änderungen überhaupt eine Rolle spielen.

1. Ich habe statt #define UART_BAUD_RATE 9600L
das hier bei mir stehen #define BAUD 19200UL
Demzufolge würde bei dir ein U fehlen. Genau das selbt wäre bei der Frequenz #define F_CPU 3686400L : U fehlt

2. uint16_t ubrr = (uint16_t) ((uint32_t)F_CPU/(16*UART_BAUD_RATE) - 1);
Bei dieser Zeile habe ich zwei Klammern mehr, die Zeile sieht, wenn man sie so schreiben würde bei mir dann so aus:
uint16_t ubrr = (uint16_t) (((uint32_t)F_CPU/(16*UART_BAUD_RATE)) - 1);

Dadurch subtrahiert er nämlich erst nach der Division.

Ich weis allerdings nicht, ob das überhaupt damit zu tun hat, es sind nur kleine Unterschiede, die mir zu meinem Programm aufgefallen sind.

Wenn du möchtest, kann ich dir mal das Programm von mir schicken.

Gruß Micro5

Leuchtturm
13.01.2007, 14:12
Hi Micro,

- das "U" ändert den Datentyp in unsigned. Ich hab´s mal probehalber geändert, das Problem bleibt.

- die Klammer dürfte auch nichts ändern, da Punktrechnung vor Strichrechnung gilt - ich hab´s trotzdem mal geändert, das Problem bleibt.

Schick mir bitte mal Dein Programm, vielleicht geht das ja bei mir.

Welches Terminalprogramm benutzt Du? Vielleicht macht das ja bei mir die Probleme?

Bis dahin
Gruß
Leuchtturm

Micro5
13.01.2007, 16:44
Hallo

also ich benutze zum Testen im Moment das Programm "Terminal", hab es mal mit angehängt. Später werde ich dann noch ein C++ Programm dazu schreiben, zum Testen funktioniert das aber einwandfrei.
Mein Quellcode sieht so aus:


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


// Sollte schon im Makefile definiert sein.
// In dem Fall hier einfach löschen.
#define F_CPU 7372800UL

#define BAUD 19200UL
#define UBRR_BAUD ((F_CPU/(16L*BAUD))-1)

// USART initialisieren
void uart_init(void)
{
// Baudrate einstellen (Normaler Modus)
UBRRH = (uint8_t) (UBRR_BAUD>>8 );
UBRRL = (uint8_t)UBRR_BAUD;

// Aktivieren von receiver und transmitter
UCSRB = (1<<TXEN) | (1<<RXEN);

// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
//UCSRC |= (1<<URSEL)|(3<<UCSZ0);
}

int main(void)
{
uint8_t buffer;

// USART initialisieren
uart_init();

while (1)
{
// Warten bis Daten empfangen wurden
while ( !(UCSRA & (1<<RXC)) );

// Empfangsregister auslesen
buffer = UDR;

// Warten bis der Sendepuffer frei ist
while ( !( UCSRA & (1<<UDRE)) );

// Daten in den Puffer schreiben und damit senden
UDR = buffer;


}
return 0;
}


Bei mir funktioniert der mit Terminal. Natürlich müsstet du dann auch noch die entsprechenden Werte im Quelltext ändern (Frequenz..).

Das Programm Terminal sollte von der Bedienung relativ selbsterklärend sein. Einfach entsprechenden Werte einstellen und Open klicken, in Text senden Box klicken, was schreiben und dann sollte normalerweise der Text, den man geschrieben hat im Feld rechts daneben erscheinen.

Gruß micro5

Leuchtturm
15.01.2007, 11:16
Hi Micro5,

besten Dank fürs online-stellen Deines Quellcodes. Ich habe den Quelltext 1 zu 1 in mein AVR-Studio kopiert, Frequenz und Baudrate geändert, kompiliert, übertragen und ausprobiert - keine Änderung.

Dein Terminalprogramm habe ich auch ausprobiert. Es liefert aber auch genau das zurück, was mein anderes Terminalprogramm TerraTerm auch zurück gibt.

Irgendwo ist also noch der Wurm drin. Ich denke, ich werde es jetzt doch wie vorgeschlagen mal im Mikrocontroller-Forum probieren.

Besten Dank für Eure Hilfe bis hierhin.

Grüße
Leuchtturm

D'oh
15.01.2007, 20:31
Hi Leuchtturm

hast du die Fusebits des Atmegas richtig gesetzt? Wenn du einen neuen eingesetzt hast, wovon ich mal ausgehe, musst du noch die Fusebits einstellen, damit er auch mit dem externen Quarz getaktet wird, ansonsten läuft er mit dem intern 1MHz oszillator und dann stimmt die ganze Berechnung für die Baudrate nicht mehr. Dadurch kommt es dann zu falsch übertragenen Zeichen wie bei dir.

Gruß D'oh

Leuchtturm
16.01.2007, 15:02
Hi D´oh,

wie Du schon sagst, war die Baudratenberechnung das Problem.

Ich habe das Programm nach Hilfestellung im Mikrocontroller-Forum etwas abgeändert und nun läuft das wie gewünscht:

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

/* CPU Frequenz */
#define F_CPU 1000000UL //Frequenz 1 Mhz

#define BAUD 9600UL //Baudrate


// USART initialisieren
void uart_init(void)
{
// Baudrate einstellen (Normaler Modus)
#if F_CPU < 2000000UL
UCSRA = (1 << U2X);
UBRRL = F_CPU / (8 * BAUD) - 1;
#else
UBRRL = F_CPU / (16 * BAUD) - 1;
#endif

// Aktivieren von receiver und transmitter
UCSRB = (1<<TXEN) | (1<<RXEN);

// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

int main(void)
{
uint8_t buffer;

DDRA=0xff; //Port A als Ausgang

// USART initialisieren
uart_init();

while (1)
{
// Warten bis Daten empfangen wurden
while ( !(UCSRA & (1<<RXC)) );

// Empfangsregister auslesen
buffer = UDR;

if(buffer==0x31) //Wenn der PC das Zeichen "1" sendet,
PORTA=0x01; //dann die erste LED ausschalten
else //sonst
PORTA=0x00; //alle LED´s ein

// Warten bis der Sendepuffer frei ist
while ( !( UCSRA & (1<<UDRE)) );

// Daten in den Puffer schreiben und damit senden
UDR = buffer;
}
return 0;
}

Grüße
Leuchtturm