Forum: Mikrocontroller und Digitale Elektronik Problem mit delay.h und Optimierungsstufe v. AVR Studio 4


von Nn N. (jaytharevo)


Lesenswert?

Hoi!

Also kurz zur Vorgeschichte.
Letzten Dienstag war ich mit dem Debuggen von meinem Projekt 
beschäftigt. War ganz zufrieden an dem Tag da ich fast alles zum laufen 
brachte, was ich mir so vorstellte. 2 Tage später hatte ich wieder Zeit 
und hab noch ein paar Dinge geändert. Unter anderem brauchte ich die 
delay.h Library. Beim Kompilieren bekam ich dann die Warnung: "functions 
won't work as designed....optimization level....". Also hab ich dann die 
Optimierungsstufe geändert und siehe da, keine Warnungen/Fehler mehr. 
Als ich es dann probieren wollte macht der Controller (ATmega88PA) nicht 
mal mehr annähernd das was er machen sollte. Leider verschwendete ich 
den restlichen Teil meiner Zeit mit der Fehlersuche im Code (hatte ja 
einiges geändert). Übers Wochenende ist mir, dann eingefallen das ich 
die Optimierungsstufe veränderte. Und als ich es heute wieder probierte 
funktionierte alles wie gewohnt, man war ich froh^^.
Dafür hab ich immer noch die Warnung der delay.h. Was kann man nun tun?
Meiner Meinung nach funktionierte einer der Interrupts nicht so wie er 
es sollte. Aber wie zum Henker kann da die Optimierung da reinpfuschen?

Hat wer eine Lösung für mich? Würde die delay.h nämlich gern verwenden 
:).

MfG
Julian

von Karl H. (kbuchegg)


Lesenswert?

Julian Schild schrieb:

> Als ich es dann probieren wollte macht der Controller (ATmega88PA) nicht
> mal mehr annähernd das was er machen sollte. Leider verschwendete ich
> den restlichen Teil meiner Zeit mit der Fehlersuche im Code (hatte ja
> einiges geändert).

Das war nicht wirklich verschwendet.

> Übers Wochenende ist mir, dann eingefallen das ich
> die Optimierungsstufe veränderte. Und als ich es heute wieder probierte
> funktionierte alles wie gewohnt, man war ich froh^^.

Du hast deine Programmfehler nicht behoben. Du hast sie nur versteckt.

> Dafür hab ich immer noch die Warnung der delay.h. Was kann man nun tun?

Die eigentlichen Fehler im Code beheben, so dass der Optimizer nach 
Herzenslust arbeiten kann.

> Meiner Meinung nach funktionierte einer der Interrupts nicht so wie er
> es sollte. Aber wie zum Henker kann da die Optimierung da reinpfuschen?

Schuss ins Blaue: vergessene 'volatile' bei den Kommunikationsvariablen 
der ISR mit dem Rest des Programms.

> Hat wer eine Lösung für mich? Würde die delay.h nämlich gern verwenden
> :).

die _delay_xx Sachen sind meistens sowieso der falsche Ansatz. Für die 
ersten einfachen Programme geht das noch. Aber ein ernsthaftes, 
tragfähiges Design ist mit dem Auftauchen von _delay_ms normalerweise 
meistens zum Scheitern verurteilt.
Bei einer sauberen, evantbasierten Herangehensweise benötigt man keine 
_delay_xx. Ausser vielleicht in Ausnahmefällen, wenn man mittels 
_delay_us (NICHT _delay_ms !) kurze Verzögerungen zur Pulsgenerierung 
benötigt.

von Hannes (Gast)


Lesenswert?

>Aber ein ernsthaftes,
>tragfähiges Design ist mit dem Auftauchen von _delay_ms normalerweise
>meistens zum Scheitern verurteilt.

Und warum?

von Karl H. (kbuchegg)


Lesenswert?

Hannes schrieb:
>>Aber ein ernsthaftes,
>>tragfähiges Design ist mit dem Auftauchen von _delay_ms normalerweise
>>meistens zum Scheitern verurteilt.
>
> Und warum?

Probier einfach mal dein Programm auszubauen, so dass es 2 oder mehr 
Dinge mehr oder weniger gleichzeitig macht. zb Tasten überwachen und 2 
LED unterschiedlich schnell blinken lassen. Und schon hast du ein 
Problem.

Oder arbeitest du in der Küche zb so, dass du erst die Suppe kochst, 
daneben stehen bleibst, bis die fertig ist. Ist die Suppe fertig, 
schälst du die Kartoffeln und kochst sie. Sind die Kartoffeln gar, kommt 
das Fleisch in die Pfanne. Und wenn das dann fertig ist, fängst du an 
den Salat zu waschen.

Das machst du nicht. Du machst alles 'gleichzeitig' und lenkst deine 
Aufmerksamkeit kurz rundum, Suppe - Kartoffeln - Fleisch - Salat. Nur so 
wird alles gleichzeitig fertig. Der Schlüssel liegt also darin, nicht zu 
warten, bis eine Aktion fertig ist, sondern in den erzwungenen 
Wartepausen etwas anderes zu machen. Dazu ist aber ein _delay_ms völlig 
ungeeignet.

von Hannes (Gast)


