Forum: Mikrocontroller und Digitale Elektronik UART sendet nicht das was er soll (kein offset problem)


von Robert M. (robert_maucher)


Lesenswert?

Hallo,
Ich benutze Robostix bord von Gumstix. (8Mhz Intern, mega128)

An diesem Board möchte ich gern einen UART Verbindung zum PC betreiben.
Leider macht diese Verbindung nicht das was sie soll.

Ich habe zuerst eine eigene Routine geschrieben, die ich auch in anderen 
Projekten schon genutzt habe und die Ports angepasst.
Leider hat das nicht Funktioniert.
Als nächstes habe ich die bewährte UART Routine von Peter Fleury benutzt 
um sicher zu gehen das in der Implementierung nichts falsch ist. leider 
hat das auch nicht geklappt.

Um das Problem einzukreisen habe ich jeden Schnick Schnack entfernt und 
nur eine einfache UART Implementierung genommen.
1
#define USART_BAUDRATE_0 2400UL
2
#define UBRR_0 ((F_CPU+USART_BAUDRATE_0*8)/(USART_BAUDRATE_0*16)-1)
3
int main(void){
4
  UBRR0H = (uint8_t) (UBRR_0>>8);
5
  UBRR0L = (uint8_t) (UBRR_0 & 0xFF);
6
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);
7
  UCSR0C = (3 << UCSZ0);
8
  int16_t i = -12345;
9
  unsigned char s[]={'k','a','t','z','e','\0'};
10
  void USART_Transmit( unsigned char data )
11
  {
12
    /* Wait for empty transmit buffer */
13
    while ( !( UCSR0A & (1<<UDRE0)) )
14
         ;
15
    /* Put data into buffer, sends the data */
16
    UDR0 = data;
17
  }
18
19
  void uart3_puts (char *s)
20
  {
21
      do{   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
22
          USART_Transmit(*s);
23
          s++;
24
      }while (*s);
25
  }
