Hallo Zusammen,
ich habe hier ein kleines Problem. Schon im letzten Jahr habe ich aus
Corona Langeweile angefangen, fürs Bobbycar von meinem Sohn ein
Blaulicht/Martinshorn auf Basis des Tiny 861 zu bauen. Die LEDs für die
Blitzer werden mit PWM angesteuert, wofür ich einen Soft-PWM Schnipsel
eingebaut habe:
1
ISR(TIMER0_COMPA_vect){
2
staticuint8_tpwm_cnt=0;
3
uint8_ttmp=0;
4
uint8_tbuffer=PWM_PORT;
5
6
OCR0A+=(uint16_t)T_PWM;
7
8
if(pwm_setting[0]>pwm_cnt)tmp|=(1<<1);
9
if(pwm_setting[1]>pwm_cnt)tmp|=(1<<2);
10
11
buffer&=~(1<<1);
12
buffer&=~(1<<2);
13
buffer|=(tmp);
14
15
PWM_PORT=(buffer);// PWMs aktualisieren
16
17
18
if(pwm_cnt==(uint8_t)(PWM_STEPS-1))
19
pwm_cnt=0;
20
else
21
pwm_cnt++;
22
}
Das funktioniert soweit alles prima. Nun habe ich einen Schleifenzähler,
der nach etwa einer Minute ohne irgendeinen Tastendruck alles
ausschaltet, und den µC in den Tiefschlaf schickt:
1
if(sleep_counter>sleep)
2
{
3
pwm_setting[0]=0;
4
pwm_setting[1]=0;
5
horn1_state=0;
6
horn2_state=0;
7
flash_state=0;
8
horn_tone_counter=0;
9
horn_duration_counter=0;
10
seq_cnt=0;
11
12
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
13
sleep_mode();
14
sleep_counter=0;
15
}
16
17
sleep_counter++;
18
}
Auch das funktioniert soweit. Ton wird abgeschaltet, µC geht verlässlich
in den Power Down (an der Stromaufnahme nachzuvollziehen) und wird beim
nächsten Tastendruck per PCINT wieder aufgeweckt.
Allerdings: Ganz ganz selten, wenn der µC in den Power Down geht, gehen
die beiden Pins für die Blitzer auf 1, d.h. alle LEDs werden (über Ihren
vorgeschalteten Mosfet) voll durchgesteuert. Zum Glück sind die
Batterien der limitierende Faktor, denn wenn die Spannung durch die
Belastung von 12 LEDs nicht zusammen brechen würde, wären die mir bei
4,5V jetzt schon ein paar mal abgebrannt. Aber warum passiert das
überhaupt? Die Ports bleiben doch im Power Down nicht geschaltet oder
etwa doch?
Gruß
Holger
Holger K. schrieb:> Aber warum passiert das> überhaupt? Die Ports bleiben doch im Power Down nicht geschaltet oder> etwa doch?
Natürlich behalten im PowerDown alle Ports ihren letzten Zustand.
PowerDown bedeutet nichts anderes als: alles wird "eingefroren" und zwar
durch Anhalten des Taktes, der all den Kram letztlich steuert.
Wenn man etwas anderes will, muss man das explizit machen, und zwar
bevor man in den PowerDown geht.
c-hater schrieb:> Natürlich behalten im PowerDown alle Ports ihren letzten Zustand.
Ok, das erklärt es dann.
> Wenn man etwas anderes will, muss man das explizit machen
Habe ich, flash_state und pwm_setting[x] auf null. Dann friert er die
wahrscheinlich ein, wenn er gerade in der Timer ISR beim kurzen
On-Zyklus des PWM ist, und just in dem Moment das Power Down greift.
Dann werde ich mal versuchen vor dem Power Down eine Sekunde zu warten.
Danke erstmal für den Tip.
Gruß
Holger
Holger K. schrieb:> Dann werde ich mal versuchen vor dem Power Down eine Sekunde zu warten.
Falscher Ansatz.
Richtig:
a) du wartest für dem PowerDown auf eine "günstige" Situation, also dass
die LEDs "gerede eben" ausgeschaltet wurden.
b) du stellst einen Zustand her, in dem die Abläufe der der Ansteuerung
egal werden. Sprich du koppelst die LED temporär von der Timer-Hardware
ab und stellst händisch den gewünschten Zustand des Pins her.
Das erfordert dann natürlich, dass beim Aufwachen wieder die
ursprüngliche Situation hergestellt wird, also Ansteuerung per
Timer-Hardware.
Ich würde eindeutig Variante b) empfehlen, auch wenn sie erstmal
deutlich mehr Arbeit macht.
Wenn dein System komplexer wird, wirst du ganz sicher irgendwann
verstehen, warum ich diese Empfehlung gebe...
Ja aber a) müsste ich ja genau damit erreichen. Denn jetzt leuchtet mir
ein: pwm_setting[x]=0 setzt zwar beide Pins zurück, aber natürlich erst
beim nächten durchlauf der ISR. Ich muss also eigentlich nur warten,
bis ein PWM Zyklus komplett durchlaufen ist.
Du bist der Jenige, der genau weiß, was der Rechner gerade macht!
Entweder Du hast eine Automatik, die sagt: Ab in die Heia!
Also eine Unterbrechung (z.B. Zeiter), oder irgendein anderes Ereignis.
Der Rechner "stolpert" ja nicht durch irgendeinen Zufall ins Bettchen.
Also ganz einfach an der Stelle die Peripherie in einen sinnvollen
Zustand bringen. Bei flüchtigen Zuständen: Diese speichern und beim
Aufwachen berücksichtigen. Der Grübler (µP) löscht ja seinen Speicher
nicht beim Sprung in ein Bett.
Der aktuelle Zustand ist vor allem dann wichtig, wenn Du via PWM an
einer H-Brücke rumspielst, oder bei ähnlichen Spielchen. Schaltest Du
eine LED an, so bleibt diese eingeschaltet und deine Energieersparnis
ist futsch.
Holger K. schrieb:> pwm_setting[x]=0 setzt zwar beide Pins zurück, aber natürlich erst> beim nächten durchlauf der ISR.
Wieso braucht man für eine blinkende LED einen Interrrupt?
Für was braucht man dazu PWM - werden mehrere gedimmt, um ein
Rundumlicht zu imitieren?
c-hater schrieb:>> Dann werde ich mal versuchen vor dem Power Down eine Sekunde zu warten.> Falscher Ansatz.
Ich bin immer wieder beeindruckt, wie unselbstständig die Leute
unterwegs sind. Ich habe eine Anwendung, wo ich einen µC in den Sleep
schicke. Ich habe garnicht darüber nachgedacht, sondern meine Ports
natürlich zuvor in einem definierten Zustand.
Sebastian S. schrieb:> Der Rechner "stolpert" ja nicht durch irgendeinen Zufall ins Bettchen.> Also ganz einfach an der Stelle die Peripherie in einen sinnvollen> Zustand bringen.
Das war zu einfach.
Zum einen verträgt die LED die volle Versorgungsspannung nicht (eingangs
erwähnt), zum anderen soll die Helligkeit später einmal analog zur
Umgebungshelligkeit gedimmt werden.
Und, ich habe darüber nachgedacht, wenn Du Dir den Codeschnipsel
zumindest mal angeschaut hättest, hättest Du vermutlich gesehen
1
pwm_setting[0]=0;
2
pwm_setting[1]=0;
3
horn1_state=0;
4
horn2_state=0;
5
flash_state=0;
6
horn_tone_counter=0;
7
horn_duration_counter=0;
8
seq_cnt=0;
Ich setzte immer so zum Spaß einen haufen Variablen zurück.
Mario M. schrieb:> Oder einfach warten, bis die LEDs aus sind.while (PWM_PORT &> (1<<1) + (1<<2));
Auch ein sehr guter Ansatz, werde ich zur Sicherheit mit einbauen. Danke
Holger K. schrieb:> Auch ein sehr guter Ansatz, werde ich zur Sicherheit mit einbauen. Danke
Nein, das ist Variante a). Führt je nach Anwendung früher oder später
in's Verderben.
Sicherlich machbar für einfache Sachen, ganz sicher für nur eine LED.
Aber wehe, es wird mal etwas komplizierter...
Dann ist die "race condition" praktisch eingebaut. Nur Idioten machen
das so, um das mal ganz deutlich zu sagen.
c-hater schrieb:> Nein, das ist Variante a). Führt je nach Anwendung früher oder später> in's Verderben.
Da haben wir aneinander vorbeigeredet. Mit "warten bis die LEDs
ausgeschaltet wurden" meinte ich, der Routiene auch die Zeit dazu zu
geben, die Anforderung sie auszuschalten auch auszuführen.
Das ganze ist so nur enstanden weil ich damals (ist ja schon über ein
Jahr her) irgendwo gelesen habe, die Ports würden im Power Down mode OC
gehen. Nachdem das Verhalten dann aber vereinzelt aufgetreten ist, habe
ich vor dem Power Down explizit die LEDs ausgeschaltet. Also dachte ich
zumindest. Ich hab schlichtweg nicht dran gedacht, dass die Variablen ja
erst in der Timer ISR ausgelesen werden.
Die Lösung von Mario M dachte ich mir nur als zweite Sicherung.
Grundsätzlich soll der Sleep Timer ja die LEDs (und Akkustik)
ausschalten, wenn die Zeit abgelaufen ist.
Holger K. schrieb:> Zum einen verträgt die LED die volle Versorgungsspannung nicht (eingangs
erwähnt),
Ach, mal wieder LEDs ohne Strombegrenzung direkt an der Batterie?
Holger K. schrieb:> Ich setzte immer so zum Spaß einen haufen Variablen zurück.
Kann es sein, dass zufällig kurz vor sleep die ISR kommt und das Licht
wieder an macht, weil sie nicht gesperrt wurde?
c-hater schrieb:> Dann ist die "race condition" praktisch eingebaut. Nur Idioten machen> das so, um das mal ganz deutlich zu sagen.
Du bist wieder so lieb, dass ich da nicht mithalten kann.