Hy Leute, Ich arbeite gerade mit dem ATMEGA32L und soll so energiesparend wie möglich programmieren. Dafür möchte ich alle _delay_ms(); durch eine eigene Routine ersetzen, welche den µC für diese Zeit in den Idle-Mode schickt. Ich habe das Programm außerhalb meines Hauptprogramms zur Testung geschrieben. Da die Variante mit Timer1 und ISR(TIMER1_COMPA_vect); nicht funktioniert hat, kommentierte ich diese aus und versuchte es mit einem externen Interrupt. Doch leider komm ich auf das selbe Ergebnis, die LED (welche mir als Kontrolle dient) schaltet sich ca. alle 5s ein und nach weiteren 5s wieder aus. Ich konnte in anderen Beiträgen, bzw. im GCC Tutorial keinen Unterschied zu meinem Programm entdecken... Vielen Dank im Voraus!
ghost schrieb: > Da die Variante mit Timer1 und ISR(TIMER1_COMPA_vect); nicht > funktioniert hat, Das geht auch nicht. Im Sleep ist der Takt abgeschaltet. Dann hat der Timer nichts zum zählen. ghost schrieb: > Doch leider komm ich auf das selbe Ergebnis, die LED (welche mir als > Kontrolle dient) schaltet sich ca. alle 5s ein und nach weiteren 5s > wieder aus. Wo kommen denn die 5s her? Und wieso dasselbe Ergebnis? Dasselbe wie was? mfg.
Thomas Eckmann schrieb: > ghost schrieb: >> Da die Variante mit Timer1 und ISR(TIMER1_COMPA_vect); nicht >> funktioniert hat, > > Das geht auch nicht. Im Sleep ist der Takt abgeschaltet. Nein. > ghost schrieb: >> Doch leider komm ich auf das selbe Ergebnis, die LED (welche mir als >> Kontrolle dient) schaltet sich ca. alle 5s ein und nach weiteren 5s >> wieder aus. > > Wo kommen denn die 5s her? Ich hätte 2,2 erwartet, wenn das Schlafen nicht funktioniert. > Und wieso dasselbe Ergebnis? Dasselbe wie was? Das selbe wie mit Timer? ghost schrieb: > #define EXT_INT0_PIN PD3 > #define EXT_INT1_PIN PD2 Das ist falsch. Laut Datenblatt ist PD2 INT0 und PD3 INT1.
Thomas Eckmann schrieb: > Das geht auch nicht. Im Sleep ist der Takt abgeschaltet. Dann hat der > Timer nichts zum zählen. Wasn Quatsch. Natürlich läuft alle Peripherie im Idle weiter, nur die CPU wird angehalten. Die Stromeinsparung ist daher auch nicht sonderlich hoch (~50%).
Ich weiß leider auch nicht warum es 5s sind... die Frequenz (soft- und hardwaretechnisch) stimmt. Das mit INT0 und INT1 ist in diesem Fall egal, weil beide gleich beschaltet werden, aber danke. Ja genau, ich erhalte mit externem Interrupt und Timer1 dasselbe Ergebnis => kein Idle-Mode, LED schaltet sich alle 5s ein und aus. Auch der Stromverbrauch sinkt nicht während der Messung nicht(nur der Strom der LED bei EIN/AUS).
:
Bearbeitet durch User
Thomas P. schrieb: > LED schaltet sich alle 5s ein und aus. Dann stimmt Dein F_CPU nicht. Im Code hast Du ja 10 * 0,2s stehen. Du mußt das nicht verklausulieren, _delay_ms verträgt bis 6,5535s. Was sollen die Delays überhaupt, schmeiß sie raus und nimm den Timer.
Mein F_CPU ist auf 1MHz eingestellt, softwaretechnisch und hardwaretechnisch. Auszug aus delay.h: "The maximal possible delay is 262.14 ms / F_CPU in MHz." Die Delays habe ich, um den Strom besser messen zu können. Ich glaube nicht, dass es an den _delay_ms() liegt...
Thomas P. schrieb: > Auszug aus delay.h: > "The maximal possible delay is 262.14 ms / F_CPU in MHz." Wenn's danach nicht weitergeht hast du aber noch eine sehr, sehr alte Version davon installiert. Die nächsten Sätze wären nämlich: When the user request delay which exceed the maximum possible one, _delay_ms() provides a decreased resolution functionality. In this mode _delay_ms() will work with a resolution of 1/10 ms, providing delays up to 6.5535 seconds (independent from CPU frequency). The user will not be informed about decreased resolution. Und die "decreased resolution" ist sicher noch besser als Selbst-Zusammenstöpseln von Einzel-Delays in einer Schleife.
Ich weiß, dass es nachher noch weiter geht! Aber ich wollte die maximal erreichbare Genauigkeit, da ich mit dem Oszi alles kontrolliere. Aber darum geht es ja jetzt nicht. Ich möchte wissen, ob jemand einen Tipp hat, warum mein µC nicht in den Idle-Mode geht bzw. was ich vergessen oder falsch gemacht habe!
Thomas P. schrieb: > Aber darum geht es ja jetzt nicht. Ich möchte wissen, ob jemand einen > Tipp hat, warum mein µC nicht in den Idle-Mode geht bzw. was ich > vergessen oder falsch gemacht habe! Ich habe mir Mal erlaubt, dein Programm in der Timerversion laufen zu lassen. Atmega644, 1MHz, Prescaler = 64
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <util/delay.h> |
4 | #include <stdlib.h> |
5 | #include <avr/sleep.h> |
6 | |
7 | #define EXT_INT0_REG DDRD
|
8 | #define EXT_INT1_REG DDRD
|
9 | #define EXT_INT0_PORT PORTD
|
10 | #define EXT_INT1_PORT PORTD
|
11 | #define EXT_INT0_PIN PD3
|
12 | #define EXT_INT1_PIN PD2
|
13 | |
14 | |
15 | int main(void) |
16 | {
|
17 | DDRA = 0x00; |
18 | DDRB = 0x00; |
19 | DDRC = 0x00; |
20 | // DDRD = 0x00;
|
21 | PORTA = 0x00; |
22 | PORTB = 0x00; |
23 | PORTC = 0x00; |
24 | // PORTD = 0x00;
|
25 | |
26 | ACSR |= (1<<ACD); |
27 | |
28 | EXT_INT0_REG &= ~(1<<EXT_INT0_PIN); // activate external interruptports |
29 | EXT_INT0_PORT |= (1<<EXT_INT0_PIN); |
30 | |
31 | // GICR |= (1<<INT0);
|
32 | |
33 | TCCR1B |= (1<<CS11) | (1<<CS10) | (1<<WGM12); // Prescaler 64 |
34 | TIMSK1 |= (1<<OCIE1A); |
35 | OCR1A = 5*975; // max.: 975 => jede Sekunde ein Interrupt |
36 | //
|
37 | // => 975/10 = 97 => alle 100ms ein Interrupt
|
38 | |
39 | while(1) |
40 | {
|
41 | DDRD &= ~(1<<PD7); |
42 | PORTD &= ~(1<<PD7); |
43 | |
44 | for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++) |
45 | {
|
46 | _delay_ms(200); |
47 | }
|
48 | |
49 | set_sleep_mode(SLEEP_MODE_IDLE); |
50 | sei(); |
51 | sleep_enable(); |
52 | TCNT1 = 0; |
53 | sleep_cpu(); |
54 | sleep_mode(); |
55 | |
56 | sleep_disable(); |
57 | DDRD |= (1<<PD7); |
58 | PORTD |= (1<<PD7); |
59 | |
60 | for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++) |
61 | {
|
62 | _delay_ms(200); |
63 | }
|
64 | }
|
65 | }
|
66 | |
67 | ISR(TIMER1_COMPA_vect) |
68 | {
|
69 | ;
|
70 | }
|
Der Sleepmode wird erreicht und es läuft mit dem erwarteten Timing. TIMSK1 muss in TIMSK geändert werden. Dann muss das bei dir auch laufen. mfg.
:
Bearbeitet durch User
Thomas P. schrieb: > Beim ATMEGA32 gibt es leider kein TIMSK1... Thomas Eckmann schrieb: > TIMSK1 muss in TIMSK geändert werden. mfg.
Ah, ok, das hab ich falsch verstanden! Ich dachte, sleep_mode() ist die Zusammenfassung von sleep_enable() und sleep_cpu()? Warum benötige ich hier beides? Ich kann leider trotzdem keine Änderung des Stromes messen... 17mA (ohne Status-LED), weniger bekomm ich nicht!
:
Bearbeitet durch User
Peter Dannegger schrieb: > Dann stimmt Dein F_CPU nicht. > Im Code hast Du ja 10 * 0,2s stehen. 11 * 0,2 s. Thomas P. schrieb: > Die Delays habe ich, um den Strom besser messen zu können. Ja, aber wenn da 5 statt 2,2 Sekunden rauskommen und die Taktrate korrekt für das Delay angegeben ist, sind das 2,8 Sekunden zuviel. Die müssen ja irgendwo herkommen. Thomas P. schrieb: > Ich weiß, dass es nachher noch weiter geht! Aber ich wollte die maximal > erreichbare Genauigkeit, da ich mit dem Oszi alles kontrolliere. Die verlierst du durch deine Schleife außenrum aber auch. Und wenn der Takt vom internen R/C-Oszillator stammen sollte, ist der außerdem noch deutlich ungenauer.
Thomas P. schrieb: > Ich dachte, sleep_mode() ist die Zusammenfassung von sleep_enable() und > sleep_cpu()? Warum benötige ich hier beides? Benötigst du nicht. Da habe ich einfach nur zuviel wieder "einkommentiert". Ich hab das Ganze jetzt ein wenig zusammengestrichen:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <util/delay.h> |
4 | #include <stdlib.h> |
5 | #include <avr/sleep.h> |
6 | |
7 | int main(void) |
8 | {
|
9 | ACSR |= (1<<ACD); |
10 | |
11 | TCCR1B |= (1<<CS11) | (1<<CS10) | (1<<WGM12); // Prescaler 64 |
12 | TIMSK1 |= (1<<OCIE1A); |
13 | OCR1A = 5*975; // max.: 975 => jede Sekunde ein Interrupt |
14 | //
|
15 | // => 975/10 = 97 => alle 100ms ein Interrupt
|
16 | |
17 | DDRD |= (1<<PD7); |
18 | set_sleep_mode(SLEEP_MODE_IDLE); |
19 | sleep_enable(); |
20 | sei(); |
21 | |
22 | while(1) |
23 | {
|
24 | PORTD &= ~(1<<PD7); |
25 | |
26 | //for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++) _delay_ms(200);
|
27 | _delay_ms(2200); |
28 | |
29 | TCNT1 = 0; |
30 | sleep_cpu(); |
31 | |
32 | PORTD |= (1<<PD7); |
33 | |
34 | // for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++) _delay_ms(200);
|
35 | _delay_ms(2200); |
36 | }
|
37 | }
|
38 | |
39 | ISR(TIMER1_COMPA_vect) |
40 | {
|
41 | }
|
Thomas P. schrieb: > Ich kann leider trotzdem keine Änderung des Stromes messen... 17mA (ohne > Status-LED), weniger bekomm ich nicht! Sleep Idle ist nicht sehr effektiv. Bei mir beträgt der Unterschied 1,3mA (84,4mA : 83,1mA). Auf meinem Testboard ist aber noch einiges mehr drauf. Der 644P verbraucht ca. 10mA bei 5V. Also gut 10% Ersparnis im Sleep. Bei 3V beträgt der Unterschied nur noch 0,4mA. mfg.
Danke Thomas. Ich glaub das war es jetzt. Ich komme jetzt auch auf diese Werte! Vielen Dank für die Hilfe!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.