26
27
  while(1){

Ein einzelnens Zeichen ausgeben funktioneirt
1
USART_Transmit('e');//Ausgabe: e

Ein Zeichen aus dem char Array (s)auszugeben auch
1
USART_Transmit(s[3]);//Ausgabe: z

Eine Zahl im Terminal hochzählen lassen mit einer For-Schleife
1
for(i=0;i<=4;i++){
2
        USART_Transmit(i+0x30);
3
        USART_Transmit(',');
4
}//Ausgabe: 0,1,2,3,4

Was nicht Funktioniert ist ein Array in einer Schleife auszugeben.
1
for(i=0;i<=4;i++){
2
        USART_Transmit(s[i]);
3
}//Ausgabe: S (Undefiniertes Zeichen) T (Undefiniertes Zeichen)

Ich hab zuerst an ein Buffer oder Timing Problem gedacht aber wenn ich 
mehrere Zeichen direkt einzeln Ausgebe dann ist die Ausgabe auch 
korrekt.
1
USART_Transmit(s[0]);
2
USART_Transmit(s[1]);
3
USART_Transmit(s[2]);
4
USART_Transmit(s[3]);
5
USART_Transmit(s[4]);
6
USART_Transmit('\n');//Ausgabe: Katze

Ich hoffe das ihr mir Helfen könnt, denn ich bin mit meinem Latein am 
ende.

gruß,
Robert

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>int main(void){
>  UBRR0H = (uint8_t) (UBRR_0>>8);
>  UBRR0L = (uint8_t) (UBRR_0 & 0xFF);
>  UCSR0B = (1 << RXEN0) | (1 << TXEN0);
>  UCSR0C = (3 << UCSZ0);
>  int16_t i = -12345;
>  unsigned char s[]={'k','a','t','z','e','\0'};
>  void USART_Transmit( unsigned char data )
>  {

Die Definition einer Funktion (USART_Transmit) in einer Funktion (main) 
erzeugt bei deinem Compiler keinen Fehler?

Ich spekuliere im Moment darauf, dass in dem Fehlerbeispiel das Feld s 
nicht mehr gültig ist, wenn die Funktion USART_Transmit es abarbeiten 
will.

Meiner Ansicht nach würde es bei der Fehlersuche helfen, wenn du exakt 
die verwendeten Quellcodes anhängen würdest.

von Robert M. (robert_maucher)


Lesenswert?

Nein hat nicht mal ne Warnung gegeben.
Hab die 2 Funktionen jetzt auserhalb der main deklariert.
Aber das Problem besteht Immernoch.

von Karl H. (kbuchegg)


Lesenswert?

Robert Maucher schrieb:
> Nein hat nicht mal ne Warnung gegeben.

Ist eine gcc Erweiterung.

Das wird vielleicht in irgendeiner der nächsten ISO-C Versionen kommen. 
IMHO ist das aber in C nicht wirklich so der große Brüller, so dass es 
eigentlich keinen Grund gibt, so etwas zu machen.

In C regeln sich viele Probleme, bei denen man nach Funktionen in 
Funktionen schreit, durch die Aufteilung in mehrere Source Code Files 
von alleine, so dass dieses Feature nicht sooooo nachgefragt ist.

> Hab die 2 Funktionen jetzt auserhalb der main deklariert.
> Aber das Problem besteht Immernoch.

Wie schon gesagt:
Zeige bitte den kompletten Code

von Karl H. (kbuchegg)


Lesenswert?

Die Funktion uart3_puts änderst du mal so um
1
void uart3_puts (char *s)
2
{
3
  while( *s ) {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
4
    USART_Transmit(*s);
5
    s++;
6
  }
7
}

damit ist schon mal der Fehler, das du das \0 Zeichen mitüberträgst, weg 
(oder war das Absicht?)

von Robert M. (robert_maucher)


Angehängte Dateien:

Lesenswert?

Robert Maucher schrieb:
> Nein hat nicht mal ne Warnung gegeben.
> Hab die 2 Funktionen jetzt auserhalb der main deklariert.
> Aber das Problem besteht Immernoch.

Die Quellcodes ist im Moment nur dieser eine.
1
#include <stdio.h>
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <stdint.h>
5
6
#define USART_BAUDRATE_0 2400UL
7
#define UBRR_0 ((F_CPU+USART_BAUDRATE_0*8)/(USART_BAUDRATE_0*16)-1)
8
9
void USART_Transmit( unsigned char data )
10
  {
11
    /* Wait for empty transmit buffer */
12
    while ( !( UCSR0A & (1<<UDRE0)) )
13
         ;
14
    /* Put data into buffer, sends the data */
15
    UDR0 = data;
16
  }
17
18
  void uart3_puts (char *s)
19
  {
20
      do{   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
21
          USART_Transmit(*s);
22
          s++;
23
      }while (*s);
24
  }
25
int main(void){
26
  UBRR0H = (uint8_t) (UBRR_0>>8);
27
  UBRR0L = (uint8_t) (UBRR_0 & 0xFF);
28
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);
29
  UCSR0C = (3 << UCSZ0);
30
  unsigned char s[]={'k','a','t','z','e','\0'};
31
32
33
  while(1){
34
//    USART_Transmit('K');
35
//    USART_Transmit('a');
36
//    USART_Transmit('t');
37
//    USART_Transmit('z');
38
//    USART_Transmit('e');
39
//    USART_Transmit('\n'); //geht
40
41
//    uart3_puts (s); //geht nicht
42
43
//    USART_Transmit(s[0]);
44
//    USART_Transmit(s[1]);
45
//    USART_Transmit(s[2]);
46
//    USART_Transmit(s[3]);
47
//    USART_Transmit(s[4]);
48
//    USART_Transmit('\n'); //geht
49
50
    int i;
51
    unsigned char dummy;
52
    for(i=0;i<=4;i++){
53
      _delay_ms(1000);
54
      USART_Transmit(i+0x30); //geht
55
      USART_Transmit('\n');
56
    }
57
    for(i=0;i<=4;i++){
58
      _delay_ms(1000);
59
      USART_Transmit(s[i]);//geht nicht
60
      USART_Transmit('\n');
61
    }
62
  }
63
}

von Robert M. (robert_maucher)


Lesenswert?

Karl heinz Buchegger schrieb:
> Die Funktion uart3_puts änderst du mal so um
>
>
1
> void uart3_puts (char *s)
2
> {
3
>   while( *s ) {   /* so lange *s != '\0' also ungleich dem
4
> "String-Endezeichen" */
5
>     USART_Transmit(*s);
6
>     s++;
7
>   }
8
> }
9
>
>
> damit ist schon mal der Fehler, das du das \0 Zeichen mitüberträgst, weg
> (oder war das Absicht?)

Ja war ein Fehler. ich habe die while irgendwann mal gegen eine do while 
ausgetauscht und das s++ in der Schleife vergessen zu löschen.

Das Problem mit der for Schleife besteht immer noch, da es mit der 
uart3_puts nichts zu tun hat, aber trotzdem danke.

von Karl H. (kbuchegg)


Lesenswert?

Robert Maucher schrieb:

> Das Problem mit der for Schleife besteht immer noch,

Ich sehs.
Aber ich sehe nichts, was das von dir beschriebene Verhalten erklären 
könnte.

Kann es sein, dass du mit der Baudrate ein klein wenig daneben bist 
(interner RC-Oszillator) und bei dieser Übertragung einfach zuviele 
Zeichen am Stück gesendet werden und sich der Empfänger nicht richtig 
synchronisieren kann.

von Robert M. (robert_maucher)


Lesenswert?

Das habe ich mir auchgedacht, aber wenn ich
1
USART_Transmit(s[0]);
2
USART_Transmit(s[1]);
3
USART_Transmit(s[2]);
4
USART_Transmit(s[3]);
5
USART_Transmit(s[4]);
6
USART_Transmit('\n');
dauernd in der while(1) drin habe dann passt alles.
Und was anders macht die For Schleife eigentlich auch nicht.

Hab mir noch gedacht das es einen Jitter geben könnte der mir ein 
Problem Macht, aber da passt alles.

bin Inzwischen auf 2400 Baud runter weniger kann ich nicht.
(Im Datenblatt steht das ein maximaler Fehler von 0,2% bei 2400 Baud 
ist.)

Das Problem lässt mich langsam durchdrehen.

Werde jetzt mal alles in Assamler coden um zu schauen (was ich eher 
nicht denk) ob im avr-gcc ein bug ist. was anderes kann ich mir nicht 
mehr vorstellen.

von Falk B. (falk)


Lesenswert?

@  Robert Maucher (robert_maucher)

>Werde jetzt mal alles in Assamler coden um zu schauen (was ich eher
>nicht denk) ob im avr-gcc ein bug ist. was anderes kann ich mir nicht
>mehr vorstellen.

;-)
Selten so gelacht. Lern erstmal ein paar Grundlagen.

http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART

MFG
Falk

von Robert M. (robert_maucher)


Lesenswert?

Falk Brunner schrieb:
> @  Robert Maucher (robert_maucher)
>
>>Werde jetzt mal alles in Assamler coden um zu schauen (was ich eher
>>nicht denk) ob im avr-gcc ein bug ist. was anderes kann ich mir nicht
>>mehr vorstellen.
>
> ;-)
> Selten so gelacht. Lern erstmal ein paar Grundlagen.
>
> http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART
>
> MFG
> Falk

