mikrocontroller.net

Forum: PC-Programmierung serielle Kommunikation


Autor: Machine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, für die serielle Schnittstelle verwende ich einen sogenannten 
Zwischenpuffer.
int CQUEUE::write_que_str(char* str)
{
  int i;
  i = (len + ri - wi - 1) % len; //i = space in buffer
  if (i>0) //if enough space
    { 
    sprintf(strbuf,"%s",str); 
      return(1); //successfully transmitted one int
    }
  else
    return(0);
}

int CQUEUE::read_que_str(char* str)
{
  int i;
  i = (len - ri + wi) % len; //i = contents in buffer
  if (i>0) //if enough space
    { 
    sprintf(str,"%s",strbuf);
      return(1); //successfully transmitted one int
    }
  else
    return(0);
}

Wenn ich dies so mache, dann stürzt mein System ab.
Kann ich dies mit dem QUEUE auch noch anders lösen? Gibt es da schon 
fertige Methoden in C++?

Autor: Machine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit dem QUEUE bekomme ich nicht gebacken! Brauche dringend 
Unterstützung.

Danke im voraus!

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn keiner antwortet, ist vielleicht

1/ deine Ungeduld zu gross
2/ das Problem zu ungenau beschrieben
3/ das Problem zu komplex

Ich vermute die Punkte 1+2 treffen zu.

Du könntest z.B. angeben

* aus welcher Library sich dein CQUEUE stammt. Dann könnte man 
nachsehen, woher die obskuren Variablen len, ri, wi und strbuf stammen 
und was sie bedeuten. Ist strbuf der Anfang des CQUEUE Puffers oder die 
Adresse der ersten freien Position in der Queue? Wenn letzteres - wer 
erhöht strbuf nach der sprintf Aktion?

* wie du die Klasse CQUEUE im Hauptprogramm initialisierst.

* wie gross du den Puffer str anlegst und ob sprintf(str,"%s",strbuf); 
den zum Platzen bringen kann.

Es scheint sich bei strbuf um einen Ringpuffer zu handeln (ri, wi 
könnten ReadIndex und WriteIndex) sein. In dem Fall kannst du nicht 
davon ausgehen, dass der freie Speicher linear fortlaufend angeordnet 
ist, d.h. du darfst kein sprintf verwenden. Du musst eine Kopieraktion 
benutzen, die einzelne Zeichen kopiert (wi erhöht) und beim erreichen 
von len bei 0 am Pufferanfang bis max. ri (-1 fürs Nullbyte) 
weitermacht.

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

Bewertung
0 lesenswert
nicht lesenswert
> Es scheint sich bei strbuf um einen Ringpuffer zu handeln (ri, wi
> könnten ReadIndex und WriteIndex) sein. In dem Fall kannst du nicht
> davon ausgehen, dass der freie Speicher linear fortlaufend angeordnet
> ist, d.h. du darfst kein sprintf verwenden. Du musst eine Kopieraktion
> benutzen, die einzelne Zeichen kopiert (wi erhöht) und beim erreichen
> von len bei 0 am Pufferanfang bis max. ri (-1 fürs Nullbyte)
> weitermacht.

@Machine

Was auch immer wieder gut kommt:

Sich eine Zeichnung machen!
Und dann mal ein paar Beispiele am Papier durchspielen!

