Forum: Compiler & IDEs Zeiger Problem aus einer Funktion heraus


von Bene J. (terfagter)


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):
1
void abfrage_spg_hc(void)
2
{
3
  char spg_vor[5], spg_nach[5];                //Variablen für Funktion deklarieren
4
  uint16_t spg_utoa=0, spg=0;
5
  float result=0;
6
  char data[12];
7
  uint8_t len=11;
8
    
9
  ADCSR=0xc7;                          //ADC einschalten und konfigurieren; Teiler 128
10
  
11
  while (!(spg_utoa == 10))                  //arithm. Mittelwert bilden aus 10 Messungen
12
  {  
13
    loop_until_bit_is_clear(ADCSR,ADSC);  
14
    result += ADCW;
15
    ADCSR |= (1<<ADSC);                  //ADC-Einzelmessung neustarten
16
    spg_utoa++;
17
  }
18
  
19
  result /= 10;
20
  
21
  spg = result * 5000/1024;
22
    
23
  spg_utoa = spg % 1000;                    //Wert für Nachkommazahl umwandeln
24
  spg /= 1000;                        //Wert für Vorkommazahl umwandeln
25
  utoa( spg, spg_vor, 5 );                  //Werte in ASCII umrechnen
26
  utoa( spg_utoa, spg_nach, 5 );  
27
  
28
  sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%s"".""%s""\x0D", spg_vor, spg_nach);    //String zusammenfügen
29
  send_to_lcd(data, len);                          //String an LCD senden
30
}

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:
1
void abfrage_spg_hc(char *spg_vor, char *spg_nach)
2
{
3
  uint16_t spg_utoa=0, spg=0;                  //Variablen für Funktion deklarieren
4
  float result=0;
5
6
  ADCSR=0xc7;                          //ADC einschalten und konfigurieren; Teiler 128
7
  
8
  while (!(spg_utoa == 10))                  //arithm. Mittelwert bilden aus 10 Messungen
9
  {  
10
    loop_until_bit_is_clear(ADCSR,ADSC);  
11
    result += ADCW;
12
    ADCSR |= (1<<ADSC);                  //ADC-Einzelmessung neustarten
13
    spg_utoa++;
14
  }
15
  
16
  result /= 10;
17
  
18
  spg = result * 5000/1024;
19
    
20
  spg_utoa = spg % 1000;                    //Wert für Nachkommazahl umwandeln
21
  spg /= 1000;                        //Wert für Vorkommazahl umwandeln
22
  utoa( spg, spg_vor, 5 );                  //Werte in ASCII umrechnen
23
  utoa( spg_utoa, spg_nach, 5 );  
24
}

Das steht jetzt unter anderem in meiner main.c:
1
char spg_vor[5], spg_nach[5];
2
uint8_t len=12;
3
char data[12];
4
5
abfrage_spg_hc(spg_vor, spg_nach);
6
sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%s"".""%s""\x0D", spg_vor, spg_nach);    //String zusammenfügen
7
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.

von Stefan B. (stefan) Benutzerseite


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.

von Bene J. (terfagter)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von Stefan E. (sternst)


Lesenswert?

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

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Bene J. (terfagter)


Lesenswert?

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

von Karl H. (kbuchegg)


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
1
uint16_t abfrage_spg_hc()
2
{
3
  float   result=0;
4
  uint8_t i;
5
6
  ADCSR = 0xc7;                          //ADC einschalten und konfigurieren; Teiler 128
7
  
8
  for( i = 0; i < 10; ++i )
9
  {
10
    //arithm. Mittelwert bilden aus 10 Messungen
11
12
    loop_until_bit_is_clear(ADCSR,ADSC);  
13
    result += ADCW;
14
    ADCSR |= (1<<ADSC);                  //ADC-Einzelmessung neustarten
15
  }
16
  
17
  result /= 10;
18
  
19
  return result * 5000/1024;
20
}
21
 
22
....
23
24
25
  uint8_t len;
26
  char data[50];
27
  uint16_t spg;
28
29
  spg = abfrage_spg_hc();
30
31
  sprintf(data, "\x1B""DL""\x1B""ZC""\x03""\x3F""%d.03d""\x0D", spg / 1000, spg % 1000 );
32
33
  len = strlen( data );
34
  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.

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.