UART/USART Echo

Gast #4708805
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
}
(Firma: matzetronics) #4708811
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.
Gast #4708854
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
}
Gast #4710208
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
(Firma: matzetronics) #4710398
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.
Gast #4710557
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
(Firma: matzetronics) #4710578
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.
Gast #4710679
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.
Gast #4710778
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.
Angehängte Dateien:
(Firma: matzetronics) #4710943
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.
Gast #4711208
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
}
Gast #4711231
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.
(Firma: matzetronics) #4711239
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.
Gast #4711252
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren