PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit dem senden von Zeichen per UART



KingTobi
29.10.2008, 17:27
Hi

Ich habe das myAVR 2 USB Board.
Nun möchte ich ein Zeichen vom PC an den Mikrocontroller senden und je nach Zeichen soll reagiert werden.
Nur kommen die Zeichen leider ganz anders an als sie sollen.
Die mitgelieferten Beispiel Programme funktionieren auch nicht.

Mein Testprogramm:



#define F_CPU 3686400
#include <avr\io.h>
#include <util\delay.h>
#include <avr/io.h>
void uartPutString(char *buffer);
//----------------------------------------------------------------------
void uartInit()
{
UBRRL = 23; //9600Baud siehe Baudratentabelle
UCSRB = 8 + 16; //Sender enable, Empfänger enable
}
//----------------------------------------------------------------------
char uartGetChar()
{
char data=0;
//warte bis RX-complete
while (!(UCSRA&128));
//empfangen
data=UDR;
return data;
}
//----------------------------------------------------------------------
void uartPutChar(char data)
{
//warte bis UDR leer ist UCSRA / USR bei z.B.: 2313
while (!(UCSRA&32));
//sende
UDR=data;
}
//----------------------------------------------------------------------
main ()
{
DDRB = 0xFF;
PORTB = 0xFF;
_delay_ms(500);
PORTB = 0x00;

char zeichen;

uartInit();
while (true) // Mainloop
{
zeichen=uartGetChar();

PORTB = (1<<PINB1);
_delay_ms(500);
PORTB = (0<<PINB1);
_delay_ms(500);

if(zeichen=='0')
PORTB = (0<<PINB0);
if(zeichen=='1')
PORTB = (1<<PINB0);

_delay_ms(500);
}
}


Durch die LED an PINB1 kann ich sehen das etwas angekommen ist, aber es ist nicht das was es soll.

Ich habe schon die Baudraten 2400, 9600 und 115200 ausprobiert.
Zum senden bzw. empfangen benutze ich HTerm.

Und wie gesagt, mit den mitgelieferten Beispielprogramm welches ein String an den PC senden soll klappt es auch nicht! Es kommt zwar ein String auf dem PC an aber das ist nur Zeichensalat...

Was kann ich noch probieren?

gruß

PicNick
29.10.2008, 18:03
Am besten, du siehst dir das genau an,
https://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc

KingTobi
29.10.2008, 18:10
Werd ich tun.

Es muss doch aber auch mit den Beispielprogrammen funktionieren!
Wo kann da der Fehler noch liegen?

PicNick
29.10.2008, 18:19
Das ist c-mässig ein Stiefel, auch wenn es scheinbar funktioniert;
if(zeichen=='0')
PORTB = (0<<PINB0);

Ein Bit löschen geht so
PORTB &= ~(1<<PINB0);


Du solltest, so wie in der Wikil, für die Register-Bits die korrekten Symbole verwenden

sowas ist pfui gack:
UBRRL = 23; //9600Baud siehe Baudratentabelle
UCSRB = 8 + 16; //Sender enable, Empfänger enable

Besser:


uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BAUDRATE) - 1);

UBRRH = (uint8_t) (ubrr>>8);
UBRRL = (uint8_t) (ubrr);

// UART Receiver und Transmitter anschalten
// Data mode 8N1, asynchron
UCSRB = (1 << RXEN) | (1 << TXEN);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);



Noch was: Bevor "Hello, world" nicht geht, ist an empfange nicht zu denken

https://www.roboternetz.de/wissen/index.php/Sourcevergleich#GCC_.28Hello.2C_world.29

KingTobi
29.10.2008, 18:25
Nun kommt was anderes an, aber immernoch nicht das richtige...

Mein Programm:



#define F_CPU 3686400
#include <avr\io.h>
//----------------------------------------------------------------------
void uartInit()
{
uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*9600) - 1);

UBRRH = (uint8_t) (ubrr>>8);
UBRRL = (uint8_t) (ubrr);

// UART Receiver und Transmitter anschalten
// Data mode 8N1, asynchron
UCSRB = (1 << RXEN) | (1 << TXEN);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
}
//----------------------------------------------------------------------
void uartPutChar(char data)
{
//warte bis UDR leer ist UCSRA / USR bei z.B.: 2313
while (!(UCSRA&32));
//sende
UDR=(uint8_t)data;
}
//----------------------------------------------------------------------
void print(char buffer[])
{
for (int i=0;buffer[i]!=0;i++)
uartPutChar(buffer[i]);
}
//================================================== ====================
main ()
{
uartInit();
while (true) // Mainloop
{
print("x");
}
}




Edit:
Ich habe das Beispiel aus der Wiki übernommen (die ohne Interupts):



#define F_CPU 3686400 // Taktferquenz des myAVR-Boards
#include <avr\io.h> // AVR Register und Konstantendefinitionen
#include <util\delay.h>

void uart_init()
{
uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*9600) - 1);

UBRRH = (uint8_t) (ubrr>>8);
UBRRL = (uint8_t) (ubrr);

// UART Receiver und Transmitter anschalten
// Data mode 8N1, asynchron
UCSRB = (1 << RXEN) | (1 << TXEN);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);

// Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
do
{
UDR;
}
while (UCSRA & (1 << RXC));
}

int uart_putc (const uint8_t c)
{
// Warten, bis UDR bereit ist für einen neuen Wert
while (!(UCSRA & (1 << UDRE)))
;

// UDR Schreiben startet die Übertragung
UDR = c;

return 1;
}

