Ok. Ich weiss ich bin jetzt besoffen und das ist auch gut so, darum mag
man mir die Tippfehler verzeihen. Ich bastle seit Wochen an meinem Board
rum um den CAN128 in den Schlaf zu versetzen, was mich inzwischen 3 oder
mehr Wochenenden gekostet hat.
Das Ziel: Die CPU soll schlafen und sich aus einer kleinen Knopfzelle
nähren wenn an PINE,PE7 ein Lowlevel anliegt und soll aus dem Schlaf
zurückkehren, wenn PINE,PE7 wieder Spannung hat (High - Level),
Natürlich soll dan noch immer die Uhrzeit stimmen. Es ist ein 32?Xde
irgendwas am Port und das ASSR Register ist entsprechend eingestellt.
// Oszillatoren einstellen
setbit(ASSR,AS2); // 2. Oszillator für TOSC
aktivieren
// Clocktimer aktivieren
TCCR2A = 0x05; // Prescaler Timer 2 = 128, extern
32kHz Clock
setbit(TIMSK2,OCIE2A); // Interrupt enable Timer 2
while(checkbit(ASSR,TCN2UB) || checkbit(ASSR,OCR2UB) ||
checkbit(ASSR,TCR2UB)) asm("NOP");
und ausgewertet wird auch ganz artig
SIGNAL(SIG_OUTPUT_COMPARE2)
{
setbit(GPIOR2,GPIOR01); // Sekundenbit
}
wird gesetzt und die Uhrroutine arbeitet es ab, wenn Zeit dafür ist.
Ich habe zig Anleitungen und natürlich das vermaledeite Handbuch des CAN
128 gelesen, den Befehl asm(sleep) habe ich natürlich nirgendwo
gefunden sondern bin in dem Programmbeispiel des Butterfly darüber
gestolpert.
Da der Stromverbrauch im Sleep-Modus noch immer bei 10 - 12 mA lag hatte
ich schon die Hardware in Verdacht... Heute dann die Ernüchterung.
Bei einem Codeschnipsel, der etwa diesem hier
clearbit(EIMSK,INT7);
cli();
SMCR = 0x0c;
sleep_enable();
sei();
sleep_cpu();
while(!checkbit(PINE,PE7)) {totzeitx++; asm volatile ("sleep");}
sleep_disable();
sei();
ähnlich gewesen sein könnte war totzeitx nach 3 Sekunden bei einer
5stelligen Zahl. Es sollte dieses räudige 64beinige Mistvieh doch
schlafen?! und nur jede Sekunde erwachen, wenn
SIGNAL(SIG_OUTPUT_COMPARE2) klingelt. Wie kann es sich da in 3 Sekunden
auf 27?x? hochschrauben?
Ergo. Die Sau schläft nicht. Ich bin mir nicht sicher ob ich überhaupt
noch wissen will, warum das elende Mistvieh nicht schläft, aber
vieleicht hat jemand eine Routine für mich wie ich den Hund zum schlafen
bringe.
Prosit!
ceberus wrote:
> Ergo. Die Sau schläft nicht.
Ja, der Powerdown Mode ist ziemlich tückisch.
Man muß eine bestimmte Abfolge einhalten und besonders auf die
Interrupts achten.
Die WINAVR-Funktionen tragen auch das ihre zur Verwirrung bei, da sie
nicht interruptfest sind.
Da steht zwar im "sleep.h" schön versteckt wichtiger Text, aber wer
liest das schon so gründlich.
Am besten fährt man, wenn man sie daher nicht benutzt und alles selber
macht.
Hier mal ein funktionierendes Beispiel auf nem ATtiny45:
http://www.mikrocontroller.net/attachment/33635/SLEEP.C
Peter
Ach Peter, es ist ja nicht so, dass ich Deine Hilfen und Erklärungen
nicht zu schätzen wüsste, auch wenn ich mir dabie immer vorkomme wie
Alice im Wunderland.
Das Beispiel sieht ja auch schick aus, aber ???
Wie und wann kommt Dein Tiny aus der For-Schleife am Ende wieder raus?
Und wo lässt man die Uhr?
Und wo ist jetzt eigentlich der elementare Fehler in meinem
Geschriebsel? Macht es einen Unterscheid, ob ich das Register so SMCR =
0x0c; oder MCUCR = 1<<SE^1<<SM1; beschreibe? wenn die 0 gesetzten Bits
ohnehin nicht belegt sind?
ceberus wrote:
> Wie und wann kommt Dein Tiny aus der For-Schleife am Ende wieder raus?
Garnicht, das ist die Mainloop, da kommt nie ein MC raus.
Sie ist hier leer (außer dem Sleep), aber das ist ja nur ein
Grundgerüst.
> Und wo lässt man die Uhr?
Im T2-Interrupt oder in der Mainloop.
Ganz wo Du willst.
> Und wo ist jetzt eigentlich der elementare Fehler in meinem> Geschriebsel?
Daß es nur zusammenhanglose Codefetzen sind.
> Macht es einen Unterscheid, ob ich das Register so SMCR => 0x0c; oder MCUCR = 1<<SE^1<<SM1; beschreibe?
Ja, das letzte ist lesbarer.
Das Beispiel soll zeigen, daß es am sinnvollsten ist, die entsprechenden
Sleepmodi in nem Interrupt zu setzen.
Dann muß das Main nur noch das eigentliche Sleep machen, wenn es alle
Tasks fertig hat.
Wichtig ist, nur das nackte SLEEP, nicht das sleep_mode !!!
Es ergibt IMHO keinerlei Sinn, das Sleepenable separat von den
Sleepmodis zu setzen. Entweder man will schlafen oder nicht.
Damit gibt es keine Konflikte mehr.
Peter
Nun ja, ich hatte mir die Sache aus dem sleep.h zusammengeklaubt.
Geholfen hat es nix. Warum das Sleep_enable immer separat gesetzt wurde,
kann ich auch nicht sagen, ich habe es überall so gefunden und weil es
bei mir nicht wirklich funktionierte, wenn ich es gleich mit geschrieben
habe, habe ich es eben mal so herum probiert. Sleep im Interrupt, sleep
ohne interrupt, sleep in der Endlosschleife, ... langsam gehen mir die
Ideen aus... Vermutlich muss ich es noch einmal ganz von Vorne anfangen
und die komplette Software um das Sleep-Modul herumschreiben ...
cerberus wrote:
> Vermutlich muss ich es noch einmal ganz von Vorne anfangen> und die komplette Software um das Sleep-Modul herumschreiben ...
Eigentlich nicht.
Man sollte erst die Funktionalität fertig stellen und das Sleep ganz zum
Schluß dazubasteln.
Dazu braucht es nur eine Stelle im Main, wo man denkt, grad nichts mehr
zu tun zu haben und dann das Sleep dahin setzen.
Das Sleep Mode einstellen machen dann die Interrupts oder das Main unter
Interruptsperre.
Die Mainloop darf natürlich keine Delayschleifen enthalten, das würde ja
einem Sleep zuwider laufen.
Also immer schön in Sleep gehen und Timerinterrupts aufsetzen für die
Delays.
Peter
Ich komme aus der SPS-Programmierung ;-) bei mir gibt es keine delays
;-), wird alles über Merker gesteuert.
Das sleep in der Main-schleife und die Initialisierung in der ISR hatte
ich gestern auch schon, hat aber auch nicht geholfen ...
Ich muss noch mal schauen, was passiert, wenn ich vorher alle Interrupts
kille, bevor ich den Kollegen schlafen lege. Irgend wo da war ich
gestern nicht mehr aufnahmefähig ... Ich weiss, dass er dann nicht mehr
aufwacht, gerade das will ich ja wissen, oder ob er dann einfach
sang-und Klanglos weitermacht.
Was denkst zu zu einem Main in der Form
int main( void )
{
// Initialisierung und vorgeplänkel
while(1)
{
if(!checkbit(PINE,PE7))
{
totzeitx++;
asm volatile ("sleep");
}
else
{
// Hauptprogramm
}
}