Lesenswert?

Aber wenn es viele Dinge gleichzeitig machen soll, baut man doch kein 
delay ein.

Was aber spricht dagegen, wenn man z. B. einen Triggerkontakt abfrägt 
und sonst nichts anderes zu tun hat, nach der Flankenerkennung 10 ms per 
delay zu warten?

von Karl H. (kbuchegg)


Lesenswert?

Hannes schrieb:
> Aber wenn es viele Dinge gleichzeitig machen soll, baut man doch kein
> delay ein.
>
> Was aber spricht dagegen, wenn man z. B. einen Triggerkontakt abfrägt
> und sonst nichts anderes zu tun hat, nach der Flankenerkennung 10 ms per
> delay zu warten?

Nichts.

Aber den Fall hat er höchst wahrscheinlich nicht.
Er hat Interrupts erwähnt. Daraus schliesse ich, dass er nicht mehr 
diesen Trivialfall hat, sondern seine Komplexität höher liegt.

Vielleicht liege ich falsch mit dieser Einschätzung. Mag sein.
Aber meistens ist mein Riecher schon ganz gut.

von H.Joachim S. (crazyhorse)


Lesenswert?

In der Initialisierungsphase des Controllers nutze ich delay recht 
häufig.
Prinzipiell hast du Recht, aber das ist kein Grund es gänzlich zu 
verdammen.
Genauso wie das ewig geschmähte goto :-). Setze ich ohne Bedenken ein, 
wenn es sich anbietet und Konstrukte deutlich vereinfacht.
Ja, es geht ohne. Und es geht auch ohne delay. Und es geht auch mit noch 
viel weniger.
Kurzum - wenn eine fertige Funktion angeboten wird, sollte sie auch 
funktionieren wie gewollt.
Es lässt sich ja leicht testen, ob es an der evtl. fehlerhaften Funktion 
liegt oder an anderen Effekten.

von Hannes (Gast)


Lesenswert?

Mein Reden.

von Karl H. (kbuchegg)


Lesenswert?

Juuuuuuungs.

Die _delay_ms funktionieren perfekt. Er hat ein Problem, dass sein 
Programm beim Aktivieren des Optimizers nicht mehr funktioniert. Das hat 
an sich nichts mit _delay_ms zu tun. Damit _delay_ms korrekte Zeiten 
liefert, müsste er den Optimizer aktivieren. Tut er das, geht der Rest 
nicht mehr. Und da bin ich nun mal der Ansicht, dass den Optimizer 
weglassen nicht die Lösung sein kann. Die Lösung muss lauten: Die 
Fehler, die er bisher übersehen hat, zu korrigieren. Dann kann sie der 
Optmimizer auch nicht gegen ihn ausnutzen.


Ja, es gibt die Fälle, dass man _delay_ms einsetzen kann. Trotzdem sind 
90% aller Fälle, in denen hier von Anfängern mit _delay_ms gearbeitet 
wird, nicht in dieser Kategorie. Zufrieden? Hier im Forum ist _delay_ms 
sehr oft das Design-Problem und nicht die Design-Lösung.

von Nn N. (jaytharevo)


Lesenswert?

Hehe, Karl Heinz und sein Riecher :D!

Danke mal für eure Anregungen.
Also es geht hier definitiv um _delay_us und nicht ms!
Im Bereich von 80 - 250 us. Und zwar arbeite ich mit dem externen 
Interrupt.
Bei steigender Flanke kommt der Interrupt, danach muss ich kurz warten 
und frage dann in der ISR einen PIN ab ob der high oder low ist. Warten 
muss ich da es eine kurze Zeit dauert bis sich ein ev. high bzw. low 
einstellt.

Könnte ich dieses Abfrage auch aus der ISR auslagern. Werd ich dann whs 
auch. Aber das Warten wird wohl bleiben.


Hum, also mein Code hat Fehler und deswegen hat der Optimizer mir da 
reingepfuscht? Na dann schau ich gleich mal :)!

Thx so far!

von Karl H. (kbuchegg)


Lesenswert?

Julian Schild schrieb:
> Hehe, Karl Heinz und sein Riecher :D!
>
> Danke mal für eure Anregungen.
> Also es geht hier definitiv um _delay_us und nicht ms!

_delay_us hört sich schon wesentlich besser an.


> Hum, also mein Code hat Fehler und deswegen hat der Optimizer mir da
> reingepfuscht? Na dann schau ich gleich mal :)!

Höchst wahrscheinlich.
Überprüf mal, ob alle volatile da sind, wo sie sein müssen. Das ist der 
häufigste Fehler.

von Ich sag nur: 2.Posting (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Schuss ins Blaue: vergessene 'volatile' bei den Kommunikationsvariablen
> der ISR mit dem Rest des Programms.

So ins Blaue ist das gar nicht geschossen. Wenn ISRs mit Optimierung 
nicht mehr richtig mit dem Programm zusammenarbeiten, ist das in 99% der 
Fälle richtige Zauberwort.

von Karl H. (kbuchegg)


Lesenswert?

Ich sag nur: 2.Posting schrieb:
> Karl Heinz Buchegger schrieb:
>> Schuss ins Blaue: vergessene 'volatile' bei den Kommunikationsvariablen
>> der ISR mit dem Rest des Programms.
>
> So ins Blaue ist das gar nicht geschossen.

:-)
Ohne den Code gesehen zu haben schon.