uint8_t uart_getc_wait()
{
// Warten, bis etwas empfangen wird
while (!(UCSRA & (1 << RXC)))
;

// Das empfangene Zeichen zurückliefern
return UDR;
}

int uart_getc_nowait()
{
// Liefer das empfangene Zeichen, falls etwas empfangen wurde; -1 sonst
return (UCSRA & (1 << RXC)) ? (int) UDR : -1;
}

//----------------------------------------------------------------------
main () // Hauptprogramm, startet bei Power ON und Reset
{
uart_init();

//... // hier Init-Code eintragen
do
{
// Schleifenanfang Mainloop
uart_putc('x');
_delay_ms(50);
}
while (true); // Schleifenende Mainloop
}



Aber immernoch das selbe Ergebnis.

McJenso
29.10.2008, 20:21
Hallo,

wie sind die Fusebits gesetzt?

Gruß

Jens

KingTobi
29.10.2008, 20:27
So sind sie gesetzt:

McJenso
29.10.2008, 20:33
Hallo,

wenn ich das richtig sehe, hast du den internen Oszillator mit 4Mhz aktiviert. Aber rechne ruhig noch einmal mit deinen binären Werten nach.

FuseCalculator (http://www.engbedded.com/cgi-bin/fc.cgi/?P_PREV=ATmega8&P=ATmega8&V_LOW=E3&V_HIGH=D9&O_HEX=Apply+user+values&M_LOW_0x3F=0x23&M_LOW_0x80=0x80&M_HIGH_0x06=0x00&M_HIGH_0x20=0x00&B_SPIEN=P&B_SUT0=P&B_CKSEL3=P&B_CKSEL2=P&B_BOOTSZ1=P&B_BOOTSZ0=P)

Gruß

Jens

KingTobi
29.10.2008, 20:51
Hab schon andere ausprobiert
Bin jetzt auf "Ext Crsytal.... 1k ck+64ms.."

Die Ausgabe ist nun anders aber immernoch nicht korrekt...
Auf dem Board sitzt ein 3,6864MHz Oszilator.

Edit:
Wenn ich ne Null an den PC sende bekomm ich auch ne 00, wenn ich was anderes sende bekomm ich immer C0

McJenso
30.10.2008, 17:10
Hallo,

es hilft nichts, andere Fusebits zu probieren. Es helfen nur die richtigen. O:)

Ändere


uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*9600) - 1);


in



uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*9600UL) - 1);


Gruß

Jens

KingTobi
30.10.2008, 17:28
Also das UL bringt nichts...

Nun geht es wenn ich die Zeile so umgeändert:


uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*38400));

Also -1 weg, und auch nur mit der Baudrate 38400...
War ein Zufallstreffer, ist also noch lange nicht die Lösung des Problems. Aber wenigstens kann ich nun erstmal weiter testen

McJenso
30.10.2008, 18:03
Hallo,

interessant, kannst du mal schreiben, mit welchem Compiler du arbeitest? Ich hatte mich schon bei deinem true im Beispielcode gewundert. Ich habe es mal im AVR-Studio simuliert. Ohne das UL wird der Ausdruck in der Klammer mit nur 16 Bit gerechnet.

Gruß

Jens

KingTobi
30.10.2008, 18:35
Also ich benutze das Workpad Plus mit WinAvr.
Ich werde mir die Tage aber mal das AVR-Studio installieren.

Das Workpad PLUS bietet einfach nichts was für richtiges Programmi9eren erforderlich ist, alleine schon ohne einen Debugger, bzw. eine ordentliche Simulation ist die Fehlersuche nicht leicht...

EDIT:
Mit dem http://www.gjlay.de/helferlein/avr-uart-rechner.html
Kann ich die passenden Werte für ubrr ausrechnen, so funktioniert es schonmal

McJenso
30.10.2008, 20:20
Hallo,

Avr-Studio nutzt auch WinAvr. Was mich halt wundert ist, dass 'true' da eigentlich nicht definiert ist. Der Simulator von Avr-Studio ist schon nicht schlecht. Man darf ihn aber auch nicht überschätzen.
Wenn du Werte von der Seite einsetzt, dann geht es jetzt?
Die 23 bei 9600 Baud ist genau der Wert, der hierbei


uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*9600UL) - 1);

ausgerechnet wurde. Wenn ich 16*9600 in 16 Bit rechne bekomme ich ein ubrr von 162. Wenn du damit an den PC sendest ist dein Startbit schon so lang, dass Teile als Datenbits erkannt werden. Vielleicht möchtest du ja doch noch einmal in der Richtung ermitteln.

Gruß

Jens

KingTobi
30.10.2008, 20:29
Also ich nutze den internen 4MHz Oszilator.
das wäre dann bei 9600 Baud ein Wert von 25.

Bei 4MHz und mit "UL" funktioniert es auch!

Mit 4 MHz hatte ich es schon vorher probiert, nur leider ohne das "UL".
Also, es geht jetzt! Danke für eure Hilfe!!


Zu dem "true":
Das steht da nur drin weil ich den teil aus einem Beispiel habe, ich selber setz da immer ne 1 ein.
Warum es mit true geht, keine Ahnung, so tief hab ich mich mit dem WinAVR noch nicht beschäftigt, programmiere sonst mit anderen Compilern.

EDIT:
Vom PC zum Testboard funktioniert jetzt auch!
Nochmal Danke.