Fischertechnik AVR Raspberry Pi Elektronik Netzwerk Sonstiges Impressum |
Stromsparen mit ATtiny25Diese Schaltung läuft mit einem alten 65mAh-LiPo aus einem alten Spielzeug mehr als sechs Monate und erzeugt unerwartet helle Lichtblitze. Der Trick ist die Nutzung der "sleep"-Funktion des ATtiny, die den Strombedarf drastisch reduziert. Das Programm erzeugt alle 15 Sekunden einen Lichtblitz mit einer Dauer von 3 Millisekunden. Die weiße LED wird ohne Vorwiderstand betrieben, überlebt das aber problemlos; sie hat ja genügend Zeit zum Abkühlen. Der Stromverbrauch im Sleep-Mode/Watchdog-Enabled liegt bei ca. 6μA. Mit dieser Technik habe ich auch einen Temperatur-Logger auf Basis ATmega328P aufgebaut, der alle drei Minuten die Temperatur misst und auf einer μSD-Karte abspeichert. Dieser Logger läuft mit einem 420mAh-LiPo mehr als 4 Wochen. Quelltext/* 2011 Februar CN ATTINY 25/45/85 fuer Blinkschaltung Stromversorgung: 1 Zelle LiPo Beschaltung: Pin 1 offen (Reset) Pin 2 Ausgang fuer LED Port B3 Pin 3 Pin 4 Ground, Masse Pin 5 Pin 6 Pin 7 Pin 8 Vcc, +3,7V */ #define SET_B3 PORTB |= (1<< PB3) // LED #define CLR_B3 PORTB &= ~(1<< PB3) #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif /* ------------------------------------------------------------------------- */ #include <inttypes.h> #include <avr/io.h> #include <stdlib.h> #include <string.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <util/delay.h> #include <avr/pgmspace.h> //----------------------------------------------------------------------------- // 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec void setup_watchdog(uint8_t ii) { uint8_t bb; if (ii > 9 ) ii=9; // begrenze auf erlaubte Werte bb=(ii+0x18)&0x27; // schiebe bit3 in bit 5 bb|= (1<<WDCE); // ist ggf. ueber .... ????? MCUSR &= ~(1<<WDRF); WDTCR |= (1<<WDCE) | (1<<WDE); // nur so geht der Enable vom Watchdog!! WDTCR = bb; // set new watchdog timeout value WDTCR |= _BV(WDIE); // Watchdog Interrupt Enable } //----------------------------------------------------------------------------- // set system into the sleep state; system wakes up when watchdog is timed out void system_sleep() { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); // gute nacht, schlaf schoen... } //----------------------------------------------------------------------------- void delay_seconds_by_watchdog(uint16_t sec){ uint16_t t1; uint8_t t2; //t2 ist die tatsaechliche Watchdog-Zeit in Sekunden uint8_t t3; //t3 ist der zugehoerige Parameter hierzu t1=sec; while(t1>0){ if(t1>7){t3=9;t2=8;} else if(t1>3){t3=8;t2=4;} else if(t1>1){t3=7;t2=2;} else {t3=6;t2=1;}; setup_watchdog(t3); system_sleep(); t1-=t2; }; } /* ------------------------------------------------------------------------- */ void wait(uint16_t dauer){ uint16_t j; uint8_t i; for(j=0;j<dauer;j++){ for(i=100;i>0;i--)asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop"); }; } /* ------------------------------------------------------------------------- */ // ISR fuer Watchdog muss selber nichts tun; wichtig ist, dass sleep endet ISR(WDT_vect) { } /* ------------------------------------------------------------------------- */ void main(void) { uint8_t minutes=0; DDRB = (1<<PB3); // Setze LED-Anschluss als Ausgang sei(); // erlaube prinzipiell Interrupts for(;;){ SET_B3; // LED an wait(3); // ca. 3 ms CLR_B3; // LED aus DDRB = 0; // LED Ausgang als Eingang definieren, spart Strom... delay_seconds_by_watchdog(15); DDRB = (1<<PB3); // LED-Ausgang wieder richtig als Ausgang }; } /* ------------------------------------------------------------------------- */ Makefileavrdude = avrdude -v -v DEVICE = attiny25 CLOCK = 1000000 PROGRAMMER = -c avrispmkII -P usb OBJECTS = blink25.o # Fuses: internal oscilator 8 MHz, 1:8 prescale, BOD 2.7V FUSES = -U hfuse:w:0xDD:m -U lfuse:w:0x62:m AVRDUDE = $(avrdude) $(PROGRAMMER) -p $(DEVICE) OBJDUMP = avr-objdump COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -mint8 # symbolic targets: all: blink25.hex blink25.lss .c.o: $(COMPILE) -c $< -o $@ .S.o: $(COMPILE) -x assembler-with-cpp -c $< -o $@ asm: $(COMPILE) -S -o blink25.asm blink25.c .c.s: $(COMPILE) -S $< -o $@ flash: all $(AVRDUDE) -U flash:w:blink25.hex:i fuse: $(AVRDUDE) $(FUSES) install: flash fuse clean: rm -f blink25.hex blink25.elf $(OBJECTS) blink25.elf: $(OBJECTS) $(COMPILE) -o blink25.elf $(OBJECTS) blink25.hex: blink25.elf rm -f blink25.hex avr-objcopy -j .text -j .data -O ihex blink25.elf blink25.hex disasm: blink25.elf avr-objdump -Z -d blink25.elf %.lss: %.elf @echo $(OBJDUMP) -h -S $< > $@ cpp: $(COMPILE) -E blink25.c |