Forum: Mikrocontroller und Digitale Elektronik UART/USART Echo


von Mark (Gast)


Lesenswert?

Hallo,

ich habe hier eine Anfängerfrage. Ich wollte über Terminal etwas(zb. 
'k') schicken und das gleich zurück bekommen. Kann mir jemand einen Tipp 
geben was ich ändern soll und/oder wo der Fehler ist.

Danke
1
[#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
#define F_CPU 16000000UL
5
//Usart
6
#define Baud 9600UL
7
#define UBRR_Val ((F_CPU/(16*Baud))-1)  
8
9
10
void Usart_Init(void);
11
void Usart_Transmit (void);
12
unsigned char Usart_Receive (void);
13
14
15
unsigned char data;
16
int main()
17
{
18
//Ausgang
19
DDRD|=(1<<PD1);
20
//Eingang
21
DDRD&=~(1<<PD0);
22
Usart_Init();
23
unsigned char data;
24
25
while(1)
26
{
27
Usart_Transmit();
28
Usart_Receive();
29
}
30
return 0;
31
}
32
33
34
//Usart
35
void Usart_Init(void)
36
{
37
//Baudrate einstellen
38
UBRR0H=(UBRR_Val>>8);
39
UBRR0L=UBRR_Val;
40
//Frame-Format:8 Bit Nutzsignal
41
UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);
42
//Sender und Eampfenger initialisieren
43
UCSR0B=(1<<RXEN0)|(1<<TXEN0);
44
}
45
46
47
void Usart_Transmit (void)
48
{
49
//Daten senden
50
while (!(UCSR0A & (1<<UDRE0)));
51
UDR0=data;
52
}
53
54
55
unsigned char Usart_Receive (void)
56
{
57
//Daten empfangen
58
//Solange nichts ankommt, soll er nichts machen
59
while (!(UCSR0A & (1<<RXC0))); 
60
return UDR0;
61
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mark schrieb:
> void Usart_Transmit (void)
> {
> //Daten senden
> while (!(UCSR0A & (1<<UDRE0)));
> UDR0=data;
> }
Es wäre sicher sinnvoll, der Sendefunktion auch das Zeichen zu 
übergeben, das gesendet werden soll - z.B. so:
1
void Usart_Transmit (unsigned char data)
2
{
3
//Daten senden
4
while (!(UCSR0A & (1<<UDRE0)));
5
UDR0=data;
6
}
Die nächste gute Idee ist es, das Zeichen, das die Empfangsfunktion 
liefert, auch zu benutzen:
1
while (1) {
2
 Usart_Transmit(Usart_Receive());
3
}
Wenn du stattdessen die globale Variable data benutzen willst, musst du 
sie zumindest mit dem return Wert von Usart_Receive füllen und dann 
deine alte Usart_Transmit aufzurufen.

: Bearbeitet durch User
von Mark (Gast)


Lesenswert?

> Wenn du stattdessen die globale Variable data benutzen willst, musst du
> sie zumindest mit dem return Wert von Usart_Receive füllen und dann
> deine alte Usart_Transmit aufzurufen.

meinst du so
1
while(1)
2
{
3
4
data=Usart_Receive();
5
Usart_Transmit();
6
}
7
return 0;
8
}

von Timmo H. (masterfx)


Lesenswert?

Data würde ich nicht global machen sondern als Argument für Transmit

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mark schrieb:
> meinst du so

Jo. Wenn du schon die Sache mit dem Argument nicht machen willst, dann 
eben so.

von Mark (Gast)


Lesenswert?

Hallo,

