mikrocontroller.net

Forum: Compiler & IDEs Parameter an Funktion


Autor: Ludwig Meyerhoff (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ludwig Meyerhoff (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ludwig Meyerhoff (Gast)
Datum:
Angehängte Dateien:
  • uart.s (4,22 KB, 182 Downloads)

Bewertung
0 lesenswert
nicht 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

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ludwig Meyerhoff (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Also, anbei der Quellcode.


Saluti!

Ludwig

Autor: Peter (Gast)
Datum:

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

Gruss Peter

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter (Gast)
Datum:

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

Autor: Ludwig Meyerhoff (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Günter R. (galileo14)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BufCount und die Arrays müssen volatile sein.

Autor: Christian Schifferle (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist doch interruptgesteuert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...???

Autor: Ludwig Meyerhoff (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das 'volatile' sollte in diesem Fall auch kein Problem sein.

Warum nicht?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieser Code (vom Poster):
char obuf[BUFLEN + 1];
char ibuf[BUFLEN + 1];
unsigned int BufCount = 0;


ISR(UART_UDRE_vect)
{
  PORTB  = 0xaa;
  if( obuf[BufCount] != 0 )
    UDR = obuf[BufCount++];
}

int sendString(char *c)
{
  unsigned int count = 0;
  while( c[count] )
  {
    obuf[count] = c[count];
    count++;
  }

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

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.