Forum: Compiler & IDEs 3 while-Schleifen zuviel für mega16???


von Dominik L (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!
Ich bin absolut verwirrt. Warum macht mein Controller bei den
einfachsten Programmen nur Unsinn? Das Programm im Anhang soll mir
eigentlich nur 3 verschiedenen Zustände im Wechsel an PortB ausgeben,
bleibt jedoch nach dem dritten Zustand einfach stehen, also gibt 0x81
aus. Woran kann das liegen?
Habe noch ein paar mehr Beispiele, die noch kurioser sind. Die kann ich
später mal posten.

MFG Dominik

von Christoph _. (chris)


Lesenswert?

Vermutlich gibt das Programm 3 verschiedene Zustände im Wechsel an PortB
aus. Also eigentlich genau das, was es soll. Vermutlich aber so schnell,
dass du das mit LEDs nicht sichtbar machen kannst.
Falls du das nicht beabsichtigt haben solltest:

Der gcc sieht wohl, dass deine while-Schleifen "sinnlos" sind und
ersetzt sie durch ein "a = 0;". Wenn du Warteschleifen willst, würd
ich dir delay.h aus der avrlibc empfehlen. Dann kannst du sicher sein,
dass zumindest das funktioniert (aber bitte die Doku lesen wegen der
Beschränkungen). Ansonsten musst du in die Schleifen irgendeinen
assembler-Befehl wie z.B. nop schreiben (wird nicht optimiert) oder du
deklarierst a als volatile (was aber andere Performance-Nebeneffekte
haben könnte, weswegen delay.h IMHO die bessere Wahl wäre [abgesehen
von Timern, aber du willst ja erstmal Warteschleifen]).

von Dominik L (Gast)


Lesenswert?

Hey Chris.
Besten Dank! Das war es anscheined. Hat mir echt geholfen. Gibt es auch
Funktionen, die noch längere Wartezeiten ermöglichen als die 65000 Takte
mit dem 16 Bit Zähler?

MFG Dominik

von Helge Dietert (Gast)


Lesenswert?

Hallo,

der Compiler optimiert die While-Schleifen wahrscheinlich komplett weg,
da sie für ihn keinen Sinnn ergeben, d.h. entweder die speziellen
Bibliotheksfunktionen verwenden oder so was selbst schreiben. Jenes ist
wahrscheinlich portabler und zuverlässiger.

Der Prozesser schaltet wahrscheinlich die drei Zustände durch und macht
dann den Rücksprung, der immerhin 2-Takte braucht, so dass du nur das
wahrnimmst. Schau Dir das Assembler mal an!

Helge

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Gibt es auch Funktionen, die noch längere Wartezeiten ermöglichen
> als die 65000 Takte mit dem 16 Bit Zähler?

Hier verwechselst du wohl gleich mal alles Mögliche.

Erstens, mit einem 16-bit-Zähler kann man sehr viel mehr als nur 64
Ki Takte zählen, da man ihn noch mit einem Vorteiler versehen kann,
der bis zu 1:1024 teilt, das macht also maximal 64 Mi Takte bis zum
Überlauf mittels Hardware.  Dann kann man natürlich noch den Overflow-
Interrupt auswerten, und softwaremäßig N weitere Bytes ,,nach oben''
zur Zählweite hinzufügen.

Zweitens, die Funktionen in <avr/delay.h> gestatten zwar auch nur 64
Ki als maximales Argument (in _delay_loop_2), aber das teilt sich auch
nochmals durch 4 Takte pro Schleifendurchlauf, also 256 Ki Takte
maximal.  Die kann man natürlich noch einfach schachteln:
1
#include <stdint.h>
2
3
#define F_CPU 8000000UL
4
#include <avr/delay.h>
5
6
7
...
8
uint8_t i;
9
...
10
/* 1 Sekunde warten */
11
for (i = 0; i < 100; i++)
12
  _delay_ms(10);

von Dominik L (Gast)


Lesenswert?

Hallo Jörg.
Du hast natürlich recht :-) Hab net wirklich nachgedacht... Also danke
dass du mir mal eben die Augen geöffnet hast.

Grüße Dominik

von michi (Gast)


Lesenswert?

Hi

@Christoph

warum sind diese drei while schleifen denn sinnlos?

void main(void){
  int16_t a;
  int16_t h=2;
  DDRB=0xff;
  while(1){
    a=30000;
    PORTB=0x0f;

    while(a>0){
      a--;
    }
    a=30000;
    PORTB=0xf0;

    while(a>0){
      a--;
    }
    PORTB=0x81;
    a=30000;

    while(a>0){
      a--;
    }
  }
}

Irgendwie machen dise schleifen doch sinn, oder?
Warum sollten die wegoptimiert werden.
Diese schleifen währen doch sinnlos:

while(a>0){}


cu

von mthomas (Gast)


Lesenswert?

Nur vom kurz drueberschauen: Die Schleifen werden nicht gebraucht, da
a=0 ohne Schleifenkonstrukt bestimmt werden kann . Aber a wird nie
genutzt, also faellt "alles was damit zu tun hat" weg. Uebrig bleiben
die Portzuweisungen. Falls das ganze irgend eine Art Zeitverzoegerung
sein soll: volatile uint16_t a.

von Thomas K. (thomas_k)


Lesenswert?

Mit uint16_t kommt er aber nicht auf eine negative Zahl. Diese wird aber
benötigt um die Scheilfen zu verlassen :)

von Rolf Magnus (Gast)


Lesenswert?

> Mit uint16_t kommt er aber nicht auf eine negative Zahl. Diese
> wird aber benötigt um die Scheilfen zu verlassen :)

Wie kommst du auf die Idee?

von Thomas K. (thomas_k)


Lesenswert?

uint bedeutet unsigned

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Ja, und?
Ist '0' negativ?

von ---- (Gast)


Lesenswert?

Um weiteren Mißverständnissen vorzubeugen:

Der Hinweis ging an mthomas, da er aus "int16_t a" aus dem Original
(versehentlich) schnell ein "uint16_t a" gemacht hatte. Die
Folgerung, daß mit diesem Variablentypen die Schleife nicht
abgebrochen werden könne, war falsch...

@Patrick: Du weißt doch genau was gemeint war. Nicht auflaufen
lassen... da kriegste nur Schelte. *;-)*
Du hast zwar Recht, aber Thomas' Hinweis in der Grundidee war auch
gerechtfertigt - nur die Ausführung war mangelhaft ;-)

----, (QuadDash).

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

'tschuldigung! Hab mich zu schnell hinreißen lassen :-)

von Thomas K. (thomas_k)


Lesenswert?

Ups, tut mir echt Leid. Hab ich da gewaltig vertan :(

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.