Forum: Compiler & IDEs Parameter an Funktion


von Ludwig Meyerhoff (Gast)


Lesenswert?

Hallo!

Ich verstehe nicht, wieso ich Müll rauskriege, wenn ich eine Funktion
habe:

int sendstring(char *s)
{
  unsigned char c = 0;
  while(s[c] != 0)
    if( USR & 0x20 )
      UDR = s[c++];
return(0);
}

int main(void)
{
  sendString("Hallo, Du da!\n\r\0");
return(0);
}

ich auf dem Terminal nur Müll angezeigt bekomme (sendstring abgerollt
in Main geht aber wunderbar!).

Im AVR-GCC-Tutorial habe ich einen Hinweis auf die Harvard-Architektur
gefunden, werde aber daraus nicht schlau. Die Zeichenkette ist ja
statisch und wird vom Compiler WO hingepackt?
Muß ich sendString einen Flag "Konstante/Programmspeicher" übergeben,
daß er den Pointer auf den richtigen Speicher anwendet?


Saluti!

Ludwig

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Du ratterst ganz ganz schnell durch den String durch, stellst
fast, dass das UART data register not empty ist, und gehst
zum nächsten Zeichen über.

Du willst wohl stattdessen lieber für jedes Zeichen einzeln
warten, bis das UDR empty ist, und dann weitermachen.

Deine Interruptvariante ist natürlich besser.  Übrigens braucht
diesen den Test auf UDRE selbst gar nicht: wenn der Interrupt
triggert, ist garantiert, dass dieses Bit gesetzt ist.

von Ludwig Meyerhoff (Gast)


Lesenswert?

Hallo!