Danke erst mal,

-ich habe nur einen Internen Takt zu verfügung.
-die verbindung und die Übertragung funktioniert Prinzipiell
-zeichen könne ohne fehler übertragen werden wenn man sie einzeln von 
hand eingibt (z.b. USART_Transmit('q');) sowie aus einen Array genommen 
werden (z.b. USART_Transmit(s[1]);)
-zeichenketten gehen nicht (uart3puts ...)
-einzelne zeichen in einem Array mit einer forschleife ausgeben geht 
nicht

Grundlagen habe ich schon Durchgelesen.

gruß Robert

Ps: Hilfsbedürftige ins Lächerliche zu ziehen ist nicht die feine Art

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich spekuliere, dass es Unterschiede im Funktionsaufruf gibt. Deshalb: 
Wie ist die M103 Fuse des Atmega128 eingestellt? Kannst du ein 
Disassemblerlisting (oder das HEX-File) bereitstellen?

von Karl H. (kbuchegg)


Lesenswert?

Robert Maucher schrieb:

> -ich habe nur einen Internen Takt zu verfügung.

Das ist schon mal ziemlich schlecht.


Nur testweise:
probier mal Folgendes
1
void USART_Transmit( unsigned char data )
2
{
3
  /* Wait for empty transmit buffer */
4
  while ( !( UCSR0A & (1<<UDRE0)) )
5
    ;
6
  /* Put data into buffer, sends the data */
7
  UDR0 = data;
8
9
  _delay_ms( 1 );
10
}

wenns dann geht, dann hast du ziemlich sicher ein Problem mit dem 
internen Oszillator.

Du kannst auch mal probieren, auf 2 Stoppbits zu erhöhen.

> Ps: Hilfsbedürftige ins Lächerliche zu ziehen ist nicht die feine Art

Wenn jemand den internen Oszillator zur UART Übertragung benutzt, ist 
jegliches Mitleid fehl am Platze.

von Robert M. (robert_maucher)


Lesenswert?

Karl heinz Buchegger schrieb:
> Robert Maucher schrieb:
>
>> -ich habe nur einen Internen Takt zu verfügung.
>
> Das ist schon mal ziemlich schlecht.
>
>
> Nur testweise:
> probier mal Folgendes
>
>
1
> void USART_Transmit( unsigned char data )
2
> {
3
>   /* Wait for empty transmit buffer */
4
>   while ( !( UCSR0A & (1<<UDRE0)) )
5
>     ;
6
>   /* Put data into buffer, sends the data */
7
>   UDR0 = data;
8
> 
9
>   _delay_ms( 1 );
10
> }
11
>
>
> wenns dann geht, dann hast du ziemlich sicher ein Problem mit dem
> internen Oszillator.
>
> Du kannst auch mal probieren, auf 2 Stoppbits zu erhöhen.

das geht auf jedenfall
auch ohne delay

ich hab nur probleme mit

einer String (char array) ausgabe

von Karl H. (kbuchegg)


Lesenswert?

Robert Maucher schrieb:

> das geht auf jedenfall
> auch ohne delay
>
> ich hab nur probleme mit
>
> einer String (char array) ausgabe

Probiers einfach!

An deiner String Ausgabe ist nichts falsch.
Es könnte aber sein, dass dein Optimizer die Schleifenvariante schneller 
realisieren kann, als wenn du die Aufrufe einzeln machst. Mit ein wenig 
Pech reicht das dann schon, dass du mit dem Timing daneben bist.

von Robert M. (robert_maucher)


Angehängte Dateien:

Lesenswert?

Die M103 ist deaktiviert da ich später beide Uarts brauche

von Robert M. (robert_maucher)


Lesenswert?

Robert Maucher schrieb:
> Karl heinz Buchegger schrieb:
>> Robert Maucher schrieb:
>>
>>> -ich habe nur einen Internen Takt zu verfügung.
>>
>> Das ist schon mal ziemlich schlecht.
>>
>>
>> Nur testweise:
>> probier mal Folgendes
>>
>>
1
>> void USART_Transmit( unsigned char data )
2
>> {
3
>>   /* Wait for empty transmit buffer */
4
>>   while ( !( UCSR0A & (1<<UDRE0)) )
5
>>     ;
6
>>   /* Put data into buffer, sends the data */
7
>>   UDR0 = data;
8
>>
9
>>   _delay_ms( 1 );
10
>> }
11
>>
>>
>> wenns dann geht, dann hast du ziemlich sicher ein Problem mit dem
>> internen Oszillator.
>>
>> Du kannst auch mal probieren, auf 2 Stoppbits zu erhöhen.
>
> das geht auf jedenfall
> auch ohne delay
>
> ich hab nur probleme mit
>
> einer String (char array) ausgabe

Nein macht kein Unterschied,
Ich habe jetzt auch mit verschiedenen Zeiten Rumgespielt, aber hat auch 
keine Veränderung gegeben.


von der Timing her müsste es eigentlich kein Problm geben, da
1
for(i=0;i<=4;i++){
2
  USART_Transmit(i+0x30); //geht
3
  USART_Transmit('\n');
4
}

auch ohne Probleme ausgegeben wird

von Karl H. (kbuchegg)


Lesenswert?

Dann hilft alles nichts.
Ein Assembler Listing muss her

von Robert M. (robert_maucher)


Angehängte Dateien:

Lesenswert?

Karl heinz Buchegger schrieb:
> Dann hilft alles nichts.
> Ein Assembler Listing muss her

Hier die Listings und die Maps

von Stefan E. (sternst)


Lesenswert?

Ich würde dir raten nochmal sehr gründlich und eindringlich die M103C 
Fuse zu überprüfen.

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst schrieb:
> Ich würde dir raten nochmal sehr gründlich und eindringlich die M103C
> Fuse zu überprüfen.

Das lässt sich relativ leicht prüfen.
Einfach den Optimizer komplett ausschalten, so dass er nichts inlinen 
kann. Wenns beim ersten Funktionsaufruf kracht, dann wars die Fuse

