Last active
October 25, 2022 18:53
-
-
Save electronut/5648690 to your computer and use it in GitHub Desktop.
Putting the ATmega168 into Power Save mode, and then waking it with a pin-change interrupt.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//********************************************************************** | |
// | |
// Putting the ATmega168 into Power Save mode, and then waking it | |
// with a pin-change interrupt. | |
// | |
// electronut.in | |
//********************************************************************** | |
/* | |
build commands on OS X with CrossPack: | |
avr-gcc -Wall -Os -DF_CPU=8000000 -mmcu=atmega168 -c main.c -o main.o | |
avr-gcc -Wall -Os -DF_CPU=8000000 -mmcu=atmega168 -o main.elf main.o | |
rm -f main.hex | |
avr-objcopy -j .text -j .data -O ihex main.elf main.hex | |
avr-size --format=avr --mcu=atmega168 main.elf | |
avrdude -c usbtiny -p atmega168 -U flash:w:main.hex:i | |
avrdude -c usbtiny -p atmega168 -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m -U efuse:w:0x01:m | |
*/ | |
#include <avr/io.h> | |
#include <string.h> | |
#include <util/delay.h> | |
#include <avr/interrupt.h> | |
#include <avr/sleep.h> | |
#define F_CPU 8000000 | |
// for sleep | |
volatile int goToSleep = 0; | |
int main (void) | |
{ | |
// Put an LED on PD4 (pin 6) | |
// PD4 as output | |
DDRD |= (1<<4); | |
//Set high | |
PORTD |= (1<<4); | |
// | |
// 16-bit timer setup: | |
// | |
// turn off interrupts | |
cli(); | |
// 16 bit timer - every 3 seconds: | |
// Count cycles - 3*8000000/1024 | |
OCR1A = 23437; | |
// Put Timer/Counter1 in CTC mode | |
TCCR1B |= 1<<WGM12; | |
// enable 16-bit timer interrupt | |
TIMSK1 |= 1<<OCIE1A; | |
// start 16-bit timer if PCINT0 pin-14 PB0 is low | |
if((!PINB & (1 << PB0))) { | |
TCCR1B |= (1<<CS12) | (1<<CS10); // Divide by 1024 | |
} | |
// enable Pin change interrupt enable 0 | |
// this is PCINT0 - pin 14 | |
PCICR |= (1 << PCIE0); | |
PCMSK0 |= (1 << PCINT0); | |
// turn on interrupts | |
sei(); | |
// loop | |
while (1) { | |
// delay | |
_delay_ms(100); | |
// toggle led pin on/off | |
PORTD ^= (1<<4); | |
// sleep section | |
if(goToSleep) { | |
// turn LED pin off | |
PORTD &= ~(1<<4); | |
// set sleep mode | |
set_sleep_mode(SLEEP_MODE_PWR_SAVE); | |
// disable global interrupts | |
cli(); | |
// enable sleep flag | |
sleep_enable(); | |
// enable global interrupts | |
sei(); | |
// actually sleep | |
sleep_cpu(); | |
// ... | |
// just awake here | |
// ... | |
// disable global interrupts | |
cli(); | |
// enable Pin change interrupt enable 0 | |
// this is PCINT0 - pin 14 | |
PCICR |= (1 << PCIE0); | |
PCMSK0 |= (1 << PCINT0); | |
// unset sleep flag | |
goToSleep = 0; | |
// disable sleep flag | |
sleep_disable(); | |
// enable global interrupts | |
sei(); | |
} | |
} | |
return 1; | |
} | |
// pin change interrupt | |
ISR (PCINT0_vect) | |
{ | |
// read PCINT0 (PB0 - pn 14): | |
if(PINB & (1 << PB0)) { | |
// rising edge | |
// disable sleep - wake up! | |
sleep_disable(); | |
// stop clock for 16-bit timer | |
TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10)); | |
} | |
else{ | |
// falling edge | |
// clear counter in 16-bit timer | |
TCNT1 = 0; | |
// start 16-bit timer | |
TCCR1B |= (1<<CS12) | (1<<CS10); | |
} | |
} | |
// 16-bit timer CTC handler | |
ISR(TIMER1_COMPA_vect) | |
{ | |
// set sleep flag | |
goToSleep = 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment