Hi
Bei meinem ersten AVR-Projekt habe ich ein kleines Problem mit dem
ATmega8 und dem Power Save Mode.
Nachdem ich den mC mittels Timer2 und Uhrenquarz aufgeweckt habe,
bekomme ich keine Variablen mehr geändert. Die Variablen sind global
deklariert und volatile, vor dem ersten Einschlafen ändert sich der Wert
auch noch, aber danach tut sich am Variablenwert nix mehr.
Wo denke ich falsch? Die Variablenwerte bleiben stumpf wo soe vor dem
ersten schlafenlegen waren.
Rene K. schrieb:> aber ich finde die Funktion> Sleep_Mode() nicht in deinem Code?!
Vorletztes Statement im Programm.
@TO: du machst den Setup "von Hand", bei mir stehen da immer mit Erfolg
die Zeilen:
1
// Power-Down Sleep Mode einstellen
2
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// stromsparend, aufwecken über WD oder INT0
3
sleep_enable();// Schlafmodus vorbereiten
und eben dann irgendwo in der Loop das "Sleep_Mode()"
Hi
Doch, ganz unten, vorletzte Anweisung. Das Schlafenlegen und Aufwachen
klappt auch, nur Variablen kann ich nach dem ersten Schlaf nicht mehr
verändern.
Gruß, Frank
HildeK, ja, ich hatte mich da am Datenblatt entlanggehangelt und erst
später die hilfreichen Makros entdeckt, aber ich habs jetzt mal
geändert, was aber leider keine Verbesserung brachte.
Gruß, Frank
Kann es sein, das du evtl. Probleme mit der Variablen 'DoorStatus' hast?
Würde mich nicht wundern, weil du die etwas inkonsequent behandelst.
Entweder machst du die zu einer bool'schen oder du benutzt konsequent
deine OPEN und CLOSED defines, aber sowas hier:
1
// we really don't want door to be anything except 00000000b or 00000001b
2
doorStatus&=1;
macht dann nur noch eine 0 oder 1 aus Doorstatus und dann funktioniert
1
if(doorStatus==CLOSED)
2
{
3
while(!(PINB&(1<<DOOR_CLOSED)))
4
{
5
_delay_ms(100);
6
counter++;
7
if(counter>DOOR_TURNOFF_TIME)
8
break;
9
}
10
}
11
// wait until door is opened
12
if(doorStatus==OPEN)
13
{
14
while(!(PIND&(1<<DOOR_OPEN)))
15
{
16
_delay_ms(100);
17
counter++;
18
if(counter>DOOR_TURNOFF_TIME)
19
break;
20
}
21
}
natürlich nicht mehr, denn du hattest ja
1
#define OPEN 1
2
#define CLOSED 2
definiert. Ändere das mal lieber zu TRUE und FALSE, dann klappt das
besser.
Hi
ja, stimmt. OPEN und CLOSED waren ursprünglich mal als 0 und 1
definiert, das habe ich vergessen anzupassen. Leider schafft mein
Programm es bisher noch gar nicht bis dahin, da ja auch toggleCounter
nach dem ersten sleep_mode() nicht mehr verändert wird.
Gruß, Frank
Frank Evers schrieb:> da ja auch toggleCounter> nach dem ersten sleep_mode() nicht mehr verändert wird.
Grundsätzlich ist es keine gute Idee, 'SetupSleepMode()' schon mal vor
der Hauptschleife aufzurufen, das wurde aber schon gesagt. Mach das
direkt vor dem eigentlichen sleep_mode() und sorge dafür, das dann
später auch keine ISR mehr dazwischen funkt - z.B. der merkwürdige ADC
Interrupt, den du freigibst und definierst, der aber leer ist?
Übrigens hat avr-libc alle Funktionen, um den Sleep Mode zu setzen, das
musst du nicht zu Fuss machen. Hier ein kurzer Auszug aus meiner
Fernbedienung - die Hauptschleife:
1
// poll the PCINT Flags and call accordingly
2
{
3
while(RemoteFlags.KeyPressed){
4
Flash_IR(PressedKey);
5
CheckKeys();
6
}
7
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// set power down mode
Oliver S. : Ich habe mir in der Hauptschleife den Zählerstand von z.B.
wakeupCounter oder toggleCounter über Blinken der ERROR_LED anzeigen
lassen, und auch mal wakeupCounter um 2 inkrementiert und das Ergebnis
ist jeweils, dass beim ersten Schleifendurchlauf inkrementiert wird und
danach nichts mehr passiert.
ABER: du hast Recht! Testweise habe ich jetzt mal wakeupCounter mit 9
initialisiert und hier wird auch inkrementiert und in die if Verzweigung
gesprungen,
aber die Zuweisung wakeupCounter = 0 funktioniert offenbar nicht, denn
im nächsten Aufruf wird wieder in die if-Verzweigung gesprungen (und in
allen folgenden). Das Problem scheint also früher als gedacht zu
beginnen. Irgendwas mit den Gültigkeitsbereichen was ich übersehe? Ich
deklariere aber ja alles global...
Gruß, Frank
Frank Evers schrieb:> setNewReferenceValue
Und auch hier empfehle ich dir dringend, das zu einer bool'schen
Variable zu machen. Ein TRUE oder FALSE ist eindeutig - ein 0 oder 1 ist
hier irreführend.
Matthias S. schrieb:> Grundsätzlich ist es keine gute Idee, 'SetupSleepMode()' schon mal vor> der Hauptschleife aufzurufen
Warum denn?
Entweder Du traust dem MC, daß einmal gesetzte Register ihren Wert
behalten oder der MC ist Schrott.
Code, der einmalig etwas ändert, gehört immer vor die Mainloop.
Frank Evers schrieb:> aber die Zuweisung wakeupCounter = 0 funktioniert offenbar nicht, denn> im nächsten Aufruf wird wieder in die if-Verzweigung gesprungen (und in> allen folgenden).
Dafür gibt es ja noch zwei andere Möglichkeiten. Mach die doch mal
raus...
Frank Evers schrieb:> Bei meinem ersten AVR-Projekt> cli();> :> _delay_ms(100);> :> sei();
Ich habe da einen offensichtlichen Programmfehler gefunden... ;-)
Allein das delay_ms() im ablauf deutet auf einen unschönen
Programmierstil hin. Aber solange die Interrupts abzuschalten, das
grenzt an Verzweiflung. Das ist, wie wenn du den Milchmann nach dem
Klingeln eine Woche vor der Tür warten lässt. Und dich hinterher über
die saure Milch beschwerst...
Als Tipp: dieses Programm wäre besser und einfacher, wenn es nur mit 1
Timerinterrupt für die Zeit und ohne delay() programmiert wäre.
Allerdings brauchst du da einen etwas anderen Programmierstil.
// set Timer2 Pescaler ( CS22 - CS20) to 1024 and turn on CTC mode ( WGM21, WGM20 )
3
TCCR2&=~((1<<WGM20)|(1<<WGM21));
Das ist kein CTC, sondern Normal Mode.
1
TIFR&=~((1<<OCF2)|(1<<TOV2));
So löscht man keine Interrupt Flags.
1
2
TIMSK|=((1<<OCIE2)|(1<<TOIE2));
Wo ist die Compare-ISR?
Auch wenn der CTC-Mode nicht eingestellt ist, wird das Compare-Flag in
jedem TCNT-Umlauf gesetzt und der entsprechende Interrupt ausgeführt. Da
du keine ISR dafür hast, fängt dein Programm dann wieder von vorne an.
Hi
@Thomas Eckmann:
Im Verlauf der Fehlersuche habe ich schon das eine oder andere probiert
und in dem Zuge CTC in Normal Mode geändert, dabei aber (da hast du
Recht) vergessen den Interrupt dafür auszuschalten und die Kommentare
geändert. ja, alles etwas verzweifelt.
Wie löscht man Interrupt-Flags?
JIPPEE, das ungenutzte Compare-Interrupt rausgenommen und es scheint auf
den ersten Blick zu funktionieren :) Mal schauen ob jetzt auch der Rest
tut.
@Lothar Miller:
Die beiden anderen Möglichkeiten für die if-Verzweigung hatte ich
natürlich vorher schon testweise rausgenommen.
Die Interrupts deaktiviere ich, weil ich während des Türöffnens, bzw.
Türschließens keine Zustandsänderung will. Sollte zugegebenermaßen auch
so nicht passieren, das war das Codeäquivalent zum Angstblech ;) Ich
fange ja erst an mit der MC-Programmierung.
das delay_ms ist nicht schön, das war mir auch beim Schreiben schon
klar, ich habe da eine schnelle und dreckige Lösung gesucht mit Ambition
das später schöner zu machen, nur warum ist das ein Programmfehler?
Sollte das an der Stelle nicht trotzdem wie gewünscht klappen?
Nur 1 Timerinterrupt: Meinst du den TIMER2 auch rausnehmen? Wie kriege
ich den MC dann aus dem Power Save Mode? Oder zusätzlich einen Timer für
die Zeitsteuerung? TIMER2 wollte ich eigentlich so lassen, sonst ist die
Batterie so schnell leer...
Gruß, Frank
Frank Evers schrieb:> Wie löscht man Interrupt-Flags?
Indem man eine 1 an die entsprechende Stelle schreibt.
Im einfachsten Fall TIFR = TIFR.
Du solltest dich allerdings dringend intensiv mit dem Datenblatt
befassen.
Hi
Thomas E. schrieb:> Indem man eine 1 an die entsprechende Stelle schreibt.> Im einfachsten Fall TIFR = TIFR.
Hmm, ja, ich lösche also ein gesetztes Bit indem ich es nochmal setze...
Ja, steht so im Datenblatt, wenn auch etwas verklausoliert
> Du solltest dich allerdings dringend intensiv mit dem Datenblatt> befassen.
Hatte ich eigentlich, dachte ich, aber diese Passage hatte ich falsch
gelesen.
Gruß, Frank
Dank eurer Hilfe funktioniert meine Hühnerklappe jetzt erstmal wie sie
soll. In der Schaltung waren noch ein paar Korrekturen nötig. Was mich
dabei überrascht hat: Ich wollte einen Spannungsteiler aus LDR und 10k
Festwiderstand direkt über MC-Pin betreiben, aber die
Ausgangsspannungpannung brach massiv ein, obwohl rechnerisch maximal
rund 300uA drüber gehen sollten - Ich dachte das schafft der ATmega. Mit
einem Transistor drin geht es jetzt sehr gut.
Der INT0-Interrupt funktionierte so noch nicht, ein Blick ins Datenblatt
verriet mir dann, dass der in allen Schlafzuständen außer Idle nur mit
Low-Pegel oder Pegeländerung funktioniert, nicht aber mit Signalflanken.
Für den Ersatz der Delays habe ich mir mittlerweile was ausgedacht, das
muss aber bis nach dem Urlaub warten. Das bemängelte Ausschalten der
Interrupts war in der Tat unnötig und ist jetzt raus.
Wie auch immer: Erstes Mikrocontrollerprojekt erfolgreich und eine Menge
dabei gelernt :)
Gruß, Frank
Frank Evers schrieb:> Ausgangsspannungpannung brach massiv ein, obwohl rechnerisch maximal> rund 300uA drüber gehen sollten - Ich dachte das schafft der ATmega. Mit> einem Transistor drin geht es jetzt sehr gut.
Dann hast du den Pin nicht als Ausgang gesetzt, sondern nur den Pullup
aktiviert.
Tipp:
Ein bisschen mehr Sorgfalt, dann klappts auch mit den AVR.
Arduino F. schrieb:>> Ausgangsspannungpannung brach massiv ein, obwohl rechnerisch maximal>> rund 300uA drüber gehen sollten - Ich dachte das schafft der ATmega. Mit>> einem Transistor drin geht es jetzt sehr gut.>> Dann hast du den Pin nicht als Ausgang gesetzt, sondern nur den Pullup> aktiviert.
Nö, der ist schon als Ausgang gesetzt, siehe setupIOs():
1
/* set optputs */
2
// L293 enable, 1A, 2A, Sensor supply
3
DDRC|=(1<<DDC5)|(1<<DDC4)|(1<<DDC3)|(1<<DDC1);
Ich habe die Schaltung auch dreimal durchgemessen. Der ADC ist ja auch
als Eingang beschaltet und somit hochohmig. Ich werde es mir im Zuge des
nächsten Upgrades nochmal anschauen.
Da die Schaltung batteriebetrieben ist sind da noch große
Einsparpotentiale auszuschöpfen :)
>> Tipp:> Ein bisschen mehr Sorgfalt, dann klappts auch mit den AVR.
Naja, ist halt ziemlich viel Info auf einmal. 300 Seiten Datenblatt
bleiben nicht mit einem mal lesen hängen. Und es klappt ja. Ich habe nur
vorher keinerlei Erfahrung mit den Biestern gehabt, insoweit bin ich
eigentlich ganz zufrieden mit dem Ergebnis. Was mir fehlt ist in erster
Linie Erfahrung, aber daran arbeite ich ja :)
Gruß, Frank
Frank Evers schrieb:> Nö, der ist schon als Ausgang gesetzt, siehe setupIOs():
Tut mir leid, daran kann ich nicht sehen, welchen Pin du dafür benutzt
hast.
Und schon gar nicht, kann ich das im Zusammenhang prüfen.
Ein High geschalteter Ausgang sollte min. 20mA liefern können.
Wenn er das nicht kann, liegt irgendwas ganz arg daneben.