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


von Black Z. (black)


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

von Klaus W. (mfgkw)


Lesenswert?

Diese Zeile:
1
 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.:
1
  Zaehler++;

oder
1
  Zaehler = Zaehler+1;

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

von Black Z. (black)


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:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
// Variablen definieren
5
unsigned char Zaehler;    // Up/Down-Zähler (0-255)
6
7
// --- Hauptprogramm ---
8
int main (void)            
9
{
10
 while (1)                // Endlosschleife
11
 {
12
  Zaehler++;              // Zaehler um 1 erhöhen
13
 }
14
}

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

von Klaus W. (mfgkw)


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:
1
volatile unsigned char Zaehler;    // Up/Down-Zähler (0-255)

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

von Rolf Magnus (Gast)


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.

von Klaus W. (mfgkw)


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.

von Black Z. (black)


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:
1
#include <avr/io.h>
2
#include <stdint.h>
3
#include <util/delay.h>
4
5
// Variablen definieren
6
volatile unsigned char Zaehler; // Up/Down-Zähler (0-255)      
7
8
// --- Hauptprogramm ---
9
int main (void)            
10
{
11
// Pins definieren
12
 DDRB = 0xff;                   // PortB (0-7) als Ausgang definieren (LEDs)
13
14
// Programm
15
 while (1)                      // Endlosschleife
16
 {
17
  Zaehler = Zaehler+1;          // Zaehler um 1 erhöhen
18
  PORTB = Zaehler;              // Zahl an PortB Binär ausgeben
19
  _delay_ms(1000);              // 1 Sekunde warten
20
 }
21
}

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

von Rolf Magnus (Gast)


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).

von Black Z. (black)


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 !

von Imon (Gast)


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.

von Stefan (Gast)


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

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.