Forum: Mikrocontroller und Digitale Elektronik Uart empfängt immer das selbe


von Loris I. (loris1123)


Lesenswert?

Hallo zusammen,

aktuell arbeite ich für die Hochschule an einem kleinen Projekt mit 
Microcontrollern.
Ich habe hierzu einen Arduino Uno mit ATmega328p, programmiere aber 
nicht über das Arduino Framework sondern in reinem C mit avr-gcc.

Mein Ziel ist es, Daten (Texte) per Kabel an von einem RaspberryPi an 
den Arduino zu senden und diese dort zu verarbeiten. Zum Testen möchte 
ich das empfangene Byte einfach auf 8 LEDs darstellen.

Ich habe also den Ground des Raspis und des Arduino verbunden und 
außerdem TX des Raspi mit RX des Arduino.

Wenn ich nun im Raspi einen Minicom öffne und Tasten drücke, gehen zwar 
LEDs an, jedoch sind es bei fast allen Buchstaben alle LEDs, bis auf die 
letzte. (1111110) Nur bei einigen Buchstaben, zum Beispiel h,j ,k l, 
gehen 2 LEDs aus. Dann wird immer 10011110 ausgegeben.

Wenn ich das ganze über das Arduino Framework mache, funktioniert es 
wunderbar und ich kann auf unterschiedliche Buchstaben reagieren.
Mein Fehler wird also vermutlich in der Initialisierung des UART oder 
der Verarbeitung liegen. Meinen Fehler finde ich jedoch nicht. Ich habe 
ihn mit vielen Beispielcodes, unter anderem aus diesem Forum, 
verglichen.

Ich hoffe, dass ihr mir helfen könnt :)

Viele Grüße
Loris,

Hier noch mein Quellcode:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
// Calculate Baudrate
5
#define BAUDRATE 9600
6
#define BAUD_PRESCALE (((F_CPU / (BAUDRATE * 16UL))) - 1)
7
8
void USART_init(void){
9
    // Set baud
10
    UBRR0H  = (BAUD_PRESCALE >> 8);
11
    UBRR0L  = BAUD_PRESCALE;
12
13
    // Enable UART Receive and Receivecomplete Interrupt
14
    UCSR0B = (1<<RXEN0) | (1 << RXCIE0);
15
16
    // Set frameformat to 8 Data and 1 Stopbit
17
    UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01));