von Nn N. (jaytharevo)


Lesenswert?

Alle meine Globalen Variablen sind volatile.

Karl Heinz Buchegger schrieb:
> _delay_us hört sich schon wesentlich besser an.

Schön :)! Werd es aber whs trotzdem auslagern!

von Nn N. (jaytharevo)


Angehängte Dateien:

Lesenswert?

Leider find ich keinen Fehler.
Ich habe bis heute diese Volatile noch nicht richtig verstanden. Obwohl 
ich es mir schon einige Male angeschaut habe. Vllt findet hier wer einen 
Fehler :)!

von ... (Gast)


Lesenswert?

Compilen tut Dein Code schon mal ohne Fehler/Warnungen (bei -Os)
Ein volatile fehlt trotzdem noch, sonst geht Deine Statemachine unter 
Umständen nicht.

Das hier:
1
  if (Minute == 59)
2
  {
3
    Hour++;
4
    Minute = 0;
5
  }
wäre im INT0_vect direkt nach dem "Minute++;" besser aufgehoben, dann 
aber auch mit dem korrekten Vergleichswert bzw -operator. Eine Stunde 
hat nun mal 60 Minuten und nicht 59.
Diese Zeile:
1
PORTB ^= ~(1<<PB4);
sieht auch sehr merkwürdig aus. Willst Du da wirklich irgendwelche 
PullUps togglen und Deine PWM durcheinander bringen?
Diese Zeile:
1
DDRD &= ~((1<<PB6) | (1<<PB7));
ist auch daneben. Ist nun Port B oder D gemmeint? Auch die nachfolgenden 
Zeilen solltest Du Dir dringenst nochmal anschauen. Zwei Ausgänge 
gegeneinander arbeiten zu lassen ist meistens keine gute Idee.

Wie groß kann denn Dein "Tick_P_el" werden? Bekommst Du da eventuell 
Probleme mit signed/unsigned Konvertierungen und Überläufen?

Ansonsten: Läuft Dein AVR tatsächlich mit den angegeben internen 8MHz? 
Hast Du die Fuses dafür auch richtig geändert?

von Nn N. (jaytharevo)


Lesenswert?

Hallo!

Erst mal vielen Danke für deine Hilfe :)!


... schrieb:
> Ein volatile fehlt trotzdem noch, sonst geht Deine Statemachine unter
> Umständen nicht.

Wo denn?

... schrieb:
> Eine Stunde
> hat nun mal 60 Minuten und nicht 59.

Hehe, schon klar :). Aber ist meine Überlegung falch, dass hier die 0. 
Minute ebenfalls als eine zählt? Somit wären ich mit der 59. insgesamt 
auf 60 Minuten. Dadurch, dass sich diese Abfrage vor den cases befindet 
ist es doch ok oder? Wird jedes mal durchlaufen, oder ist genau, dass 
das Problem :D?

... schrieb:
> sieht auch sehr merkwürdig aus. Willst Du da wirklich irgendwelche
> PullUps togglen und Deine PWM durcheinander bringen?

Sry, hab ich vergessen zu dokumentieren. Das ist eine LED die ich da 
toggle. Ist ein überbleibsel aus dem Debugging. Kann also raus :)! 
Bringt, dass meine PWM wirklich durcheinander? Denn die funktioniert 
(Ansteuerung des Servos) zum Glück problemlos :D!

1
DDRD &= ~((1<<PB6) | (1<<PB7)); // PB6 & PB7 are Input for Servo Reverse
2
DDRD = 0xFF;                       // All Output
Hast du recht, das negiert sich wohl :D! Also gehören die PB6 & PB7 also 
als Output. Hier wird lediglich abgefragt ob High oder Low Pegel 
vorhanden sind. Je nach dem wird die eine oder andere Rechnung 
ausgeführt.
Und PD4, hier wird ebenfalls ein Port abgefragt ist dann auch Falsch.

Jetzt schauts so aus:
1
DDRB |= (1<<PB1) | (1<<PB2)| (1<<PB3) | (1<<PB4);   // Set PB1 & PB2 as Output for PWM Channels// PB3 and PB4 LEDs for testing
2
DDRD = 0xFF;                     // All Output
3
DDRD &= ~((1<<PD2) | (1<<PD3));  // PortD, two Input, Externer Interrupt 1 & 0 @ PD3
4
DDRC = 0xFF;                     // PortC, all Output

... schrieb:
> ist auch daneben. Ist nun Port B oder D gemmeint? Auch die nachfolgenden
> Zeilen solltest Du Dir dringenst nochmal anschauen.

Done. Siehe oben :)!

... schrieb:
> Zwei Ausgänge gegeneinander arbeiten zu lassen ist meistens keine gute Idee.

Was meinst damit?

... schrieb:
> Wie groß kann denn Dein "Tick_P_el" werden? Bekommst Du da eventuell
> Probleme mit signed/unsigned Konvertierungen und Überläufen?

