www.mikrocontroller.net

Forum: Compiler & IDEs AVR-GCC Anfängerproblem(e) - Rechenoperationen mit Variablen


Autor: Black Zero (black)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wie schon die Überschrift meines Beitrages verrät, bin ich gerade am 
AVR-GCC "lernen".
Vorauskenntnisse bringe ich aus der PC-Programmierung mittels Basic und 
Pascal und aus der "C-Control I M-Unit 2"-Programmierung mittels CCBasic 
und BasiC++ mit.

Ich benutze das AVR Studio 4.18 zur Programmierung und habe bereits ein 
sehr einfaches Projekt mit AVR-GCC erfolgreich programmiert und im 
Einsatz.

Jedoch stehe ich jetzt seit Tagen schon vor einem mir unlösbaren 
Problem. Die Suche in diversen Tutorials und Google hat nichts zur 
Lösung beigetragen, daher schreibe ich nun diesen Beitrag.

Nun aber zum Projekt selbst (eigentlich auch ganz einfach - aber derzeit 
nicht für mich):
Ich habe zwei Taster (schalten nach Masse). Drücke ich den einen Taster, 
soll eine Variable um 1 hoch gezählt werden; drücke ich den Anderen, 
soll die selbe Variable um 1 herunter gezählt werden.

Bevor ich aber die Taster interplementieren wollte, wollte ich zuerst 
ein ganz einfaches Testprogramm schreiben, welches einfach in einer 
Schleife die Variable hochzählt:

>#include <stdint.h>
>#include <util/delay.h>
>
>unsigned char Zaehler;
>
>int main (void)
>{
>while (1)
>{
>Zaehler = Zaehler++;
>_delay_ms_(1000);
>}
>}

Lasse ich die Schleife "while (1)" weg, so wird die Variable Zähler 
tadellos von 0 auf 1 erhöht. Will ich aber, dass die Variable alle 1 
Sekunde um 1 erhöht wird, so wird einfach der Ausdruck "Zaehler = 
Zaehler++;" übersprungen und das Programm nach 1 Sekunde beendet.

Wo liegt hier mein (Denk-)Fehler? Die "While"-Schleife funktioniert(e) 
auch ohne "Return"-Befehl bei meinem letzten Projekt.

Es wäre toll, wenn Ihr mir einen kleinen Tipp geben könntet, warum mir 
der Debugger die Variable nicht erhöht...


Vielen Dank und Grüße,

Black

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Diese Zeile:
 Zaehler = Zaehler++;
erhöht erst Zaehler um 1 (wegen des ++) und weist an Zaehler
dann den alten Wert zu, womit die Variable wieder den alten Wert
hat.
Richtig wäre z.B.:
  Zaehler++;

oder
  Zaehler = Zaehler+1;

PS: Quelltexte sollte man hier im Forum mit
[c]
 ...
[/c]
formatieren.

Autor: Black Zero (black)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für die schnelle Antwort.

Was ich vielleicht noch erwähnen sollte (habe ich leider vergessen) ist, 
dass ich einen ATTiny2313-20PU mit "AVR Simulator" im AVR Studio 4.18 
programmiere.

Ich habe mal meinen Quelltext geändert:
#include <avr/io.h>
#include <util/delay.h>

// Variablen definieren
unsigned char Zaehler;    // Up/Down-Zähler (0-255)

// --- Hauptprogramm ---
int main (void)            
{
 while (1)                // Endlosschleife
 {
  Zaehler++;              // Zaehler um 1 erhöhen
 }
}

Wenn ich nun Compiliere und Debugge, dann bleibt der Pfeil (welcher die 
aktuell verarbeitete Codezeile anzeigt) bei der ersten "{" stehen - egal 
wie oft ich auf "Step into next statement" klicke.
Die Variable "Zaehler" bleibt bei ihrem Wert "0".

Normalerweise sollte der Debugger doch in die Schleife springen und 
jedes mal bei Drücken von "Step into next statement" die Variable 
"Zaehler" um 1 erhöhen... tut er aber nicht - was habe ich hier falsch 
gemacht?

Weitere Hinweise und Tipps wären super !


Vielen Dank und Grüße,

Black

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich vermute, daß der Compiler so schlau ist zu merken, daß
Zaehler nie mehr verwendet wird und deshalb die Rechnerei
einfach wegoptimiert.

Falls ja, sollte es helfen, die Variable so zu definieren:
volatile unsigned char Zaehler;    // Up/Down-Zähler (0-255)

Abgesehen davon hast du dein _delay_ms() nicht mehr drin.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Diese Zeile: Zaehler = Zaehler++;
> erhöht erst Zaehler um 1 (wegen des ++) und weist an Zaehler
> dann den alten Wert zu, womit die Variable wieder den alten Wert
> hat.