So dumm ist der Geadnke gar nicht.
Selbst wenn der Compiler alle Funktionen inlined, das Array kann er beim 
besten Willen nicht in einem Register halten.
Liegt das SRAM aber falsch (durch die Fuse) werden falsche Daten 
gelesen.

von Stefan E. (sternst)


Lesenswert?

Karl heinz Buchegger schrieb:
> So dumm ist der Geadnke gar nicht.

Hey, hattest du etwa gedacht, ich hätte das "einfach mal so" 
hingeschrieben? ;-)

Karl heinz Buchegger schrieb:
> Liegt das SRAM aber falsch (durch die Fuse) werden falsche Daten
> gelesen.

Wenn die Fuse gesetzt ist, ist dort, wo die Daten liegen, gar kein RAM. 
Und bei den direkten Aufrufen (USART_Transmit(s[0]);) werden die 
Zugriffe auf die Daten natürlich durch den Optimizer gleich durch die 
Zeichen ersetzt.

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst schrieb:
> Karl heinz Buchegger schrieb:
>> So dumm ist der Geadnke gar nicht.
>
> Hey, hattest du etwa gedacht, ich hätte das "einfach mal so"
> hingeschrieben? ;-)

Jetzt hab ich mich in die Nesseln gesetzt.
Ich hab die Fuse jetzt nur im Zusammenhang mit Funktionsaufrufen gesehen 
und laut ListFile hat der Compiler, was ich so gesehen habe, alles 
inline gemacht.

(Sieh die Aussage als Selbstgespräch mit mir selber an :-)

von Robert M. (robert_maucher)


Lesenswert?

Karl heinz Buchegger schrieb:
> Stefan Ernst schrieb:
>> Ich würde dir raten nochmal sehr gründlich und eindringlich die M103C
>> Fuse zu überprüfen.
>
> Das lässt sich relativ leicht prüfen.
> Einfach den Optimizer komplett ausschalten, so dass er nichts inlinen
> kann. Wenns beim ersten Funktionsaufruf kracht, dann wars die Fuse
>
> So dumm ist der Geadnke gar nicht.
> Selbst wenn der Compiler alle Funktionen inlined, das Array kann er beim
> besten Willen nicht in einem Register halten.
> Liegt das SRAM aber falsch (durch die Fuse) werden falsche Daten
> gelesen.

10011001 low fuse (0x99)

11100100 high fuse (0xE4)

11111111 efuse (0xFF)-> für kombi m103 oxFD

von Robert M. (robert_maucher)


Lesenswert?

Robert Maucher schrieb:
> Karl heinz Buchegger schrieb:
>> Stefan Ernst schrieb:
>>> Ich würde dir raten nochmal sehr gründlich und eindringlich die M103C
>>> Fuse zu überprüfen.
>>
>> Das lässt sich relativ leicht prüfen.
>> Einfach den Optimizer komplett ausschalten, so dass er nichts inlinen
>> kann. Wenns beim ersten Funktionsaufruf kracht, dann wars die Fuse
>>
>> So dumm ist der Geadnke gar nicht.
>> Selbst wenn der Compiler alle Funktionen inlined, das Array kann er beim
>> besten Willen nicht in einem Register halten.
>> Liegt das SRAM aber falsch (durch die Fuse) werden falsche Daten
>> gelesen.
>
> 10011001 low fuse (0x99)
>
> 11100100 high fuse (0xE4)
>
> 11111111 efuse (0xFF)-> für kombi m103 oxFD

 hab das Problem Gefunden

es war der komi Modus und die Fuse war nicht gestezt

war ein Fehler in der Makefile
hatte einen Tippfehler bei der e fuse ein read (r) anstatt write (w)

Danke euch allen für die Hilfe

gruß Robert

von Falk B. (falk)


Lesenswert?

@  Robert Maucher (robert_maucher)

> hab das Problem Gefunden
>es war der komi Modus und die Fuse war nicht gestezt

>war ein Fehler in der Makefile
>hatte einen Tippfehler bei der e fuse ein read (r) anstatt write (w)

Und wieder einmal triumphiert die AVR Checkliste.

MfG
Falk

von Robert M. (robert_maucher)


Lesenswert?

ja die Checkliste ist schon wichtig, noch wichtiger ist die eigene 
Unfähigkeit zu tippen zu überwinden schande über mich

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.