avr 睡眠模式和唤醒

avr sleep mode and wake up

我正在尝试让我的 AtTiny 13 进入睡眠状态并通过中断将其唤醒。它确实睡着了,但它永远不会醒来。完整代码:

#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();
        }
    }
}

根据 sleep.h 数据,它应该有效。有什么想法吗?

更新:从IDLE模式唤醒没有问题;

假设没有硬件接线问题,您的代码按如下方式工作:启动后,您的 LED 亮起并且 while-loop 处于空闲状态,因为 is_sleeping 最初设置为零。第一个 INT0 中断切换 LED(将其关闭)并设置 is_sleeping 标志,以便 while 循环在下一轮进入保护代码。该代码使 MCU 在 sleep_mcu() 行休眠。一旦 INT0 中断等待 MCU,它就会从最后一个地方继续,即它会回到睡眠状态,因为 is_sleeping 仍然设置! (并且在您的代码中永远不会变回 false)。这意味着在 MCU 唤醒后它几乎立即进入睡眠状态并关闭直到下一个 INT0 中断。

所以回答你的问题它永远不会醒来我会说:它确实会醒来,但时间很短。如果您测量电流(例如使用示波器和分流电阻器),您会在它醒来并立即进入睡眠状态时观察到尖峰。

不管你主要问题是注意代码质量。嵌入式编程远非宽容,您可能会因为微不足道的错误而陷入困境数小时。例如,始终对宏定义进行防御。您将 BUTTON 定义为没有括号的 1<<PB1。区别在于稍后您会受到运算符优先级的影响。例如使用 DDRB &= ~BUTTON 你没有你所期望的。您的右侧表达式展开为 11111100(因为 ~1<<111111110 << 1),而您想要 11111101(因为 ~(1<<1)~ 00000010)。如果您将 PB0 用于其他用途,您可能会遇到不希望的行为。

此外,在复制示例代码时,请确保您了解它的含义。 sleep.h 中的示例依赖于使用 seicli 互补。在您的代码中,您只坚持在循环中重新启用中断,这在这里毫无意义。

编辑: 由于您声称唤醒在 "idle" 模式下工作,那么您的下一个问题是您希望系统通过设置对 (ISC00,ISC01)(0,1)MCUCR。请参阅数据表第 9.2 章说 "Note that recognition of falling or rising edge interrupts on INT0 requires the presence of an I/O clock" 而第 7.1 章中的 table 说 Clk_I/0 不存在 掉电模式。您唯一的选择是通过在 MCUCR.

中设置对 (ISC00,ISC01)(0,0) 来使 INT0 外部中断在低电平触发