Max. Frequenz ist 4kHz. Das für 50 Sekunden (so lange wird gemessen) 
wäre ein max. von 200.000. Da, dass 4 Byte Integer sind hab ich da vor 
einem Überlauf keine Angst, muss ich ehrlich gestehen :)!

... schrieb:
> Ansonsten: Läuft Dein AVR tatsächlich mit den angegeben internen 8MHz?
> Hast Du die Fuses dafür auch richtig geändert?
1
OSCCAL = 0x54;
Ich habe probiert es so gut wie möglich zu kalibrieren.
Die Fuse CKDIV8 ist def. nicht aktiviert. Also sollten die 8MHz 
anliegen.

Danke noch mal für deine Hilfe.

MfG

PS: Hier noch ein Bild zur Verdeutlichung :)!
http://www.pic-upload.de/view-10677658/Pinbelegung_ATMEGA88PA_Wattmeter_v1.4.jpg.html

von ... (Gast)


Lesenswert?

Julian Schild schrieb:
>> Ein volatile fehlt trotzdem noch, sonst geht Deine Statemachine unter
>> Umständen nicht.
>
> Wo denn?
Deine 'State' Variable:
1
volatile enum state_t State = Wait;

>> Eine Stunde
>> hat nun mal 60 Minuten und nicht 59.
> Hehe, schon klar :). Aber ist meine Überlegung falch, dass hier die 0.
> Minute ebenfalls als eine zählt?
Nein, völlig korrekt
> Somit wären ich mit der 59. insgesamt auf 60 Minuten.
Richtig.
> Dadurch, dass sich diese Abfrage vor den cases befindet ist es doch ok oder?
> Wird jedes mal durchlaufen, oder ist genau, dass das Problem :D?
Das nicht. Aber Du zählst nur von 0 bis 58! Sowie Deine Minute auf 59 
umspringt, setzt Du sie wieder auf 0, d.h. Deine Minute 59 (also die 
60ste) existiert praktisch nicht. Also entweder:
1
if (Minute > 59)
oder:
1
if (Minute == 60)

>> sieht auch sehr merkwürdig aus. Willst Du da wirklich irgendwelche
>> PullUps togglen und Deine PWM durcheinander bringen?
> Sry, hab ich vergessen zu dokumentieren. Das ist eine LED die ich da
> toggle. Ist ein überbleibsel aus dem Debugging. Kann also raus :)!
> Bringt, dass meine PWM wirklich durcheinander? Denn die funktioniert
> (Ansteuerung des Servos) zum Glück problemlos :D!
Hab mir schon gedacht, das Du da eigentlich eine LED an PB4 togglen 
willst. Nur tust Du genau das nicht, Du togglest alle anderen Bits in 
PORTB! Darunter halt Deine PWM Outputs (PB1 & PB2), Deine LED an PB3, 
den nicht benutzten PB0 und bei den als Input konfigurierten Pins 
(PB6/PB7) halt die PullUps.
Sieh Dir die Zeile nochmal genau an, Du wolltest wahrscheinlich sowas:
1
PORTB ^= (1<<PB4);
Siehst Du den Unterschied (Hint: ~ )? Im derzeit auskommentierten Teil 
von INT1_vect hast Du es mit PB3 richtig gamacht.

> Jetzt schauts so aus:
> ...
Schon besser (DDRB), aber immer noch problematisch (DDRD) ...
>> Zwei Ausgänge gegeneinander arbeiten zu lassen ist meistens keine gute Idee.
> Was meinst damit?
Du schaltest erst den kompletten Port D als Ausgang. Bis Du direkt 
danach die Pins 2,3 und 4 wieder auf Eingang umkonfigurierst, arbeiten 
die Ausgangstreiber Deines AVR unter Umständen gegen die Ausgangstreiber 
der an diese Pins angeschlossenen Peripherie. Nicht umsonst sind die 
Pins am AVR als default Inputs. Besser z.B. so:
1
DDRB = (1<<PB1) | (1<<PB2)| (1<<PB3) | (1<<PB4);  // PB1 & PB2 as Output for PWM Channels; PB3 and PB4 LEDs for testing; keep all others Inputs
2
DDRD = ~((1<<PD2) | (1<<PD3));  // keep PD2 & PD3 as Input for external Interrupts; all others as Output
3
DDRC = 0xFF;                    // all as Output

>> Wie groß kann denn Dein "Tick_P_el" werden? Bekommst Du da eventuell
>> Probleme mit signed/unsigned Konvertierungen und Überläufen?
> Max. Frequenz ist 4kHz. Das für 50 Sekunden (so lange wird gemessen)
> wäre ein max. von 200.000. Da, dass 4 Byte Integer sind hab ich da vor
> einem Überlauf keine Angst, muss ich ehrlich gestehen :)!
Ok, das mag passen. Hab jetzt nicht im einzelnen nachgerechnet.

>> Hast Du die Fuses dafür auch richtig geändert?
> Die Fuse CKDIV8
Genau die meinte ich, das sollte also auch passen.

PS: Was mir grad noch auffällt:
1
  if (Hour <= 4 || Hour >= 21) State = Turn_off;
2
// ...
3
case Turn_off:  // System should be turned off between 10pm and 5am
4
  if (Hour <= 4 || Hour >= 21)
5
// ...
Da passt auch was nicht. Du schaltest das Teil zwischen 21 und 5 aus und 
nicht wie im Kommentar angegeben zwischen 22 und 5.

Ein weiteres Problem dürfte sein, daß Du aus dem SLEEP_MODE_PWR_DOWN im 
'Turn_off' State nicht mehr rauskommst. Deine edge-triggered external 
Interrupts funktionieren dann nicht mehr (im PWR_DOWN geht nur noch 
low-level-triggered).

PPS: Darf man fragen, was da eigentllich dranhängt und gesteuert wird?

von Nn N. (jaytharevo)


Lesenswert?

Hey,
mal wieder dickes Danke, dass du dir so viel Mühe gibst.

... schrieb:
> Deine 'State' Variable:volatile enum state_t State = Wait;

Wurde geändert.

... schrieb:
> Deine Minute 59 (also die
> 60ste) existiert praktisch nicht

Jetzt hab ich es auch durchblickt :)!
Ebenfalls geändert :)!

Komisch, dass ich es hier richtig gemacht hab^^:
1
if (_20_ms == 50)
2
  {
3
   Second++;
4
   _20_ms = 0;
5
  }

... schrieb:
> Nur tust Du genau das nicht, Du togglest alle anderen Bits in
> PORTB!
Uh, da hab ich wohl den Vogel abgeschossen, komisch nur, dass trotzdem 
beide LED's geblinkt haben? Da ich die zweite LED ja richtig toggle 
müsste doch nur eine von beiden funktionieren oder und trotzdem, dass 
das toggeln von PB3 auskommentiert ist hat es funktioniert?!
Wurde geändert :)!
Wobei ich im Datenblatt grad gesehen hab, dass
1
PINB = (1 << PIN4);
auch funktionieren würden :).

... schrieb:
> Nicht umsonst sind die
> Pins am AVR als default Inputs. Besser z.B. so:

Wurde auch geändert. Ich dachte es ist nach dem Reset sind alle Register 
0^^.

... schrieb:
> Ok, das mag passen.

2^32 = 4.294.967.296. Da bin ich noch ewig weit weg mit meinen 200.000 
xD!

... schrieb:
>
1
 if (Hour <= 4 || Hour >= 22)

Sieht jetzt so aus.

... schrieb:
> Deine edge-triggered external
> Interrupts funktionieren dann nicht mehr (im PWR_DOWN geht nur noch
> low-level-triggered).

Das habe ich im Datenblatt auch gelesen. Hab dann probiert und iwie 
wurde er trotzdem aufgeweckt. kA. Egal, wird auf Idle geändert, die paar 
mA die ich da spar^^.

Noch mal zum Verständnis. Muss es anstatt:
1
PORTC &= ~((1<<PC0) | (1<<PC1));// Turn Laser off

so heißen:
1
 PORTC &= (~(1<<PC0) | ~(1<<PC1));// Turn Laser off

?

Aber iwie passt das doch nicht. Denn hier ein kleiner Auszug aus dem AVR 
GGC Tutorial:
1
  // Pin 3 und 4 auf Eingang und andere im ursprünglichen Zustand belassen:
2
  DDRB &= ~( ( 1 << DDB3 ) | ( 1<<DDB4) );

........................................................................

Was das Teil tut?
Es ist ein Projekt aus meiner alten Schule. Ein Prof. hat mich aufgrund 
meiner µC "Diplomarbeit" angesprochen. Auf einer Leitung ist eine 
Rechteckspannung mit einer bestimmten Frequenz. Diese Frequenz ist 
direkt proportional zur el. Leistung. Alle Minuten (genau) kommt eine 
Flanke an den Int0. Da synchronisiere ich dann immer meine Zeit.
Jedenfalls wird die el. Leistung dann umgerechnet in eine PWM die einen 
Servo ansteuert. Der Servo ist an einen Laser gekoppelt welcher auf 
einer Skala die momentan benötigte el. anzeigt. Ist halt so ne Art 
Umweldprojekt. Damit soll den Leuten klar gemacht werden wie viel 
Leistung so eine Schule braucht.
Auf dem Signal ist noch zusätzlich, dass der thermischen Leistung 
Aufmoduliert (ASK- Modulation). Das wird der auskommentierte Part.


Danke für deine Hilfe :)! Kann nicht glauben wie viel da falsch ist und 
es funktioniert trotzdem :D!

von ... (Gast)


Lesenswert?

Julian Schild schrieb:
> Wobei ich im Datenblatt grad gesehen hab, dass
>  PINB = (1 << PIN4);
> auch funktionieren würden :).
Ja, bei neueren AVRs gehts natürlich auch so :)

> ... schrieb:
>> Nicht umsonst sind die Pins am AVR als default Inputs.
> Ich dachte es ist nach dem Reset sind alle Register 0^^.
Fast alle, gibt einige wenige Ausnahmen (z.B. OSCCAL und MCUSR).
Aber die DDRx gehöhren nicht zu diesen Ausnahmen. Ist doch aber auch 
kein Widerspruch zu meiner Aussage. Wenn DDRx == 0 sind doch alle Pins 
Inputs.

