问题
I'm trying to put my AtTiny 13 to sleep and wake it up with interrupt. It does go to sleep but it never wakes up. The whole code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <avr/sleep.h>
#define RED (1<<PB4)
#define RED_HIGH PORTB |=RED
#define RED_LOW PORTB &= ~RED
#define RED_TOG PORTB ^= RED
#define BUTTON 1<<PB1
volatile static bool is_sleeping;
ISR(INT0_vect)
{
RED_TOG;
is_sleeping = true;
}
int main(void){
GIMSK |= 1<<INT0;
MCUCR |= 0<<ISC00 | 1<<ISC01;
sei();
DDRB |= RED;
DDRB &= ~BUTTON;
PORTB |= BUTTON;
RED_HIGH;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
while(1){
if(is_sleeping){
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
}
}
According to sleep.h data it should work. Any ideas?
Update: it does not have problems with waking up from IDLE mode;
回答1:
Assuming no hardware wiring issues your code is working as follow: after booting your LED is turned on and while-loop is idling since is_sleeping
is initially set to zero. First INT0 interrupt toggles LED (turns it off) and sets is_sleeping
flag so that while-loop will enter to guarded code in next turn. That code turns MCU to sleep on sleep_mcu()
line. Once INT0 interrupt awaits MCU it continues from last place i.e. it goes back to sleep because is_sleeping
is still set! (and in your code is never turned back to false). It means that right after MCU awakes it goes to sleep almost instantly and is off until next INT0 interrupt.
So to answer you question it never wakes up I would say: it does wake up but for really short moment. If you measure current (e.g. with scope and shunt resistor) you would observe spikes when it wakes and goes asleep immediatelly.
Regardless of you main problem pay attention to code quality. Embedded programming is far from forgiving and you may stuck for hours on trivial mistakes. For instance always be defensive with macro definitions. You defined BUTTON
as 1<<PB1
without parens. Difference is that later on you get hit by operators precedence. For instance using DDRB &= ~BUTTON
you do not have what you expect. Your right side expression unfolds to 11111100
(because ~1<<1
is 11111110 << 1
) while you wanted 11111101
(because ~(1<<1)
is ~ 00000010
). If you use PB0 for something else you would expect unwanted behavior.
Also when copying sample code make sure you understand what it stands for. The sample in sleep.h
relies on using both sei
and cli
complementary. In your code you only insist on re-enablig interrupts in loop, which is pointless here.
EDIT: Since you claim wake up works in "idle" mode, then your next issue is that you expect system to wake up on falling edge by setting pair (ISC00,ISC01)
to (0,1)
in MCUCR
. See datasheet chapter 9.2 that says "Note that recognition of falling or rising edge interrupts on INT0 requires the presence of an I/O clock" while table in chapter 7.1 says that Clk_I/0 not present in power-down mode. Your only choice it to make INT0 external interrupt to trigger on low level by setting pair (ISC00,ISC01)
to (0,0)
in MCUCR
.
来源:https://stackoverflow.com/questions/47504614/avr-sleep-mode-and-wake-up