Das Problem ist, daß wenn ich strcpy "per Hand" durchführe:
int sendString(char *c)
{
unsigned int count = 0;
        while( c[count] )
        {
                obuf[count] = c[count];
                count++;
        }

        BufCount        = 0;
        UDR     = obuf[BufCount++];
return(0);

ich nicht das ausgegeben bekomme, was ich durch sendString("Hallo, Du
da!\n\r\0"); übergeben hatte.

BTW, BufCount ist eine globale unsigned char für die Position im
Puffer, und mit Änderung von UDR starte ich die Übertragung (der Rest
wird per Interrupt gemacht). Das ist zwar nicht ganz elegant, um die
Eleganz will ich mich in einem zweiten Augenblick kümmern.



Saluti!

Ludwig

von Karl H. (kbuchegg)


Lesenswert?

Das kann viele Ursachen haben.
Mach doch mal ein komplettes, vollständiges Programm fertig.

Um die Hardvard-Architektur brauchst du dich nicht
kümmern, solange du mit dem verfügbaren RAM auskommst
und nichts optimieren musst.

von Ludwig Meyerhoff (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Karl Heinz, wie kann ich ein vollständiges Programm fertig machen, wenn
die einzelne Funktion nicht funktioniert?
Auch ohne Optimierung ("-Os" ist rauskommentiert) kriege ich nur
Datensalat.

Im Assemblerfile sehe ich, daß die Konstante "Hallo, Du da!\n\r\0"
mit der Direktive ".string" definiert wird - leider habe ich keine
Dokumentation über die einzelnen Direktiven gefunden. Was macht
".string"?



SalutI!

Ludwig

von Stefan (Gast)


Lesenswert?

Karl Heinz meint, dass du den kompletten Quellcode (das C-Listing)
posten sollst. Und das ist eine gute Idee.

Dadurch kann man oft erst sehen, wo und wie welche Variablen angelegt
werden, ob es Initialisierungsprobleme gibt, ob sinnvolle Includefiles
eingebunden werden etc.. Gelegentlich findet sich bei komplettem
Quellcode sogar ein Helfer, der das Programm auf seinem Rechnersystem
prüft...

Bei grösseren Projekten kann es notwendig sein, den Quellcode auf den
reproduzierbaren Fehlerfall zu kürzen. Gelegentlich kann es sogar
angebracht sein, das Makefile oder weitere Daten bekanntzugeben.

von Karl H. (kbuchegg)


Lesenswert?

> Karl Heinz, wie kann ich ein vollständiges Programm fertig machen,
> wenn die einzelne Funktion nicht funktioniert?

Indem du exakt das Program postest, das du auch durch den
Compiler schickst. Und zwar vollständig. Oftmals ist es
so, dass wir nur beim Durchlesen von Code-Schnipseln auch
Dinge übersehen, bzw. das der eigentliche Fehler genau
in dem Code steckt, den du nicht postest.
Indem du ein komplettes Program postest, ermöglichst du uns,
dass wir deinen Fehlerfall (so gut es geht) bei uns nachstellen
können. Wir können das selbst mal durch den Compiler jagen
und nachsehen was da schief läuft.
Du bringst ja auch nicht nur die Hutablage deines Autos
zum Mechaniker wenn dort was klappert.

von Ludwig Meyerhoff (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Also, anbei der Quellcode.


Saluti!

Ludwig

von Peter (Gast)


Lesenswert?

Zum Code wäre es gut, wenn Du den CPU-Typ sowie die F_CPU auch noch
angibst!

Gruss Peter

von Karl H. (kbuchegg)


Lesenswert?

Das sieht soweit eigentlich ganz gut aus.
Da werden wir wohl in den Simulator muessen.
Welchen AVR benutzt du?

von Peter (Gast)


Lesenswert?

Okey, F_CPU ist 3.6864 MHz (steht im Code) und als CPU verwendest Du
offenbar den AT90S3213...

Im Prinzip funktioniert Dein Program, mal abgesehen davon, dass Du den
Buffer-Inhalt [Das klappt!] mit [Hallo Du da!!] überschtreibst, nachdem
nur die ersten zwei Zeichen vom ersten String raus sind...!

Die Strings landen so wie's Du machst im RAM, wenn Du sie im Flash
haben möchtest müsstest Du...

#include <avr/pgmspace.h>  //includen

char MyString[] = PROGMEM "Hello World!\n\r"  //String im Flash

// oder direkt als Parameter mit dem PSTR() Macro
sendString_P(PSTR("Ich komm aus dem Flash!\n\r")); // im FLASH

//---------------------------------------------------------
// Für Strings im FLASH braucht es eigene Funktionen
// für den Datenzugriff z.B. int sendString_P(PGM_P str)
//---------------------------------------------------------

int sendString_P(PGM_P str)
//---------------------------------------------------
// send a ProgMem string to UART0 Transmit-buffer
//---------------------------------------------------
{
  char c=pgm_read_byte(str);  // get  first char from ProgMem
  while (c)                   // while not string-end
  {
    UART_putc(c);   // copy char to TX-Buffer (wait if full)
    c=pgm_read_byte(++str);   // get next char from ProgMem
  }
}

Mehr dazu steht in der avr_libc Dokumentation!

Gruss Peter

von Peter (Gast)


Lesenswert?

Noch was: Das ganze lässt sich prima im AVR-Studio simmulieren,
verwendest Du den Debugger nicht?

von Ludwig Meyerhoff (Gast)


Lesenswert?

Hallo!

Also, ich benutze einen AT90S2313 in einem STK500 Testboard, der
standardmässig 3.6864MHz liefert.

Als Umgebung nutze ich den "vi" mit dem "avr-gcc", "make" und
"uisp".

Zu meiner Schande muß ich zugeben, mich nie mit dem GNU-Debugger
beschäftigt zu haben.


Saluti!

Ludwig

von Günter R. (galileo14)


Lesenswert?

@Ludwig:
Kleine Anmerkung:

>>  sendString("Hallo, Du da!\n\r\0");

Das "\0" am Ende kannst Du weglassen - stört zwar nicht, erzeugt der
Compiler aber automatisch beim Ablegen eines Strings; also:

    sendString("Hallo, Du da!\n\r");

Gruß, Günter

von Rolf Magnus (Gast)


Lesenswert?

BufCount und die Arrays müssen volatile sein.

von Christian Schifferle (Gast)


Lesenswert?

Also so wie ich das sehe ist dein eigentliches Problem eigentlich nur
dasjenige, dass du nicht wartest, bis das vorherige Zeichen erfolgreich
gesendet wurde. Es ist eigentlich ja ziemlich logisch, dass der UART
beim Tempo der CPU nicht mithalten kann.
Am einfachsten wartest du nach der Ausgabe jedes einzelnen Zeichens,
bis das Senderegister wieder leer ist. Ansonsten müsstest du echt
interruptgesteuert senden mit einem entsprechenden Sendepuffer
dazwischen. Wenn du keine absolute High Performance Application haben
willst scheint mir dieser Weg allerdings zu umständlich.

von Rolf Magnus (Gast)


Lesenswert?

Das ist doch interruptgesteuert.

von Karl H. (kbuchegg)


Lesenswert?

Moment mal.
Das ganze senden läuft interruptgesteuert ab.
Das heist: Wenn SendString zurückkommt, dann ist der
String noch lange nicht gesendet. Er ist grade mal im
Buffer und der Interrupt gibt das ganze aus.
Das heist aber auch: Lass den BuffCount danach in Ruhe.
Auch weiss ich nicht was alles passiert, wenn du in der
while Schleife ständig auf das USR Register zugreifst.

Das andere: Die ISR muss sich selbst nach dem letzten Zeichen
den Interrupt abdrehen. Den wenn das letzte Zeichen gesendet
wurde und du nichts mehr ins UDR stellst, tritt der Interrupt
sofort wieder auf, das USART-Ausgangsregister ist ja zur Benutzung
frei.

Aber all das passt nicht zu deiner Fehlerbeschreibung: Anstatt
dem Text kommt eine Menge Unsinn über die USART. Es sei
denn du hast den eigentlichen Text übersehen und richtest dein
Augenmerk auf den Unsinn der irgendwo im Speicher steht und auch
ausgegeben wird, weil die ISR auf Biegen und Brechen immer weiter
ausgibt weil der Interrupt immer wieder kommt.

von Karl H. (kbuchegg)


Lesenswert?

Denkfehler meinerseits.
Die ISR wird zwar noch aufgerufen, macht aber nichts mehr,
da die Funktion am Ende des Strings angelangt ist.

Damit kann ich dir auch nicht erklären warum das nicht
funktioniert. Sollte meiner Ansicht nach eigentlich
klappen.

Das 'volatile' sollte in diesem Fall auch kein Problem sein.

von Peter (Gast)


Lesenswert?

Ich habe weiter oben beschrieben warum es nicht klappt:

>Im Prinzip funktioniert Dein Program, mal abgesehen davon,
>dass Du den Buffer-Inhalt [Das klappt!] mit [Hallo Du da!!]
>überschtreibst, nachdem nur die ersten zwei Zeichen vom ersten
>String raus sind...!

Könnt ihr nicht lesen...???

von Ludwig Meyerhoff (Gast)


Lesenswert?

Hallo!

Peter, das sollte wohl NICHT das Problem sein, denn wenn der
Bufferinhalt überschrieben wird, sollte ja doch was drin stehen und
übertragen werden!

Ich kriege im Minicom lauter komische Zeichen, abgezählt soviele wie
eigentlich im Puffer sich befinden.


Ich werde das mit dem "volatile" versuchen und bescheidgeben. Könnte
einige Tage dauern.


Saluti!

Ludwig

von Rolf Magnus (Gast)


Lesenswert?

> Das 'volatile' sollte in diesem Fall auch kein Problem sein.

Warum nicht?

von Karl H. (kbuchegg)


Lesenswert?

Dieser Code (vom Poster):
1
char obuf[BUFLEN + 1];
2
char ibuf[BUFLEN + 1];
3
unsigned int BufCount = 0;
4
5
6
ISR(UART_UDRE_vect)
7
{
8
  PORTB  = 0xaa;
9
  if( obuf[BufCount] != 0 )
10
    UDR = obuf[BufCount++];
11
}
12
13
int sendString(char *c)
14
{
15
  unsigned int count = 0;
16
  while( c[count] )
17
  {
18
    obuf[count] = c[count];
19
    count++;
20
  }
21
22
  BufCount = 0;
23
  UDR = obuf[BufCount++];
24
  return(0);  
25
}

Weder obuf noch BufCount läuft Gefahr 'gleichzeitig' in der
ISR und woanders gelesen oder geschrieben zu werden. BufCount
hätte Potential dazu, da hier ja in SendString noch was fehlt:
Die Abfrage ob ein vorher gesendeter String noch im Buffer steckt
oder schon raus ist. Dazu würde man wahrscheinlich den BufCount nehmen
und solange warten bis der wieder 0 ist (und dann ist
volatile eine extrem gute Idee). Aber im Moment sollte das
noch kein Problem sein.

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.