>> Ok, das mag passen.
> 2^32 = 4.294.967.296. Da bin ich noch ewig weit weg mit meinen 200.000
Ja, ich habs nicht im einzelnen nachgerechnet. Bin nur drüber 
gestolpert, das Du erst von uint32 nach int32 castest und zum Schluß 
dann noch nach uint16. Da muß man halt aufpassen, daß man da nicht 
irgendwann mal ein paar Stellen oder das Vorzeichen verliert. Soweit ich 
das auf die Schnelle überblicke, sollte das aber bei Dir kein Problem 
sein. Du wirst schon wissen was Du da tust :)

> Noch mal zum Verständnis. Muss es anstatt:
>  PORTC &= ~((1<<PC0) | (1<<PC1));// Turn Laser off
> so heißen:
>  PORTC &= (~(1<<PC0) | ~(1<<PC1));// Turn Laser off
> ?
Nein! Die erste Variante ist schon richtig. Oder halt so, wenn man 
unbedingt zuerst negieren will:
1
PORTC &= ~(1<<PC0) & ~(1<<PC1);// Turn Laser off
Nimm Dir am besten Papier und Stift und spiel selber µC.
1
  ~((1<<PC0) | (1<<PC1))
2
= ~((0b00000001 << 0) | (0b00000001 << 1))
3
= ~(0b00000001 | 0b00000010)
4
= ~0b00000011
5
=  0b11111100
6
7
  ~(1<<PC0) | ~(1<<PC1)
8
= ~(0b00000001 << 0) | ~(0b00000001 << 1)
9
= ~0b00000001 | ~0b00000010
10
=  0b11111110 |  0b11111101
11
=  0b11111111
12
13
  ~(1<<PC0) & ~(1<<PC1)
14
= ~(0b00000001 << 0) & ~(0b00000001 << 1)
15
= ~0b00000001 & ~0b00000010
16
=  0b11111110 &  0b11111101
17
=  0b11111100
Und dann siehst Du auch, daß die Stelle im Tut schon so richtig ist. 
DDB3  und DDB4 werden halt auf 0 gesetzt und die restlichen Bits bleiben 
unberührt.

> Was das Teil tut?
> ...
Ah, ein Lichtzeiger http://de.wikipedia.org/wiki/Lichtzeiger
Jetzt wird mir einiges klarer. Nettes Projekt und Danke für die 
Erklärung.

> Danke für deine Hilfe :)!
Keine Ursache.
> Kann nicht glauben wie viel da falsch ist und es funktioniert trotzdem :D!
Naja, so schlimm wars nun auch wieder nicht ;)
Wünsch Dir jedenfalls noch viel Erfolg für den Rest.

von ... (Gast)


Lesenswert?

Mir ist grad in dem auskommentierten Teil nochwas aufgefallen:
1
if(Lock) 
2
{
3
  Tick_P_th++;
4
  Lock = True;
5
}
Das kann so nicht gehen. Lock wird niemals True und Tick_P_th bleibt 
immer 0. Sollte wohl eher "if(!Lock)" heißen.

Warum fragst Du eigentlich PIND4 im INT1_vect mit ab, sind die Impulse 
an PIND3 und PIND4 irgenwie voneinder abhängig? Kannst Du PIND4 nicht 
einfach mittels Pinchangeinterrupt zählen?

von Nn N. (jaytharevo)


Angehängte Dateien:

Lesenswert?

... schrieb:
> Nein! Die erste Variante ist schon richtig. Oder halt so, wenn man
> unbedingt zuerst negieren will:

Dann versteh ich nicht ganz was jetzt nicht gepasst hat :D. Bin 
verwirrt^^.

... schrieb:
> Sollte wohl eher "if(!Lock)" heißen.

Jop, ist wie gesagt noch nicht fertig. Hast aber natürlich recht :)!
Wurde angepasst ;)!

... schrieb:
> Warum fragst Du eigentlich PIND4 im INT1_vect mit ab, sind die Impulse
> an PIND3 und PIND4 irgenwie voneinder abhängig? Kannst Du PIND4 nicht
> einfach mittels Pinchangeinterrupt zählen?

Könnte ich schon. Nur will ich den Controller etwas entlasten wenn es 
"einfacher" auch geht. Sollte nämlich wirklich eine max. Frequenz von 
4kHz herschen, dann muss der eine Interrupt mit 4kHz zurecht kommen und 
der andere mit 8kHz (Wegen Pinchange, jede Änderung löst nen Interrupt 
aus). Die folgen aber unmittelbar auf einander. Ich hab da schnell ein 
Bild dazu gekrizelt wie es sich verhält.
Das hängt nämlich mit der ASK- Modulation zusammen.
So lange die Amplitude nicht einen bestimmten Wert erreicht (weiß nicht 
genau z.B.: >3V) ist das Signal an PD4 low. Ist es darüber sehe ich an 
PD4 ein high. Da die Hardware aber eine gewisse Zeit braucht damit an 
PD4 das Signal auch High wird (da die erste Flanke ja eine gewisse Zeit 
braucht um die Schwelle zu überschreiten und dann fängt erst das andere 
(PD4) Signal an zu steigen) brauche ich diese _delay Funktion. Ich hoffe 
ich hab, dass ordentlich rüber gebracht. Frag bitte nach falls etwas 
unklar sein sollte.
Ich hab dazu noch ein Bild gekrizelt :D!