also ich sitze den ganzen Tag an dem Code. Es funktioniet leider nicht 
und ich finde den Fehler nicht. Ich wollte jetzt ASCII '1','2' und '3' 
senden und am Terminal empfangen. Anstatt die Hex-Werte 31, 32 und 33 zu 
erhalten, bekomme ich die Hex-Werte 67 ,B3, 06.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
#define F_CPU 16000000UL
5
//Usart
6
#define Baud 9600UL
7
#define UBRR_Val ((F_CPU/(16*Baud))-1) 
8
9
void Usart_Init(void);
10
void Usart_Transmit (unsigned char data_tx);
11
unsigned char Usart_Receive (void);
12
13
unsigned char data=0;
14
int main()
15
{
16
//Ausgang
17
DDRD|=(1<<PD1);
18
//Eingang
19
DDRD&=~(1<<PD0);
20
Usart_Init();
21
//unsigned char data;
22
while(1)
23
{
24
Usart_Transmit('1');
25
Usart_Transmit('2');
26
Usart_Transmit('3');
27
//Usart_Transmit(Usart_Receive());
28
_delay_ms(5000);
29
//
30
}
31
return 0;
32
}
33
//-----------------------------------
34
//Usart
35
void Usart_Init(void)
36
{
37
//Baudrate einstellen
38
UBRR0H=(unsigned char)(UBRR_Val>>8);
39
UBRR0L=(unsigned char)UBRR_Val;
40
//Frame-Format:8 Bit Nutzsignal
41
UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);
42
//Sender und Eampfenger initialisieren
43
UCSR0B=(1<<RXEN0)|(1<<TXEN0);
44
}
45
//---------------------------------
46
47
void Usart_Transmit (unsigned char data_tx)
48
{
49
//Daten senden
50
//wurde vorherige Byte erfolgreich gesendet wurde und ob der UDR Puffer leer ist
51
while (!(UCSR0A & (1<<UDRE0)));
52
//sende Byte
53
UDR0=data_tx;
54
}
55
//------------------------------------
56
unsigned char Usart_Receive (void)
57
{
58
unsigned char data_Rx;
59
//Ein Zeichen (1Byte) ist über die seielle Schnittstelle in Usart angekommen
60
while (!(UCSR0A & (1<<RXC0))); 
61
//Zeichen wird ausgelesen
62
data_Rx= UDR0;
63
return data_Rx;
64
}


Danke Danke

von Bastian W. (jackfrost)


Lesenswert?

Hast du ein Arduinoboard oder nur den nackten uC ? Wenn du nur den uC 
hast passen die Fuses ?

Gruß Jackfrost

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mark schrieb:
> Anstatt die Hex-Werte 31, 32 und 33 zu
> erhalten, bekomme ich die Hex-Werte 67 ,B3, 06

Sowas ist zu 99% ein Problem mit der Taktfrequenz, denn das Programm 
sollte so klappen. Also checke die Fuses (ext. High Frequency Crystal 
wäre hier richtig) - nicht den internen RC Oszillator, denn der läuft 
mit 8MHz.

Du kannst auch mal direkt 0d103 in UBRR0L schreiben (UBRR0H bleibt auf 
null), das sollte auch die 9600 bit/s ergeben. Stelle auf jeden Fall 
sicher, das auch der Host auf 9600 Baud steht.
Wenn du aus Versehen mit dem internen Oszillator arbeitest, sollte es 
bei UBRR0L = 0d51 laufen.

: Bearbeitet durch User
von Mark (Gast)


Lesenswert?

Matthias S. schrieb:
> Mark schrieb:
>> Anstatt die Hex-Werte 31, 32 und 33 zu
>> erhalten, bekomme ich die Hex-Werte 67 ,B3, 06
>
> Sowas ist zu 99% ein Problem mit der Taktfrequenz, denn das Programm
> sollte so klappen. Also checke die Fuses (ext. High Frequency Crystal
> wäre hier richtig) - nicht den internen RC Oszillator, denn der läuft
> mit 8MHz.
>
> Du kannst auch mal direkt 0d103 in UBRR0L schreiben (UBRR0H bleibt auf
> null), das sollte auch die 9600 bit/s ergeben. Stelle auf jeden Fall
> sicher, das auch der Host auf 9600 Baud steht.
> Wenn du aus Versehen mit dem internen Oszillator arbeitest, sollte es
> bei UBRR0L = 0d51 laufen.

Also ich verwende Arduino Uno. Sorry für die Frage (ich bin ein 
Anfänger), aber ich verstehe nicht was mit dem Fuses gemeint ist. Wie 
soll ich die Fuses checken?

VG

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mark schrieb:
> Wie
> soll ich die Fuses checken?

