call by reference will nicht , Atmega163, C

#3437090
Lesenswert?

Hallo,

möchte die Uhrzeit in einer Funktion berechnen.
Dafür übergebe ich ihr die Adressen von std,min und sec (Stunden, 
Minuten, Secunden)
In der timer.c soll dann mithilfe eines SekundenFlags aus dem 
TimerInterrupt die Zeit berechnet werden und die Werte an die durch die 
Zeiger referenzierten Speicherplätze für std,min und sec gelegt werden.
Da das nicht funktioniert lass ich die Funktion gerade nur feste Werte 
verarbeiten, lasse also die Zeitberechnung weg. Um zu sehen ob die 
Funktion überhaupt angesprungen wird gibt sie einen Zähler zurück. Der 
zählt in der Main auch artig hoch, Funktion wird also angesprungen.

Anbei der, zugegebenermaßen umfangreiche, Code in C, aber man soll ja 
alles posten. Entscheident sind warscheinlich die timer.c und timer.h 
sowie die RedDisplayClock.c

Vielleicht enddeckt ja jemand den Fehler.

Jens
Angehängte Dateien:
Gast #3437349
Lesenswert?

Hallo Oliver,

die Ausgabe auf dem Display ist falsch. sec hat immer den Wert 5, min 
und std bleiben 0.
Wenn ich in der Main statt der Variablen Zahlen in den Ausgabeaufruf für 
das Display setze funzt es. Ich denke irgendetwas mit der 
Zeigergeschichte funktioniert nicht, die 5 sieht so nach Speichermüll 
aus.

Jens
#3437362
Lesenswert?

midibrain schrieb:
> Hallo Oliver,
>
> die Ausgabe auf dem Display ist falsch. sec hat immer den Wert 5, min
> und std bleiben 0.
> Wenn ich in der Main statt der Variablen Zahlen in den Ausgabeaufruf für
> das Display setze funzt es. Ich denke irgendetwas mit der
> Zeigergeschichte funktioniert nicht, die 5 sieht so nach Speichermüll
> aus.

Die Zeigersache ist in Ordnung.
Aber hier, diese Funktion ist fehlerhaft.
1
void put_number_lcd(uint8_t a, uint8_t b, uint16_t number)
2
//setzt eine Zahl bis max. 99 rechtsbündig an position a, b  
3
{
4
uint8_t i = 0;
5
  if(number < 10)
6
    {
7
      put_string_lcd(a,b,"0");
8
      b += 1;
9
      i = 1;
10
    }
11
    if((number < 100) && (number > 9))
12
      {
13
        i = 2;
14
      }
15
  
16
  char tmp[i];
17
  itoa(number, tmp, 10);
18
  put_string_lcd(a, b, tmp);
19
}

Um einen String "23" zu bilden, benötigst du ein Array der Länge 3(!), 
und nicht 2.
Denn der String besteht aus 3 Zeichen. '2', '3' und dem abschliessenden 
'\0' Zeichen, welches jeden String beendet.

Korrigier das mal und sieh nach, ob das dann schon alles war.
#3437370
Lesenswert?

Ich weiss, das steht (stand zumindest) im Kernighan&Ritchi auch so 
drinnen. Aber warum schreibst du
1
  return(i);

return ist kein Funktionsaufruf. return kann man einen Ausdruck angeben, 
der ausgewertet wird und dessen Ergebnis zurückgegeben wird. Nirgendwo 
in der Syntax wird gefordert, dass der Ausdruck in Klammern stehen muss. 
Bringt auch nicht viel.
1
  return i;
ist genausogut lesbar, wenn nicht sogar besser. Und sogar mit weniger 
Aufwand und einfacher zu tippen.

Du schreibst ja auch nicht
1
   j = (i);
oder?
#3437383
Lesenswert?

Hallo Karl-Heinz,

erstaunlich was Du alles sehen kannst...

Es war tatsächlich die falsche Stringlänge in der Displayroutine!
Habe die Stringlänge geändert und nun ist die Ausgabe korrekt, die 
Zeigergeschichte war es also nicht.

Vielen Dank und einen geruhsamen Sonntag Abend aus Berlin.

Jens
#3437392
Lesenswert?

Ich hätt ja die Funktion ezeit_ausgabe so geschrieben (wenn ich im µC 
den Platz im Flash habe)
1
//***************************************************************************************
2
void ezeit_ausgabe(uint8_t std, uint8_t min, uint8_t sec)
3
{
4
  char buff[20];
5

6
  sprintf( buff, "%02d:%02d:%02d", std, min, sec );
7
  put_string_lcd( TIMEPOSITION_Z, TIMEPOSITION_S, buff );
8
}

aber so eine Zahlenausgabe an sich ist ja auch nützlich.

Merke: du brauchst an solchen Stellen nicht kleckern. Ob du temporär ein 
Array der Länge 3 oder 10 anlegst, ist Jacke wie Hose. Wenn diese 
Differenz im Speicherverbrauch dein Programm sprengt, dann ist die Kacke 
sowieso schon am dampfen.
#3437400
Lesenswert?

Karl Heinz schrieb:

> aber so eine Zahlenausgabe an sich ist ja auch nützlich.

Allerdings solltest du dir mal überlegen, was deine Funktion 
put_number_lcd so alles macht, wenn du der mal irrtümlich zb die Zahl 
587 übergibst, wie sie zb durch einen ungewollten Programmfehler 
durchaus auch schon mal vorkomme kann.
Das letzte was du nämlich brauchen kannst ist, dass dir deine 
Basis-Ausgabefunktionen abkratzen, weil da Fälle entstehen, die du 
selbstverständlich nicht bedacht und auch nicht berücksichtigt hast, 
weil die im Nichtfehlerfall nicht vorkommen. Nur ist halt selten etwas 
von Anfang an perfekt.

Wenn die führenden 0-en dann nicht stimmen, dann ist das kein Beinbruch. 
Wenn du dann aber versucht ein Array der Länge 0 zu allokieren, dann IST 
das ein Beinbruch. Kein Beinbruch hingegen ist es, wenn du itoa den 
Integer 7 konverteren lässt und itoa dazu ein char Array der Länge 7 zur 
Verfügung stellst. Dann werden eben temporär ein paar Teile des Arrays 
nicht benutzt, aber erst mal passiert sonst nicht viel. Insbesondere 
zerschiesst du dir dann auch nicht den Stack, indem du ein Array 
überläufst.
#3437912
Lesenswert?

Hallo Karl-Heinz,

hab die Ausgaberoutine dahingehend geändert das sie Zahlen > 99 
ignoriert. Das ist keine elegante lösung aber verhindert erst einmal 
merkwürdiges Verhalten aufgrund falscher (zu großer) Werte.
Das mit dem return(x) habe ich mir wohl am Anfang des programmierens 
"eingefangen". Ist wirklich unnütz, werde es mir abgewöhnen.

Vielen Dank noch einmal für die Hilfe und die Tip`s, immer wieder toll 
bei Euch im Forum!

Jens

P.S.: Wie kann ich diesen Beitrag als "gelöst" kennzeichnen?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren