www.mikrocontroller.net

Forum: Compiler & IDEs Strings zu einem zusammenfügen


Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich möchte immoment mehrere Strings zu einem zusammenfügen also ungefähr 
so:
unsigned char Enddaten[40];
for (n=0;n<4;n++)
  {
  dtostrf(Daten[n],2,4,data);
/*hier soll mit jedem durchlauf der Schleife "data" den "Enddaten" angehangen werden so das am ende alle 4 Werte darin gespeichert sind*/
   }

leider hab ich nich die geringste ahnung wie ich das anstellen soll!
Hab nach etwas googlen zwar einige Funktionen hierfür gefunden, 
allerdings nie wirklich gut erklärt.

Hoffe ihr könnt mir hier etwas weiterhelfen.

Gruß T.M.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

die Funktionen strcat bzw. strncat sollten das für Dich erledigen 
können. Um sie nutzen zu können, musst Du string.h einbinden.

Kuckst Du hier:
http://www.opengroup.org/onlinepubs/009695399/func...
http://www.opengroup.org/onlinepubs/009695399/func...

Gruß,
Thomas

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die schnelle Hilfe werd ich sofort einmal ausprobieren!

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs jetzt ausprobiert leider bekomm ich einen Zahlensalat!
        unsigned char Enddata[40];
  unsigned char data[6];
for (n=0;n<4;n++)
  {
  dtostrf(Daten[n],2,4,data);
  strcat(Enddata,data);
  }


Fällt euch eventuell auf was ich falsch gemacht haben könnte ?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zahlensalat? Wie sieht der aus?

Wie sehen die Werte in Daten[] aus?

Was steht vor dem Aufruf der Schleife in Enddata[]?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eingentlich nichts - in den vorhandenen Zeilen. Warum du die 
Zeichenfelder als unsigned anlegst, verstehe ich zwar nicht, aber das 
ist hier jetzt egal.

Hast du mal überprüft, ob die Einzelstrings in data in jedem 
Schleifendurchlauf richtig sind?

Oliver

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
data hat nur 6 Elemente. Bist Du ganz sicher, dass Dein mit dtostrf 
erzeugter String da überhaupt reinpasst? Du gibst zwei Nachkommastellen 
an. Mit dem Dezimaltrennzeichen und einem eventuellen Vorzeichen sind 
das schon vier Stellen, da bleibt nur noch eine einzige für den 
Vorkommaanteil...

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einen Fehler hab ich schon gefunden die und zwar liegt der Programmcode 
in einer while Schleife und dadurch wurden der Endwertstring immer 
wieder neu beschrieben. das hab ich allerdings mit gets(Enddata); 
gelöst!
seh ich doch richtig das dies den String auf "\0"setzt oder ?

Ich habe das Problem des Teilweisen Zahlensalates immernoch.