Gegenfrage: Wie programmierst du den Uno denn? Wenn du da einen ISP 
Programmer benutzt, kann der auch Fuses auslesen. Wenn du den Arduino 
Bootlaoder nimmst, dann geht das nicht.
Der Uno ist normalerweise aber schon richtig auf den 16MHz Quarz 
gefused, so das du da nicht ran musst.
1
// illuminate the Uno/Duemilanove LED for exactly 1 second
2
DDRB |= (1<<PB5);
3
PORTB |= (1 << PB5);
4
_delay_ms(1000);
5
PORTB &= ~(1<<PB5);
Zum Test der Frequenz sollte mit obigem Beispiel die LED auf dem Board 
für genau 1 Sekunde leuchten.

: Bearbeitet durch User
von Mark (Gast)


Lesenswert?

Ich programmiere in AVR Studio 4 und benutze den AVRISP mkII. Tut mir 
leid, ich meinte eigentlich Arduino nano (Atmega328).

von Stefan F. (Gast)


Lesenswert?

Dein Programmieradapter kann Fuses auslesen und verändern. Lies sie aus 
und poste einen Screenshot.

von Mark (Gast)


Angehängte Dateien:

Lesenswert?

Stefan U. schrieb:
> Dein Programmieradapter kann Fuses auslesen und verändern. Lies
> sie aus
> und poste einen Screenshot.

Hier ein Bild.

von Stefan F. (Gast)


Lesenswert?

Da du den Mikrocontroller über ISP programmierst (nicht über Bootloader) 
sollte die BOOTRST Fuse aus sein.

In deinem Fall ist sie an, das bewirkt, dass dein Mikrocontroller 
irgendeinen unbekannten Code ausführt, bevor dein eigentliches Programm 
gestartet wird. Und dieser Code bewirkt möglicherweise die Fehlfunktion.

Die anderen Fuses sehen Ok aus.

Eine kleine Erklärung zu Fuses: Betrachte sie als 
Konfigurationsparameter, die vor dem Programmstart aktiviert werden und 
nicht Bestandteil des Programmes (*.hex Datei) sind. Quasi so wie Jumper 
auf einer PC Komponente.

von Mark (Gast)


Lesenswert?

Matthias S. schrieb:

>
> Du kannst auch mal direkt 0d103 in UBRR0L schreiben (UBRR0H bleibt auf
> null), das sollte auch die 9600 bit/s ergeben.

Der Wert 103 ist doch ein Dezimal-Wert. Warum 0x103?

von Mark (Gast)


Angehängte Dateien:

Lesenswert?

Stefan U. schrieb:
> Da du den Mikrocontroller über ISP programmierst (nicht über
> Bootloader)
> sollte die BOOTRST Fuse aus sein.

Den hacken am BOOTRST ist jetzt weg, BOOTRST ist also aus. Zudem habe 
ich den Programmteil umgeschrieben gemäß:
1
void Usart_Init(void)
2
{
3
//Baudrate einstellen
4
UBRR0H=0x00;
5
UBRR0L=103;
6
7
//Frame-Format:8 Bit Nutzsignal
8
UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);
9
//Sender und Eampfenger initialisieren
10
UCSR0B=(1<<RXEN0)|(1<<TXEN0);
11
}

Damit hat sich leider das Problem nicht gelöst. Wie im Bild zusehen ist, 
erhalte ich immer noch die falschen Hex-Werte.

von Stefan F. (Gast)


Lesenswert?

Schreibe das Programm mal so um, dass es einfach fortlaufend 'A' Sendet, 
mit einigen hundert Millisekunden Pause zwischen jedem Buchstaben. 
Kommen dann am PC 'A' an, oder was anderes?.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mark schrieb:
>> Du kannst auch mal direkt 0d103 in UBRR0L schreiben (UBRR0H bleibt auf
>> null), das sollte auch die 9600 bit/s ergeben.
>
> Der Wert 103 ist doch ein Dezimal-Wert. Warum 0x103?

