Forum: Mikrocontroller und Digitale Elektronik AVR GCC strom sparen lange sleep-sequenz


von Richard X. (synq1e)


Lesenswert?

Hallo,

ich möchte für ein Projekt möglichst lange (1-3 stunden) den Attiny2313 
auf einer niedrigen Taktrate im IDLE modus haben. um mich auf diese 
lange zeit vorzuarbeiten habe ich es mit einem testlauf von einer 
sekunde probiert. bei einer clock-fuse einstellung von 8mhz und CKDIV 
unprogrammiert.

irgendwie bekomme ich zwischen den beiden flanken von PB0 [fallende 
flanke] -> [steigenden flanke] nur 70ms

anscheinend bleibt mein µC auf 8Mhz / 8 = 1Mhz , eigentlich müsste er 
aber deutlich langsamer laufen wegen:  CLKPR = 7;   // change F_CPU 
clock presc 128. ich bin ratlos warum er diese internal system clock 
prescaler von 128 nicht annimmt.

wenn wer verbesserungsvorschläge hat wäre ich demjenigen sehr verbunden.


es wird mit timer1 overflow vom sleep idle wieder aufgeweckt.


CODE:
1
#define DDR     DDRB
2
#define PORT    PORTB
3
#define PIN     PB2
4
#define F_CPU   1000000
5
6
#include <avr/io.h>
7
#include <util/delay.h>
8
#include <avr/interrupt.h>
9
#include <avr/sleep.h>
10
 
11
ISR(TIMER1_OVF_vect)
12
{
13
14
}
15
16
void go_sleep (void)
17
{
18
19
    CLKPR |= (1<<CLKPCE);
20
    CLKPR = 7;   // change F_CPU clock presc 128
21
22
    set_sleep_mode(0);
23
    sleep_enable();
24
    TCNT1 = 0;
25
26
    TCCR1B |= (1<<CS10); //TIMER1 presc 1
27
    sei();
28
29
    sleep_cpu();        //SLEEP ab hier interrupt weckt mC wieder auf
30
    sleep_disable();    //für sachgemäßes aufwecken
31
32
    TCCR1B =0; //TIMER1 stop
33
    cli();
34
35
   CLKPR |= (1<<CLKPCE);
36
   CLKPR = 3;   // change F_CPU clock presc 8
37
}
38
39
int main (void)
40
{
41
42
43
    DDRB = 1;
44
    PORTB = 0xFF;
45
    PORTA = 0xFF;
46
    PORTD = 0xFF;
47
    ACSR |= (1<<ACD); //analog comparator disable
48
    DIDR |= (1<<AIN1D)| (1<<AIN0D);
49
    TIMSK  |= (1<<TOIE1);    //Timer1 ovf int. enable für sleep wake up
50
51
52
    CLKPR |= (1<<CLKPCE);
53
    CLKPR = 3;   // change F_CPU clock presc 8
54
55
56
    PORTB |= (1<<PB0);
57
    _delay_ms(150);
58
    PORTB &= ~(1<<PB0);
59
    _delay_ms(150);
60
    while (1)
61
    {
62
    PORTB |= (1<<PB0);
63
    _delay_ms(5);
64
    PORTB &= ~(1<<PB0);
65
    _delay_ms(5);
66
    go_sleep();
67
    }
68
}

: Bearbeitet durch User
von Felix Adam (Gast)


Lesenswert?

Diese beiden Zeilen werden nicht innerhalb von 4 Taktzyklen ausgeführt:

CLKPR |= (1<<CLKPCE);
CLKPR = 7;   // change F_CPU clock presc 128

Außerdem sollen bis auf das höchste Bit zunächst alle anderen auf 0 
gesetzt werden, aber mit CLKPR |= ist das vielleicht nicht garantiert. 
Besser wäre:

CLKPR = (1<<CLKPCE);


Wenn du die Optimierung auf (mindestens) -O1 stellst, sollte es gehen, 
da dann die 4 Takte eingehalten werden.

Es gibt auch Assemblercode im C-Programm, kann dabei aber nicht helfen 
mangels Erfahrung.

von Richard X. (synq1e)


Lesenswert?

danke dir , ja stimmt :) nur leider funktionierts mit verschiedenen 
optimation levels auch nicht das der code kleiner wird.

CLKPR = (1<<CLKPCE);
CLKPR = 7;   // change F_CPU clock presc 128

erzeugt weniger anweisungen.

wahrscheinlich funktionierts mit den optimierungen ja im atmel studio 
nur ich kompiliere das ganze auf linux in codeblocks.

von Thomas E. (thomase)


Lesenswert?

Richard _. schrieb:
> ich bin ratlos warum er diese internal system clock
> prescaler von 128 nicht annimmt

Wurde ja schon genannt: Timed Sequence. In der 'avr/power.h' findest du 
die passenden Funktionen/Makros zur Einstellung des CLKPR.

Ich würde allerdings den Controller in den Power-Down-Slep schicken, 
alle 16s mit dem WDT aufwecken, in dessen ISR einen passend 
initialisierten Zähler runterzählen und nach dessen Ablauf den regulären 
Betrieb wieder aufnehmen.

mfg.

von Timmo H. (masterfx)


Lesenswert?

Verwende einfach clock_prescale_set aus der power.h, dafür sind die 
mitgelieferten Funktionen schließlich da.

: Bearbeitet durch User
von Richard X. (synq1e)


Lesenswert?

Thomas E. schrieb:
> Ich würde allerdings den Controller in den Power-Down-Slep schicken,
> alle 16s mit dem WDT aufwecken, in dessen ISR einen passend
> initialisierten Zähler runterzählen und nach dessen Ablauf den regulären
> Betrieb wieder aufnehmen.

Hm, meinst du diese möglichkeit würde den gesamten stromverbrauch besser 
reduzieren als meine ? (wenn ich nur aufgaben alle paar stunden 
verrichten will)
und 16sekunden WDT timeout habe ich noch bei keinem datenblatt von AVR's 
gesehen außer höchstens 8S

danke für vorschläge

von Joachim B. (jar)


Lesenswert?

noch besser RTC DS3231, der AVR kann solange tief schlafen wie er soll, 
der /INT0 kann ihn durch die RTC und Alarm wecken.

Achtung ich fand keine Module mehr die mit Akku LiR2032 geliefert 
werden, entweder ist nix drauf oder eine CR2032 die aber nicht geladen 
werden darf, die Ladediode müsste dann entfernt werden.

Der Akku LiR2032 hat 50mAh und wird über die Diode und 200 Ohm an Power 
5V nachgeladen, die CR2032 ist eine Batterie und sollte nicht 
nachgeladen werden, dafür hat sie über 200mAh und kommt länger ohne 
Strom aus.

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.