Nicht unbedingt Nach ISO-C ist das Verhalten undefiniert. In welcher 
Reihenfolge diese Operationen durchgeführt werden, ist nicht festgelegt.

Black Zero schrieb:
> Wenn ich nun Compiliere und Debugge, dann bleibt der Pfeil (welcher die
> aktuell verarbeitete Codezeile anzeigt) bei der ersten "{" stehen - egal
> wie oft ich auf "Step into next statement" klicke.
> Die Variable "Zaehler" bleibt bei ihrem Wert "0".

Der Compiler hat erkannt, daß in der Schleife die Variable nicht benutzt 
wird und die Schleife nie verlassen wird. Also hat der Optimizer das 
Inkrementieren entfernt, weil es nicht benötigt wird.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:
> Nicht unbedingt Nach ISO-C ist das Verhalten undefiniert. In welcher
> Reihenfolge diese Operationen durchgeführt werden, ist nicht festgelegt.

ja, und damit aus 2 Gründen falsch: 1. weil es undefiniert ist und
2. weil es mit gcc offenbar nicht geht.

Autor: Black Zero (black)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

jetzt funktioniert es, so wie es soll.
Anscheinend war es die kombination aus dem "Zaehler = Zaehler++;" und 
dem "unsigned char Zaehler".

Das "_delay_ms(1000);" hab ich vergessen mit zu posten, da ich bein 
Debuggen diesen immer auskommentiere, sonst muss ich mit Sprungmarken 
arbeiten, da ich sonst ewig lange "Step into next statement" drücken 
müsste...

So lautet nun der funktionierende Code:
#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>

// Variablen definieren
volatile unsigned char Zaehler; // Up/Down-Zähler (0-255)      

// --- Hauptprogramm ---
int main (void)            
{
// Pins definieren
 DDRB = 0xff;                   // PortB (0-7) als Ausgang definieren (LEDs)

// Programm
 while (1)                      // Endlosschleife
 {
  Zaehler = Zaehler+1;          // Zaehler um 1 erhöhen
  PORTB = Zaehler;              // Zahl an PortB Binär ausgeben
  _delay_ms(1000);              // 1 Sekunde warten
 }
}

Ich habe bereits eine kleine Anzeige mittels 8 LEDs interplementiert, 
damit der Code einen kleinen Sinn ergibt.
Übertragen auf den ATTiny, macht dieser auch das, was er soll (ist bei 
mir nicht immer der Fall gewesen).

Vielen Dank für die tolle Hilfe!


Grüße,

Black

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Black Zero schrieb:
> // Programm
>  while (1)                      // Endlosschleife
>  {
>   Zaehler = Zaehler+1;          // Zaehler um 1 erhöhen
>   PORTB = Zaehler;              // Zahl an PortB Binär ausgeben
>   _delay_ms(1000);              // 1 Sekunde warten
>  }
> }

Bei diesem Code bräuchtest du das volatile allerdings nicht mehr. Das 
hast du vorher ja nur gebraucht, weil dein Zähler für nichts mehr 
verwendet wurde. Jetzt wird sein Wert aber in jedem Durchauf nach PORTB 
geschrieben, welches selbst schon volatile ist (wie sämtliche 
I/O-Register).

Autor: Black Zero (black)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:
> Bei diesem Code bräuchtest du das volatile allerdings nicht mehr. Das
> hast du vorher ja nur gebraucht, weil dein Zähler für nichts mehr
> verwendet wurde. Jetzt wird sein Wert aber in jedem Durchauf nach PORTB
> geschrieben, welches selbst schon volatile ist (wie sämtliche
> I/O-Register).
Vielen Dank für den Hinweis !

Autor: Imon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Außerdem solltest du die Variable Zähler nicht global machen,
gewohn dir so was gleich wieder ab sie wird nur in der main Funktion 
gebraucht also sollte sie auch dort definiert werden.
Glaube mir es macht das Debuggen sehr viel einfacher wenn Variablen nur 
in denn Kontext definiert sind in dem du sie brauchst in deinen Fall in 
der Funktion main.
Wenn die Projekte mal größer werden solltest du die externe Variable 
wenigsten static machen so das du sicher sein kannst das externe 
Variablen nur innerhalb der Datei existieren.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ein kleiner Hinweis: Es ist sinnvoll sich von Anfang an 
anzugewöhnen alle Variablen zu Beginn der Verwendung sauber zu 
initialisieren. Damit eliminierst du eine häufige Fehlerquelle ;)

MfG
Stefan

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.