Nicht 0x103 - ich habe doch extra 0d103 geschrieben, damit es klar wird, 
das es dezimal ist. 0x103 würde doch auch in ein 8-bit Register gar 
nicht reinpassen.
103 ist einfach der ausgerechnete Wert für Baudrate 9600 bei 16MHz Takt.

Ok, klappt trotzdem nicht. Beschreib uns doch mal, wie du TX des AVR mit 
RX des PCs verbindest und was da für Hardware dazwischen ist.

: Bearbeitet durch User
von Mark (Gast)


Angehängte Dateien:

Lesenswert?

Matthias S. schrieb:

> Ok, klappt trotzdem nicht. Beschreib uns doch mal, wie du TX des AVR mit
> RX des PCs verbindest und was da für Hardware dazwischen ist.

ok, danke. Mein MC ist über den DELOCK Adapter USB Seriell 1x9 Pin mit 
dem PC verbunden.

von Mark (Gast)


Angehängte Dateien:

Lesenswert?

Pin 2 (RxD) ist mit Pin PD1 des Contollers und Pin 3 (TxD) ist mit Pin 
PD0 (Rxd) des Controllers verbunden.

von Mark (Gast)


Lesenswert?

Stefan U. schrieb:
> Schreibe das Programm mal so um, dass es einfach fortlaufend 'A'
> Sendet,
> mit einigen hundert Millisekunden Pause zwischen jedem Buchstaben.
> Kommen dann am PC 'A' an, oder was anderes?.

Ich bin deinem Rat gefolgt. Ich habe die while-Schleife geändert. Ich 
bekomme anstatt 0x41 den Hex-Wert 5F.
1
while(1)
2
{
3
Usart_Transmit('A');
4
_delay_ms(100);
5
}

von Werner P. (Gast)


Lesenswert?

Das ist ein USB RS232 Adapter. Den kannst Du nicht verwenden und dich 
freuen wenn dein µC keinen Schaden genommen hat.

Du brauchst einen USB UART TTL Adapter.

von guest (Gast)


Lesenswert?

Werner P. schrieb:
> Du brauchst einen USB UART TTL Adapter.

Nö, braucht er nicht, der ist auf dem Nano in Form eines FT232RL schon 
drauf. Und die genannten Pins (PD0/PD1) hängen da auch schon dran. Er 
braucht ein stinknormales USB-Kabel.

von Werner P. (Gast)


Lesenswert?

So wie ich ihn verstanden habe verbindet er die µC Pins direkt. Und dann 
hat er mit seinem RS232 Adapter ein Problem.

von guest (Gast)


Lesenswert?

Werner P. schrieb:
> So wie ich ihn verstanden habe verbindet er die µC Pins direkt.
> Und dann hat er mit seinem RS232 Adapter ein Problem.

Das hab ich nicht bestritten.

Nur was soll er mit zwei USB UART TTL Adaptern, die auch noch an den 
gleichen Pins hängen? Man könnte natürlich die entsprechenden 
Widerstände vom Board kratzen und den Onboard Chip damit totlegen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

@TE nur zur Erklärung:
1. ist dein Adapter auf einen Pegelbereich von etwa -10V bis +10V am TX 
und RX Anschluss gedacht und
2. ist die Polarität der RS232 Signale genau anders rum als bei UART am 
MC.

Das kann also nicht gehen. Entweder nimmst du das USB Interface, das 
schon auf dem Uno drauf ist, wie o.a. oder du besorgt dir besagtes 
USB-TTL Adapter.

: Bearbeitet durch User
von Mark (Gast)


Lesenswert?

Werner P. schrieb:
> Das ist ein USB RS232 Adapter. Den kannst Du nicht verwenden und
> dich
> freuen wenn dein µC keinen Schaden genommen hat.
>
> Du brauchst einen USB UART TTL Adapter.

Hallo Leute ihr habt vollkommen recht. Es liegt tatsächlich an dem 
Adapter. Ich hatte irgendwo noch einen USB UART TTL Adapter. Diesen habe 
ich jetzt angeschlossen und dazu die Treiber-Software runtergeladen. Und 
es funktionert jetzt.. Danke dass ihr euch die Zeit genommen habt und 
mir geholfen habt.

VG

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.