Hier nochmal der ganze Programmcode:
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/rf12.h>
#include <inttypes.h>
#include <stdlib.h>
//------------------------------------------------------------------------------
// ADC auslesen und umrechnen in Spannungswert...
double readADC(uint8_t channel)
{
  uint8_t i;
  uint16_t adc_value;
  double voltage_sensor;
  //
   ADMUX =channel;
  ADMUX |= (1<<REFS0);
    adc_value = 0;
  for(i=0;i<4;i++)
  {
  ADCSRA |=(1<<ADSC);
  while (ADCSRA & (1<<ADSC));
  adc_value +=ADCW;
  }
  adc_value /=4;
  voltage_sensor = adc_value * 2.048 / 1024.0;
  //dtostrf(voltage_sensor,2,4,data);
  return voltage_sensor;
}
int main (void) 
{
  unsigned char Enddata[40];
  unsigned char data[6];
  double Daten[4];
  int n;
  DDRD = (1<<6)|(1<<4);

  PORTD |= (1<<6);
  PORTD |= (1<<4);
  
  DDRB = (1<<3);
  PORTB = (1<<3);
  

  rf12_init();          // ein paar Register setzen (z.B. CLK auf 10MHz)
  rf12_setfreq(RF12FREQ(868.5));  // Sende/Empfangsfrequenz auf 433,92MHz einstellen
  rf12_setbandwidth(5, 1, 4);    // 200kHz Bandbreite, -6dB Verstärkung, DRSSI threshold: -79dBm 
  rf12_setbaud(9600);        // 19200 baud
  rf12_setpower(0, 6);      // 1mW Ausgangangsleistung, 120k
  ADCSRA =(1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
    
  while(1)
  { 
// 4 ADC's auslesen
  for (n=0;n<4;n++)
  {
  Daten[n] = readADC(n); 
  }
// Packen der Daten in einen String
  for (n=0;n<4;n++)
  {
  dtostrf(Daten[n],2,4,data);
  strcat(Enddata,data);
  }
// senden des Endstrings
  rf12_txdata(Enddata,40);
  for(long a = 0;a<100000;a++){asm("nop");};
  gets(Enddata);
  }
}



Würd mich auf Kritiken zum Programmcode und oder Verbesserungsvorschläge 
freuen.

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

Bewertung
0 lesenswert
nicht lesenswert
T.M. wrote:

> Ich habe das Problem des Teilweisen Zahlensalates immernoch.

Du hast die Doku zu dtostrf nicht gelesen oder nicht verstanden.
dotostrf will 2 Zahlen haben, die festlegen wie es den String 
formatieren soll.
Die erste der beiden Zahlen legt die Feldbreite fest. Feldbreite 
bezeichnet die komplette Anzahl an zu generierenden Zeichen.
Die zweite der beiden Zahlen legt fest wieviele Nachkommastellen erzeugt 
werden sollen.


Du hast
>   dtostrf(Daten[n],2,4,data);

D.h.
du willst deine Ausgabe in einem Feld der Breite 2 haben.
Und in diesem Feld sollen 4 Stellen nach dem Komma aufscheinen.

Das wird schon mal nicht gehen!

Beachte: Die Feldbreite beinhaltet auch den Dezimalpunkt und ein ev. 
Vorzeichen


Und mach data ein wenig größer.
In einem char Array der Länge 6 bringst du maximal einen String mit 5 
nutzbaren Zeichen unter!
Mach das ruhig mal 10 oder 20 groß!


> // senden des Endstrings
>   rf12_txdata(Enddata,40);

Ach so? Dein String hat also eine Länge von 40. Das glaub ich nicht!
Dein Array ist mit 40 Einträgen dimensioniert. Das heisst aber nicht, 
dass der String der drinnen steht auch 40 Zeichen lang ist.

Du solltest auch Enddata mit einem leeren String initialisieren, ehe du 
anfängst an den leeren String Teile anzuhängen

  Enddata[0] = '\0';
  while(1)
  {
// 4 ADC's auslesen
  for (n=0;n<4;n++)
  {

http://www.mikrocontroller.net/articles/FAQ#Wie_fu...



Und gewöhn dir von Anfang an an, deinen Code korrekt einzurücken!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hupps, hatte gar nicht gesehen, dass der OP auch noch width und 
precision vertauscht hat. Danke, Karl heinz...

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Du solltest auch Enddata mit einem leeren String initialisieren, ehe du
>anfängst an den leeren String Teile anzuhängen

Und das dann IN die Schleife legen könnte helfen ;)

  while(1)
  {
   Enddata[0] = '\0';
// 4 ADC's auslesen
  for (n=0;n<4;n++)
  {

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

Bewertung
0 lesenswert
nicht lesenswert
holger wrote:
>>Du solltest auch Enddata mit einem leeren String initialisieren, ehe du
>>anfängst an den leeren String Teile anzuhängen
>
> Und das dann IN die Schleife legen könnte helfen ;)
>
>   while(1)
>   {
>    Enddata[0] = '\0';
> // 4 ADC's auslesen
>   for (n=0;n<4;n++)
>   {

Ah ja.
Durch die nicht vorhendene Einrückung ist mir völlig entgangen, dass er 
ja tatsächlich eine Hauptschleife hat.
Warum ichs allerdings nicht gemerkt habe, als ich den Einfügepunkt für 
das Leersetzen des Strings gesucht habe, ist mir rätselhaft. Hab wohl 
wieder mal mit dem Weißen geschaut.

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke muss mir wohl noch einiges zum Thema Strings durchlesen...
Naja aus Fehlern lernt man.
Danke für die konstruktiven Antworten ;) ist ja leider nicht immer 
Selbstverständlich das sich Leute Zeit für Anfänger nehmen.
Werde meine Programm morgen oder am Samstag fertigstellen!

Wie gesagt jede Kritik am Programm sind willkommen sollte gegen Ende ja 
möglichst Perfekt sein!

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Habe nun wieder rumprobiert bekomme allerdings immer noch Zahlensalad 
auf dem Empfänger.
Ich benutze folgenden Code:
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/rf12.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
//------------------------------------------------------------------------------

double readADC(uint8_t channel)
{
  uint8_t i;
  uint16_t adc_value;
  double voltage_sensor;
  //
   ADMUX =channel;
  ADMUX |= (1<<REFS0);
    adc_value = 0;
  for(i=0;i<4;i++)
  {
  ADCSRA |=(1<<ADSC);
  while (ADCSRA & (1<<ADSC));
  adc_value +=ADCW;
  }
  adc_value /=4;
  voltage_sensor = adc_value * 2.048 / 1024.0;
  return voltage_sensor;
}
int main (void) 
{
  char data[7];
  char Enddata[25];
  double Daten[4];
  int n;
  DDRD = (1<<6)|(1<<4);

  PORTD |= (1<<6);
  PORTD |= (1<<4);
  
  DDRB = (1<<3);
  PORTB = (1<<3);
  

  rf12_init();          // ein paar Register setzen (z.B. CLK auf 10MHz)
  rf12_setfreq(RF12FREQ(868.5));  // Sende/Empfangsfrequenz auf 433,92MHz einstellen
  rf12_setbandwidth(5, 1, 4);    // 200kHz Bandbreite, -6dB Verstärkung, DRSSI threshold: -79dBm 
  rf12_setbaud(9600);        // 19200 baud
  rf12_setpower(0, 6);      // 1mW Ausgangangsleistung, 120k
  
  
  ADCSRA =(1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
    
  while(1)
  { 
    Enddata[0] ="\0";
  for (n=0;n<2;n++)
  {
  Daten[n] = readADC(n);
  }

  for (n=0;n<2;n++)
  {
  dtostrf(Daten[n],6,4,data);
  strncat(Enddata,data,7);
  }
  rf12_txdata(Enddata,13);
  for(long a = 0;a<100000;a++){asm("nop");};
  }
}


Hab nach langen ausprobieren gemerkt das es wohl an der strncat funktion 
liegt habe versucht dort auch andere Stringsanzuhängen dies funktioniert 
allerdings nicht.
Hab ich an der Funktion irgendetwas falsch verstanden?
oder einen anderen Fehler gemacht ?

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hab nach langen ausprobieren gemerkt das es wohl an der strncat funktion
>liegt
Heißt das, du kannst:
 - ein einzelnes Byte
 - einen konstanten string
 - einen einzelnen dtostrf()-gewandelten Wert
senden (und empfangen)?
Vielleicht fügst du einfach mal ein Trennzeichen in den String ein:
int main (void) 
{
  char tmp_string[7];     //war: data
  char final_string[25];  //war: Enddata
  double sensor_value[4]; //war: Daten
  int i;                  //war: n (i -> Zaehlvariable aus Mathe)
  /* 
  init... 
  */
  while(1)
  { 
    final_string[0] = '\0'; // ' statt "
    for(i=0; i<2; i++)
    {
      sensor_value[i] = readADC(i);
      //"-1.234" bis "9.9999"?
      dtostrf(sensor_value[i], 6, 4, tmp_string);
      strncat(final_string, tmp_string, 7);
      strncat(final_string, "; ", 2);
    }
    rf12_txdata(final_string, 14);
    // "#include <util/delay.h>" nicht vergessen
    // Kann man den Sender nicht pollen?
    uint16_t pause;
    for(pause=1000; pause; pause--)
      _delay_ms(1);
  }
}
hth, Jörg

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Heißt das, du kannst:
> - ein einzelnes Byte
> - einen konstanten string
> - einen einzelnen dtostrf()-gewandelten Wert
>senden (und empfangen)?


Kann eine Dtostrf()-gewandelten Wert empfangen werde deine 
Verbesserungsvorschläge mal einbringen und dann nocheinmal melden!

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

Bewertung
0 lesenswert
nicht lesenswert
T.M. wrote:

> Hab nach langen ausprobieren gemerkt das es wohl an der strncat funktion
> liegt

    strncat(Enddata,data,7);

In der Tat hast du da was missverstanden.

Was wird wohl die 7 da hinten angeben?
Die Länge von data? Wozu soll das gut sein? Wie lang der String in data 
ist, interessiert nun wirklich niemanden. Am allerwenigsten strcat oder 
strncat. Beide Funktionen nehmen einfach was da ist, solange bis sie im 
Quellstring auf ein '\0' Byte treffer.

Also wozu wird diese Längenangabe gut sein?
Um zu bezeichnen wieviel Platz im Zielarray zur Verfügung steht!
Genau das ist doch das grosse Problem von strcat, strcpy und wie sie 
alle heissen! Keine dieser Funktionen weiss wie gross das Zielarray ist 
und kann sich daher dagegen schützen, dass es versucht mehr Daten in das 
Ziel zu stopfen als dort überhaupt Platz hat.

Also wird dieses Argument mit Sicherheit NICHT die Größe des 
Quellstrings sein. Wenn die Funktion diesen Wert brauchen würde, könnte 
sie ihn ganz leicht selbst mit strlen ermitteln. Das ist die Größe des 
Zielarrays! In deinem Fall also:

    strncat( Enddata, data, sizeof(Enddata) );

Und warum kriegst du dann Zeichensalat?
Ganz einfach: Was macht strncat, wenn der Platz im Zielarray nicht 
reicht? Simpel: es hört auf umzukopieren. Aber gemeinerweise schliesst 
strncat in Falle, dass der Platz nicht ausreicht, den Zielstring dann 
nicht mehr mit einem '\0' Byte ab! Falls also der Zielplatz nicht 
ausreicht, dann hast du einen ungültigen String in der Zielvariablen! Du 
hast also jetzt einen ArrayOverflow durch einen ungültigen String 
eingewechselt. Sorry, aber String Verarbeitung in C ist nicht so 
einfach. Da ist Sorgfalt angesagt!

Das andere, du kannst bei der Ausgabe nicht eine fixe ANzahl an Bytes 
angeben. DU weisst ja nicht wie lang der String wirklich ist! ALso musst 
du das ermitteln. Oder aber du baust dir endlich eine Ausgabefunktion, 
die diese Anzahl nicht braucht (weil sie ausgibt, bis das abschliessende 
'\0' Zeichen auftaucht)
  while(1)
  { 
    final_string[0] = '\0'; // ' statt "
    for(i=0; i<2; i++)
    {
      sensor_value[i] = readADC(i);
      //"-1.234" bis "9.9999"?
      dtostrf(sensor_value[i], 6, 4, tmp_string);
      strncat(final_string, tmp_string, sizeof(final_string);
      strncat(final_string, "; ", sizeof(final_string));
    }
    rf12_txdata(final_string, strlen(final_string));
    for(pause=1000; pause; pause--)
      _delay_ms(1);
  }

Und kauf die ein Buch über C.
So schwer ist Stringverarbeitung dann auch wieder nicht.

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl heinz
Die AVR-Libc-docu liest sich aber so:
>Concatenate two strings.
>
>The strncat() function is similar to strcat(), except that only the first
> n characters of src are appended to dest.
(http://www.nongnu.org/avr-libc/user-manual/group__...)
>>dt.:" Verbind zwei strings.
>> die Funktion strncat() ähnelt strcat(), bis auf dass nur die ersten n
>> char's von src an dest gehängt werden
(Übersetzung von mir ;))
Das klingt auf jeden Fall so, als ob die Angabe "strlen(final_string)" 
ziemlich in die Hose gehen kann.

hth, Jörg

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

Bewertung
0 lesenswert
nicht lesenswert
Jörg G. wrote:
> @ Karl heinz
> Die AVR-Libc-docu liest sich aber so:
>>Concatenate two strings.
>>
>>The strncat() function is similar to strcat(), except that only the first
>> n characters of src are appended to dest.
> 
(http://www.nongnu.org/avr-libc/user-manual/group__...)
>>>dt.:" Verbind zwei strings.
>>> die Funktion strncat() ähnelt strcat(), bis auf dass nur die ersten n
>>> char's von src an dest gehängt werden
> (Übersetzung von mir ;))
> Das klingt auf jeden Fall so, als ob die Angabe "strlen(final_string)"
> ziemlich in die Hose gehen kann.

Du hast recht.
(Und ich hab mich vertan. strncpy kann man so benutzen, dass man sich 
gegenüber Array Overflow absichern kann. Bei strncat geht das so einfach 
nicht)

Allerdings: Damit gibt es in obigem Code überhaupt keinen Grund mehr 
strncat zu benutzen.
  while(1)
  { 
    final_string[0] = '\0'; // ' statt "
    for(i=0; i<2; i++)
    {
      sensor_value[i] = readADC(i);
      //"-1.234" bis "9.9999"?
      dtostrf(sensor_value[i], 6, 4, tmp_string);
      strcat(final_string, tmp_string);
      strcat(final_string, "; ");
    }
    rf12_txdata(final_string, strlen(final_string));
    for(pause=1000; pause; pause--)
      _delay_ms(1);
  }

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur noch mal ne frage am Rand warum soll die delay funktion unbedingt 
besser sein als wenn ich
 asm("nop")
 nutze ?

Bin leider noch nicht zum Ausprobieren gekommen werd dies allerding bis 
morgen abend schaffen.

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weil sich bei der Delay-Funktion

1. ein schlauer Mensch unter Kenntnis des Compilers mal Gedanken gemacht 
hat, wie man möglichst exakt die angegebene Verzögerung hinbekommt

2. weil sich so dein Code auch noch in einem anderen Projekt verwenden 
läßt, was z.B. mit ner anderen Taktfrequenz läuft

Autor: T.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok hab das Problem gelöst!

Nochmals danke für eure Hilfe !

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.