18
}
19
20
void rx_to_led(int rx){
21
    // Maps the parameter to the 8 output-LEDs
22
    int b = rx >> 2;
23
    int d = (rx & 3) << 6;
24
25
    PORTB = b;
26
    PORTD = d;
27
}
28
29
int main(void) {
30
    // Enable 8 Outputs connected to LEDs.
31
    DDRB = (1 << PB0) | (1 << PB1) |(1 << PB2) |(1 << PB3) |(1 << PB4) | (1 << PB5);
32
    DDRD = (1 << PD6) | (1 << PD7);
33
34
    sei();      // Enable global interrupts
35
    USART_init();
36
    while (1){
37
38
    }
39
    return 0;
40
}
41
42
ISR(USART_RX_vect, ISR_BLOCK){
43
    rx_to_led(UDR0);
44
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Passt die Software zur Hardware:
Stimmt die Baudrate?
Ist F_CPU korrekt? (Stichwort: CLKDIV8 Fuse)

von Udo S. (urschmitt)


Lesenswert?

Loris I. schrieb:
> void rx_to_led(int rx){
>     // Maps the parameter to the 8 output-LEDs
>     int b = rx >> 2;
>     int d = (rx & 3) << 6;
>
>     PORTB = b;
>     PORTD = d;
> }

Stimmt diese Funktion? Hast du die mal mit verschiedenen festen Werten 
getestet?

von Udo S. (urschmitt)


Lesenswert?

Mir fällt gerade auf du hast die Variablen als int definiert. Da wird 
arithmetisch geshiftet.
Da wäre ein uint8_t als Typ die richtigere Wahl.

von Ernst O. (ernstj)


Lesenswert?

Stimmt die Zuordnung von Spannnungspegeln und logiscchen Pegeln?
(ist irgendwo etwas invertiert?)

von Loris I. (loris1123)


Lesenswert?

Vielen dank für die viele schnelle Hilfe!

Die Funktion rx_to_led habe ich mit verschiedenen werten getestet. Sie 
funktioniert.

Als F_CPU habe ich 16000000UL gesetzt, da das in vielen Beispielen mit 
diesem µC auch gesetzt war. Wobei ich gestehen muss, dass ich (noch) 
nicht genau verstehe was das genau bedeutet.
Ich lese mich da gerade ein bissche ein und ich kann scheinbar über 
CKSEL0..3 die Clock setzen.
Ich könnte mir vorstellen, dass der Arduino Bootloader hier vielleicht 
verschiedene Werte setzt.
Dem werde ich auf den Grund gehen.

von Udo S. (urschmitt)


Lesenswert?

Loris I. schrieb:
> Die Funktion rx_to_led habe ich mit verschiedenen werten getestet. Sie
> funktioniert.

Meine C Kenntnisse sind jetzt zwar etwas eingerostet aber das du hier 
einem 8 Bit Port ein int zuweist müsste aber mindestens eine Warning 
erzeugen.
Compiliere mal mit allen Warnings an.

von Loris I. (loris1123)


Lesenswert?

Eine Kleinigkeit ist mir gerade noch aufgefallen, die vielleicht auch 
interessant ist:

Beim senden von 'o' leuchtet zuerst 1111110 auf. Beim wiederholen dann 
nur noch 10011110. Bei weiteren Wiederholungen blinken dann die 2. und 
3. LED ganz kurz auf.

von Karl H. (kbuchegg)


Lesenswert?

Loris I. schrieb:
> Vielen dank für die viele schnelle Hilfe!
>
> Die Funktion rx_to_led habe ich mit verschiedenen werten getestet. Sie
> funktioniert.
>
> Als F_CPU habe ich 16000000UL gesetzt, da das in vielen Beispielen mit
> diesem µC auch gesetzt war. Wobei ich gestehen muss, dass ich (noch)
> nicht genau verstehe was das genau bedeutet.

Das bedeutet, dass dein M328p mit 16Mhz läuft. Und das stimmt ja auch. 
Auf einem Arduino Uno ist ein Keramik Resonator mit 16Mhz verbaut.

> Ich lese mich da gerade ein bissche ein und ich kann scheinbar über
> CKSEL0..3 die Clock setzen.

Vorsicht.
Dein Uno ist schon mit der richtigen Einstellung gekommen. Das passt 
schon.

> Ich könnte mir vorstellen, dass der Arduino Bootloader hier vielleicht
> verschiedene Werte setzt.

Nein. Der Boorloader kann diese Werte nicht ändern.
Wozu auch? Der Resonator als Bauteil hat nun mal 16Mhz.

> Dem werde ich auf den Grund gehen.

Dreh erst mal deine Senderichtung um.
Lass den Arduino senden und sieh dir am Pi im Terminalprogramm an, was 
da rauskommt. Es ist immer eine gute Idee, zuerst den Teilnehmer 
empfangen zu lassen, bei dem man das Empfangene einfach sichtbar machen 
kann und dem man soweit vertraut, das alles in Ordnung ist.
Steht diese Kommunikationsrichtung erst mal, dann funktioniert die 
andere Richtung normalerweise sofort. Ist auch logisch: wird ja in 
beiden Fällen die gleiche Baudrate benutzt.

von Loris I. (loris1123)


Lesenswert?

Karl Heinz schrieb:

> Das bedeutet, dass dein M328p mit 16Mhz läuft. Und das stimmt ja auch.
> Auf einem Arduino Uno ist ein Keramik Resonator mit 16Mhz verbaut.

Und wenn ich den internen Resonator verwenden möchte? Der Arduino ist 
nur zum Prototyping gedacht. Später wollen/sollen wir auf einen 
einzellnen Microcontroller umsteigen.

> Dreh erst mal deine Senderichtung um.
> Lass den Arduino senden und sieh dir am Pi im Terminalprogramm an, was
> da rauskommt. Es ist immer eine gute Idee, zuerst den Teilnehmer
> empfangen zu lassen, bei dem man das Empfangene einfach sichtbar machen
> kann und dem man soweit vertraut, das alles in Ordnung ist.
> Steht diese Kommunikationsrichtung erst mal, dann funktioniert die
> andere Richtung normalerweise sofort. Ist auch logisch: wird ja in
> beiden Fällen die gleiche Baudrate benutzt.

Daran hatte ich auch schon gedacht. Das Problem ist nur, dass ich keinen 
Spannungsteiler zur Hand habe, da der Arduino mit 5V läuft und der RPi 
mit 3,3V könnte der Rückweg problematisch werden.

von Karl H. (kbuchegg)


Lesenswert?

Loris I. schrieb:
> Karl Heinz schrieb:
>
>> Das bedeutet, dass dein M328p mit 16Mhz läuft. Und das stimmt ja auch.
>> Auf einem Arduino Uno ist ein Keramik Resonator mit 16Mhz verbaut.
>
> Und wenn ich den internen Resonator verwenden möchte?

Dann musst du an die Fuses ran.

Aber so wie der Ardunio geliefert wurde, läuft er mit 16Mhz durch den 
externen Resonator. Und genau das ist auch der Zweck von F_CPU: den 
Compiler darüber zu informieren, dass der µC mit 16Mhz rennt.

Das ändert aber am Grundproblem nichts.
Mit dem internen Generator (der kein Resonator ist), ist die Genauigkeit 
der Taktfrequenz schlechter als mit dem externen Generator. Wenn du mit 
dem Resonator keine saubere UART hinkriegst, dann kriegst du es mit dem 
interen Takt auch nicht hin.

> Daran hatte ich auch schon gedacht. Das Problem ist nur, dass ich keinen
> Spannungsteiler zur Hand habe, da der Arduino mit 5V läuft und der RPi
> mit 3,3V könnte der Rückweg problematisch werden.

Dann besorg dir 2 Widerstände.
Das Stochern im Nebel muss aufhören. Raten ist ein schlechter Ratgeber, 
auch wenns manchmal nicht anders geht.

: Bearbeitet durch User
von MWS (Gast)


Lesenswert?

Loris I. schrieb:
> Und wenn ich den internen Resonator verwenden möchte? Der Arduino ist
> nur zum Prototyping gedacht. Später wollen/sollen wir auf einen
> einzellnen Microcontroller umsteigen.

Es gibt keinen internen Resonator, nur einen RC-Oszillator, der im 
allgemeinen nix für serielle Kommunikation taugt, zu ungenau.

Über den ISP-Anschluss kann man das alles ändern und dauch dafür sorgen, 
dass gar nichts mehr geht.

Ein Bootloader ist sicherer, da kann man nichts verpfuschen, da man 
keinen Zugriff auf die Fuses hat. Ein ATM328 von der Stange wird 
allerdings keinen Bootloader haben, da muss dann der ISP ran.

von Loris I. (loris1123)


Lesenswert?

Ich habe nun den Arduino über den 3,3V Pin des Raspi betrieben. So 
brauche ich keinen Spannungsteiler. Für LEDs scheint es dann nicht mehr 
zu reichen, aber die brauche ich ja vorerst nicht unbedingt.
Was ich gesendet habe, habe ich den Atmega direkt zurücksenden lassen.
Minicom gibt mir beim senden von a-z folgendes:

yz{|}~hijklmnoxyz{|}~xyz

von Stefan F. (Gast)


Lesenswert?

3,3V reichen für rote, gelbe und grüne LED's aus.

Die Werte für die Baudraten-Initialisierung berechnet man normalerweise 
mit hilfe von Makros aus der AVR C Library: 
http://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html
1
#define BAUD 9600
2
#include <util/setbaud.h>
3
UBRR0H = UBRRH_VALUE;
4
UBRR0L = UBRRL_VALUE;
5
#if USE_2X
6
    UCSR0A |= (1 << U2X);
7
#else
8
    UCSR0A &= ~(1 << U2X);
9
#endif

von Loris I. (loris1123)


Lesenswert?

Stefan Us schrieb:
> 3,3V reichen für rote, gelbe und grüne LED's aus.
>
> Die Werte für die Baudraten-Initialisierung berechnet man normalerweise
> mit hilfe von Makros aus der AVR C Library:
> http://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html
>
>
1
> #define BAUD 9600
2
> #include <util/setbaud.h>
3
> UBRR0H = UBRRH_VALUE;
4
> UBRR0L = UBRRL_VALUE;
5
> #if USE_2X
6
>     UCSR0A |= (1 << U2X);
7
> #else
8
>     UCSR0A &= ~(1 << U2X);
9
> #endif
10
>

Das wars! Die Baudrate scheint wohl falsch berechnet gewesen zu sein. 
Viele dank!!
Grüße Loris

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.