von ... (Gast)


Lesenswert?

Julian Schild schrieb:
>> Nein! Die erste Variante ist schon richtig. Oder halt so, wenn man
>> unbedingt zuerst negieren will:
> Dann versteh ich nicht ganz was jetzt nicht gepasst hat :D. Bin
> verwirrt^^.
Bei Deiner zweiten Variante steht ein ODER '|' in der Mitte. Das muß 
aber ein UND '&' sein.
Schau mal hier rein:
http://de.wikipedia.org/wiki/Boolesche_Algebra
Insbesondere die De Morgan’schen Gesetze:
http://de.wikipedia.org/wiki/De_Morgansche_Gesetze

> Könnte ich schon. Nur will ich den Controller etwas entlasten wenn es
> "einfacher" auch geht.
Aber nicht indem Du ihn sinnlos im Kreis springen läßt :)
Und "einfacher" sind delays definitiv auch nicht. Ganz im Genteil, Du 
handelst Dir damit mehr Probleme ein als Dir lieb sein kann.
Mach Dir mal keine Sorgen wegen der Performance, wenn ich mich nicht 
verrechnet hab braucht der INT1_vect so wie er im Moment ist um die 10µs 
bei 8MHz F_CPU, die Impulse kommen bei 4kHz alle 250µs. Dein µC 
langweilt sich also mehr oder weniger zu Tode.
Und eine kleine Optimierung wäre sogar auch noch möglich:
1
ISR(INT1_vect)  // ISR for Pulse counting
2
{
3
  uint8_t s = Second;
4
  if(s >= 4 && s <=54)  Tick_P_el++;  // Add pulses
5
}
Spart nochmal 3 Cycles :)

Hab grad noch eine Idee. Timer/Counter 0 hast Du ja auch noch frei. Wenn 
Du das Signal statt an PD4 an PB0 legen würdest, könntest Du auch die 
Hardware für Dich zählen lassen. Brauchst zwar immer noch einen 
Interrupt für die Überläufe, der käme aber wesentlich seltener.

von Nn N. (jaytharevo)


Lesenswert?

... schrieb:
> Bei Deiner zweiten Variante steht ein ODER '|' in der Mitte. Das muß
> aber ein UND '&' sein.

Nur um das zu klären. Könntest du mir die Zeile zeigen um die es geht. 
Denn ich finde sie nicht. Zumindest keine wo in der Mitte ein | steht.

... schrieb:
> Dein µC
> langweilt sich also mehr oder weniger zu Tode.

Das schon. Nur wenn du das erste Bild noch mal anschaust, dann kanns 
schon mal sein, dass er in Schwierigkeiten kommt, da der 2 Interrupt 
unmittelbar nach dem ersten kommen kann. Aber whs is es eh besser einen 
eigenen Interrupt dafür zu gestalten. Aber wie sollte ich es zählen?


Also damit es so rauskommt wie im 2. Bild.
Im PCI (Pin Change Interrupt) einfach eine Variable setzen und diese 
dann im INT1 wieder zurück setzen. Und schauen ob sie gesetzt wurde. 
Wenn nicht, dann kann ich ja eins weiter Zählen. Aber mir fallen immer 
nur so umständliche Lösungen ein...

So was wie:
1
INT0 ()
2
{
3
 Tick_el++;
4
 if(Var2) if(!Var1) Tick_th++;
5
 Var2=False;
6
 Var1=False; 
7
}
8
9
PCI ISR()
10
{
11
 Var1=True;
12
 Var2=True
13
}

Aber ich mein, dass is doch ungeheuer kompliziert und der erste 
Interrupt würde länger werden....

von ... (Gast)


Lesenswert?

Julian Schild schrieb:
> ... schrieb:
>> Bei Deiner zweiten Variante steht ein ODER '|' in der Mitte. Das muß
>> aber ein UND '&' sein.
>
> Nur um das zu klären. Könntest du mir die Zeile zeigen um die es geht.
> Denn ich finde sie nicht. Zumindest keine wo in der Mitte ein | steht.

Es ging nicht um Deinen Code, sondern um diesen Post:
Beitrag "Re: Problem mit delay.h und Optimierungsstufe v. AVR Studio 4"
Und da speziell um das hier:
> Noch mal zum Verständnis. Muss es anstatt:
>  PORTC &= ~((1<<PC0) | (1<<PC1));// Turn Laser off
> so heißen:
>  PORTC &= (~(1<<PC0) | ~(1<<PC1));// Turn Laser off
Und da steht in der zweite Variante ein '|' statt einem '&'.

Julian Schild schrieb:
> Das schon. Nur wenn du das erste Bild noch mal anschaust, dann kanns
> schon mal sein, dass er in Schwierigkeiten kommt, da der 2 Interrupt
> unmittelbar nach dem ersten kommen kann.
Warum sollte er? Der erste Interrupt ist nach ca 10µs schon komplett 
abgearbeitet. Selbst wenn der Impuls an PD4 innerhalb dieser Zeit kommt 
heißt das ja nicht, daß der Interrupt dafür verlorengeht. Die 
Interruptroutine wird einfach nur ein paar µs später aufgerufen, halt 
dann wenn die erste fertig ist.
Probleme bekommst Du erst, wenn innerhalb der 10µs die der INT0 braucht, 
am PD4 zwei oder mehr Flankenwechsel auftreten würden. Dafür müßtest Du 
Deine Impulsfrequenzen aber schon mehr als verzehnfachen.