Autor: Machine (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Mit den Funktionen kann ich bereits Integerwerte übergeben und wieder 
lesen.

>>read_que_int(int* value)
>>write_que_int(int value)

Für Strings müsste ich dies vom Prinzip auch so realisieren.
(FIFO Prinzip)

Autor: Machine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Definitionen in der Headerdatei "queue.h"

#define QSIZE   264         // queue length

int*  buf;     // pointer to fifo-buffer
int   len;     // length of buffer
int   ri;      // read_index
int   wi;      // write_index
int   read_que_int(int* value);
int   write_que_int(int value);
void  Clear(void);                  // clears unconditionally the queue
int   get_que_space();
int   que_contents();

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

Bewertung
0 lesenswert
nicht lesenswert
Der SChlüssel zuum Ganzen liegt darin, dass du in deinem
Ringbuffer (und genau darum handelt es sich), keine
Strings bearbeiten musst, sondern einzelne Zeichen.

Um einen String einzufügen, fügst du also alle Zeichen
die den String bilden ein.

angenommen deine Queue hat eine Länge von 8 Zeichen:


  +---+---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 0
  wi = 0

und jetzt soll der String "Test" eingefügt werden.

  dann muss das Ergebnis so aussehen:

  +---+---+---+---+---+---+---+---+
  | T | e | s | t | \0|   |   |   |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 0
  wi = 5

und du erreichst es, indem du aus dem übergebenen String
Zeichen für Zeichen ausliest und in den Buffer überführst.
Warum Zeichen für Zeichen?

Nun nimm mal an aus der Queue wurde der String bereits
ausgelesen. Dann ist die Situation diese:

  +---+---+---+---+---+---+---+---+
  | T | e | s | t | \0|   |   |   |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 5
  wi = 5

und jetzt fügst du den Test "Hurra" ein (6 Zeichen)

Dann sieht das Ergebnis so aus:

  +---+---+---+---+---+---+---+---+
  | r | a | \0| t | \0| H | u | r |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 5
  wi = 3

Beachte wie der Text "Hurra" an den vorhergehenden und noch
im Speicher befindlichen Text "Test" angefügt ist und bei
Erreichen des Bufferendes am Bufferanfang weitergeschrieben
wird. Daher kannst du nicht mit irgendwelchen Standard String
Funktionen arbeiten, sondern musst selbst dafür sorgen, dass
dieser Wrap around gemacht wird.

Sagte ich nicht: Nimm dir Papier und Bleistift und mal
dir die Situationen auf. Dann schreibst du dein Programm
und spielst hinterher selbst Computer und simulierst dein
Programm auf dem Papier durch. Sehr lehrreich!



Autor: Machine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Hilfe!

Das Problem ist ja, das mein Puffer vom Typ int ist.
>>int* buf;

Den möchte ich beibehalten. Quasi ist mein buf mein Ringpuffer.

In der folgenden Funktion übergebe ich einen String (cstring).
Nach der if(i>0) Bedingung weiss ich nicht wie ich das ganze jetzt in 
den
Puffer bekomme.
int CQUEUE::write_que_str(char* cstring)
{ 
  int i;
  i = (len + ri - wi) % len; //i = contents in buffer

  if (i>0) //if enough space
    { 
      ?????
           wi = (wi + 1) % len;  //increment write index 
     return(1); //successfully transmitted one int
    }
  else
    return(0);
}

Autor: Machine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Integer setzt sich aus zwei Character zusammen.
2 x 8Bit = Integer

wenn z.B. wi = 1 ist , dann bedeutet das ja das eigentlich zwei 
Character vorhanden sind oder?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Korrekt. Du kannst jetzt auf zwei Arten weitermachen

1/ Du verschwendest pro Zeichen im String ein Byte. Du erweiterst 
einfach über einen Cast ein char (vom String) zu einem int (im Puffer). 
Nachteil: Das eine Erweiterungsbyte pro Nutzzeichen frisst den halben 
Speicher.

2/ Du setzt aus je zwei Zeichen im String ein int zusammen. (Kleiner) 
Nachteil: Du musst dir was überlegen, wie du das Stringende erkennst 
(Nullbyte kann im Highbyte oder im Lowbyte stecken) und du brauchst u.U. 
exakt ein Erweiterungsbyte (wenn strlen(str) ungerade ist).

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

Bewertung
0 lesenswert
nicht lesenswert
3/ Du wirfst die unsinnige Forderung, dass du den Speicher
   weiterhin als int halten willst über Bord und machst das
   vernünftig: Der Buffer ist ein Array von unsigned char.
   Dieselbe Technik, mit der ein String letztendlich in
   diesem Buffer landet, wird dann auch auf int angewendet.
   Und dieselbe Technik nimmt man dann auch für double,
   float, long, Strukturen, etc...

Auf dieser low level Ebene gibt es sinnvollerweise nur noch
Bytes als kleinsten gemeinsamen Nenner aller überhaupt
möglichen Datentypen. Wenn für einen Datentyp mehrere Bytes
benötigt werden, dann ist das halt so, dann werden mehrere
Bytes pro Eintrag benötigt.

Autor: Machine (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen Karl heinz Buchegger,

ich weiss nun echt nicht wie dies jetzt realisierne könnte.
//-------------------------------------------------------------------------
int CQUEUE::write_que_int(int value)
{
  int i;
  i = (len + ri - wi - 1) % len; //i = space in buffer
  if (i>0) //if enough space
    { 
      buf[wi] = value;    //tranfer value
      wi = (wi + 1) % len;  //increment write index 
      return(1); //successfully transmitted one int
    }
  else
    return(0);
}

Headerdatei:

>>int*  buf; // pointer to fifo-buffer

umändern in

>>char* buf

Das mit der Funktion macht mir noch große Probleme.
Wie könnte man jetzt einen String einlesen bzw. int?
//-------------------------------------------------------------------------
int CQUEUE::write_que_str(char* text)
{
  int i;
  i = (len + ri - wi - 1) % len; //i = space in buffer
  if (i>0) //if enough space
    { 
      buf[wi] = value;    //tranfer value
      wi = (wi + 1) % len;  //increment write index 
      return(1); //successfully transmitted one int
    }
  else
    return(0);
}

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

Bewertung
0 lesenswert
nicht lesenswert
Machine wrote:
> Headerdatei:
>
>>>int*  buf; // pointer to fifo-buffer
>
> umändern in
>
>>>char* buf

Ja.
Natürlich auch den malloc anpassen :-)

>
> Das mit der Funktion macht mir noch große Probleme.
> Wie könnte man jetzt einen String einlesen bzw. int?
>
>
> //-------------------------------------------------------------------------
> int CQUEUE::write_que_str(char* text)
> {
>   int i;
>   i = (len + ri - wi - 1) % len; //i = space in buffer
>   if (i>0) //if enough space

Das kann natürlich nicht so bleiben.
Wenn i die Anzahl der noch freien Bytes im Speicher
angibt, dann passt der String logischerweise nur dann
in diesen Speicher, wenn für jedes Zeichen im String
(+ das obligate '\0' Zeichen) ein Byte frei ist.

Die Anzahl der Zeichen in einem String kriegt man
mit strlen(). Nach 1 dazu für das '\0' Zeichen.
Ergo
    int textLen = strlen(text) + 1;
    if( textLen < i )   // es ist genug Platz

>
   {

>       buf[wi] = value;    //tranfer value
> 

Nachdem text ein String (also eine Abfolge von Zeichen) ist
wird das mit einer Zuweisung wohl nichts werden. (Man kann
Arrays nicht zuweisen. Bei dir würde es auch nichts bringen
wegen dem Wrap.
(Hab ich eigentlich schon mal erwähnt, dass man sich solche
Situationen aufzeichnen sollte ?)
       for( i = 0; i < textLen; ++i ) {
         buf[wi] = text[i];     // Ein Zeichen umkopieren

         wi = ( wi + 1 ) % len;  // Und den Zielindex um 1
                                 // erhöhen. Dabei aber aufpassen
                                 // dass er beim Erreichen des Buffer-
                                 // endes bei 0 weitermachen muss.
      }

>
       wi = (wi + 1) % len;  //increment write index 
Das brauchts dann nicht mehr. wi ist schon innerhalb der Schleife
korrekt erhöht worden.

>
      return(1); //successfully transmitted one int
>     }
>   else
>     return(0);
> }
> 

Ist doch nicht so schwer.
Nochmal: Mal dir einen Buffer auf. Mal dir einen String auf
und spiele am Papier durch, was zu passieren hat!
Das ist kein Scherz!

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.