www.mikrocontroller.net

Forum: Compiler & IDEs Zeiger Problem aus einer Funktion heraus


Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

die folgende Funktion befindet sich in meiner funktionen.c (Ich lese 
über ADC0 eine Spannung ein und will diese auf einem LCD ausgeben):
void abfrage_spg_hc(void)
{
  char spg_vor[5], spg_nach[5];                //Variablen für Funktion deklarieren
  uint16_t spg_utoa=0, spg=0;
  float result=0;
  char data[12];
  uint8_t len=11;
    
  ADCSR=0xc7;                          //ADC einschalten und konfigurieren; Teiler 128
  
  while (!(spg_utoa == 10))                  //arithm. Mittelwert bilden aus 10 Messungen
  {  
    loop_until_bit_is_clear(ADCSR,ADSC);  
    result += ADCW;
    ADCSR |= (1<<ADSC);                  //ADC-Einzelmessung neustarten
    spg_utoa++;
  }
  
  result /= 10;
  
  spg = result * 5000/1024;
    
  spg_utoa = spg % 1000;                    //Wert für Nachkommazahl umwandeln
  spg /= 1000;                        //Wert für Vorkommazahl umwandeln
  utoa( spg, spg_vor, 5 );                  //Werte in ASCII umrechnen
  utoa( spg_utoa, spg_nach, 5 );  
  
  sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%s"".""%s""\x0D", spg_vor, spg_nach);    //String zusammenfügen
  send_to_lcd(data, len);                          //String an LCD senden
}

Ich möchte die beiden letzten Zeilen aber in meiner main.c benutzen. 
Also habe ich die Funktion so umgewandelt, das die Variablen spg_vor und 
spg_nach mit Hilfe von Zeigern auch ausserhalb dieser Funktion zu 
Verfügung stehen. Wenn ich es denn dann richtig gemacht habe.

funktion.c:
void abfrage_spg_hc(char *spg_vor, char *spg_nach)
{
  uint16_t spg_utoa=0, spg=0;                  //Variablen für Funktion deklarieren
  float result=0;

  ADCSR=0xc7;                          //ADC einschalten und konfigurieren; Teiler 128
  
  while (!(spg_utoa == 10))                  //arithm. Mittelwert bilden aus 10 Messungen
  {  
    loop_until_bit_is_clear(ADCSR,ADSC);  
    result += ADCW;
    ADCSR |= (1<<ADSC);                  //ADC-Einzelmessung neustarten
    spg_utoa++;
  }
  
  result /= 10;
  
  spg = result * 5000/1024;
    
  spg_utoa = spg % 1000;                    //Wert für Nachkommazahl umwandeln
  spg /= 1000;                        //Wert für Vorkommazahl umwandeln
  utoa( spg, spg_vor, 5 );                  //Werte in ASCII umrechnen
  utoa( spg_utoa, spg_nach, 5 );  
}

Das steht jetzt unter anderem in meiner main.c:
char spg_vor[5], spg_nach[5];
uint8_t len=12;
char data[12];

abfrage_spg_hc(spg_vor, spg_nach);
sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%s"".""%s""\x0D", spg_vor, spg_nach);    //String zusammenfügen
send_to_lcd(data, len);                                    //String an LCD senden

Mein Display gibt aber nur in der ersten Variante Daten aus. Bei meiner 
Änderung wird nichts mehr ausgegeben. Ich hoffe ihr könnte mir bei 
diesem Problem helfen.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> char data[12];
> sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%s"".""%s""\x0D"...

data ist etwas sparsam angelegt oder? Allein die festen Bestandteile 
ohne die beiden %s-formatierten Strings fressen schon 11 Zeichen.

Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja schon, habs aber auch einige male vergrößert. Ist jetzt nur der 
letzte Wert, den ich verwendet habe.

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

Bewertung
0 lesenswert
nicht lesenswert
Deine Arbeitsteilung der Funktionen ist nicht gut.

Besser ist es, wenn die Funktion abfrage_spg_hc nur das tut, was ihr 
Name verspricht. Sie misst die Spannung und liefert einen Wert(!) 
(keinen Text) zurück, der der Spannung entspricht.
Was mit dem Wert weiter passiert, ob der jetzt in einen String 
umgewandelt wird und angezeigt wird, oder ob der in eine Regelung geht 
oder .... hat diese Funktion nicht zu interessieren. Sie ist dafür 
zuständig die Spannung zu messen und den Spannungswert als Zahl zu 
liefern.
Insbesondere hat diese Funktion nicht die Aufgabe den Spannungswert in 
den Vorkomma und den Nachkommateil zu splitten.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Außerdem hast du offenbar nicht verstanden, welche Bedeutung der letzte 
Parameter der Funktion utoa hat.

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

Bewertung
0 lesenswert
nicht lesenswert
> char spg_vor[5], spg_nach[5];

Werden die Werte, die Du hiermit

>  utoa( spg, spg_vor, 5 );
>  utoa( spg_utoa, spg_nach, 5 );

versuchst umzurechnen (wie Stefan schon anmerkte, ist die 5 hier fehl am 
Platz!), denn auch als Dezimalzahlen nie größer als 9999?

Wenn sie das werden, dann sind spg_vor und spg_nach nämlich zu klein.

Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@rufus:
Könntest du das noch etwas anders ausdrücken? Ich verstehe noch nicht 
ganz was du meinst!?

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

Bewertung
0 lesenswert
nicht lesenswert
Bene Jan schrieb:
> @rufus:
> Könntest du das noch etwas anders ausdrücken? Ich verstehe noch nicht
> ganz was du meinst!?

Sieh dir einfach mal die Doku zu utoa an.
Insbesondere den dritten Parameter.
Der ist nicht das, was du denkst das er ist. Das ist NICHT die Größe des 
char-Buffers.

Allerdings brauchst du utoa hier gar nicht, wenn du

* die Funktion mit einer vernünftigen, brauchbaren Schnittstelle
  versiehst (wie schon weiter oben angedeutet)
* In main dann sowieso ein sprintf benutzt

Damit ist dann auch der Fehler, dass deine Anzeige ab und zu falsche 
Werte anzeigen wird, auch ad Acta gelegt.
utoa erzeugt dir keine führenden 0-en. Das solltest du nämlich bedenken, 
wenn du dich fragst, was den Unterschied zwischen 2.5 und 2.05 in Bezug 
auf den abgetrennten Nachkommaanteil ausmacht.


So in etwa
uint16_t abfrage_spg_hc()
{
  float   result=0;
  uint8_t i;

  ADCSR = 0xc7;                          //ADC einschalten und konfigurieren; Teiler 128
  
  for( i = 0; i < 10; ++i )
  {
    //arithm. Mittelwert bilden aus 10 Messungen

    loop_until_bit_is_clear(ADCSR,ADSC);  
    result += ADCW;
    ADCSR |= (1<<ADSC);                  //ADC-Einzelmessung neustarten
  }
  
  result /= 10;
  
  return result * 5000/1024;
}
 
....


  uint8_t len;
  char data[50];
  uint16_t spg;

  spg = abfrage_spg_hc();

  sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%d.03d""\x0D", spg / 1000, spg % 1000 );

  len = strlen( data );
  send_to_lcd(data, len);                                    //String an LCD senden

An deiner send_to_lcd Funktion solltest du auch noch arbeiten. Es ist 
unsinnig, die Länge eines Strings im Vorfeld feststellen zu müssen. Eine 
korrekte String-Ausgabefunktion braucht die Länge nicht explizit.

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.