Julian Schild schrieb:
> So was wie:
> ... <code snipped>
Warum willst Du die Zählerei der th-Impulse unbedingt im INT0 Interrupt 
mit machen? Geht nicht einfach sowas?
1
INT0 ()
2
{
3
 Tick_el++;
4
}
5
6
PCI ISR()
7
{
8
 Tick_th++;
9
}
Ok, Tick_th ist dann um den Faktor 2 zu groß, aber das kannst Du ja 
problemlos bei der nachfolgenden Rechnerei mit berücksichtigen.

Irgendwie scheine ich da immer noch auf dem Schlauch zu stehen. Schreib 
doch mal in Bezug auf Dein zweites Bild, was Du da am Ende für Werte in 
Tick_el und Tick_th erwarten würdest. Ich zähle da Tick_el==18 und 
Tick_th==2.

von Nn N. (jaytharevo)


Lesenswert?

... schrieb:
> Warum sollte er? Der erste Interrupt ist nach ca 10µs schon komplett
> abgearbeitet. Selbst wenn der Impuls an PD4 innerhalb dieser Zeit kommt
> heißt das ja nicht, daß der Interrupt dafür verlorengeht.

Achso? Ich dachte immer, dass so lange ein Interrupt aktiv ist andere 
gesperrt sind. Ich wusste nicht, dass es so etwas wie eine 
"Warteschleife" gibt.

... schrieb:
> Irgendwie scheine ich da immer noch auf dem Schlauch zu stehen.

Hehe. Ein wenig vielleicht, mal schauen, ich erkläre es noch mal :)!
Also, das Bild2 sollte eigentlich nur schematisch die ASK- Modulation 
darstellen! Dh. ich muss nur wissen wann das erste Mal Tick_el und 
Tick_th gemeinsam high sind. Das stellt, dann die erste High Flanke dar. 
Wenn dann nur mehr Tick_el high ist, ist Tick_th low, aber bis dort hin 
ist es high, durchgehend, also wird bis dort hin nur ein mal Tick_th 
hoch gezählt! Nun wo nur Tick_el high ist warte ich wieder so lange bis 
Tick_el und Tick_th gemeinsam high sind um Tick_th wieder um EINS 
weiter zu zählen. Das hast du nach deinem Ergebnis nach zu urteilen eh 
verstanden. Aber zwischen diesen beiden Ergebnissen gibt es keinen fixen 
Faktor. Also weder Tick_el noch Tick_th sind statisch.
Was jetzt auch noch wichtig ist:
Wenn Tick_el und Tick_th high sind sieht es aus wie auf dem ersten Bild!
Dh also, dass für die Dauer des ersten High für Tick_th der INT1 
Interrupt 5 mal kommen würde und der PCINT 10 mal.
Um es noch ein Mal anders zu formulieren. Ich zähle Tick_th erst hoch 
wenn PCINT und INT1 zum ersten mal "gleichzeitig" high sind. Danach muss 
ich warten bis nur mehr INT1 kommt. Dann darf ich wieder weiterzählen 
wenn PCINT und INT1 "gleichzeitig" high sind (Bild1). Dh ich muss einen 
Weg finden um diese "Gleichzeitigkeit" nur ein mal zu zählen.
Ich hoffe ich hab dich jetzt nicht zu sehr verwirrt :(!

Danke, dass du dich bis jetzt noch nicht ausgeklinkt hast :)!!!!

MfG

von Nn N. (jaytharevo)


Angehängte Dateien:

Lesenswert?

PS:
Ich hab noch ein anderes Bild zur ASK- Modulation gefunden.
Der logische Pegel der Daten ändert sich nur bei einer signifikanten 
Änderung im Pegel!

MfG

von Nn N. (jaytharevo)


Lesenswert?

Hab ich dich so verwirrt? :(

von Nn N. (jaytharevo)


Angehängte Dateien:

Lesenswert?

Falls es noch jemanden interessiert.
1
ISR(INT1_vect)  // ISR for Pulse counting
2
{
3
 uint8_t s = Second;
4
 if(s >= 4 && s <=54)  Tick_P_el++;  // Add pulses
5
6
 if(!Lock1) 
7
 {
8
   if(Lock2)
9
   {
10
    Tick_P_th++;
11
    Lock2 = False;
12
   }
13
14
  Lock1 = True;
15
 }
16
 else Lock2 = True;
17
}
18
19
20
ISR(PCINT2_vect)
21
{
22
 Lock1=False;
23
}

So hab ich es jetzt gelöst. Aber wahrscheinlich gibts bei hoher Frequenz 
sicher ein Problem damit, so dass der erste PCINT geblocked wird. Aber 
dadurch, dass er bei der negativen Flanke erneut ausgeführt wird sollte 
es zum Glück keine Probleme geben :)!


MfG

ps: Hab auch das fertige Programm noch mal angehängt :)!

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.