AVR睡眠模式并唤醒 [英] avr sleep mode and wake up

查看:281
本文介绍了AVR睡眠模式并唤醒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

根据sleep.h数据,它应该可以工作.有什么想法吗?

According to sleep.h data it should work. Any ideas?

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

Update: it does not have problems with waking up from IDLE mode;

推荐答案

假定没有硬件布线问题,您的代码将按以下方式工作:引导后,LED指示灯打开,并且由于is_sleeping最初设置为,而while循环处于空闲状态零.第一个INT0中断切换LED(将其关闭)并设置is_sleeping标志,以便while循环将在下一轮进入保护代码.该代码使MCU进入sleep_mcu()行休眠.一旦INT0中断等待MCU,它将从最后一个位置继续执行,即因为is_sleeping仍被置位而返回睡眠状态! (并且在您的代码中永远不会变回false).这意味着在MCU唤醒后,它几乎立即进入睡眠状态,直到下一次INT0中断都将关闭.

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.

无论您遇到什么主要问题,都要注意代码质量.嵌入式编程远非宽容,您可能会因琐碎的错误而停留数小时.例如,始终对宏定义保持防御.您将BUTTON定义为1<<PB1,没有括号.区别在于,稍后您会受到运算符优先级的打击.例如,使用DDRB &= ~BUTTON时,您所没有的期望.当您想要11111101(因为~(1<<1)~ 00000010)时,右侧表达式会展开为11111100(因为~1<<111111110 << 1).如果将PB0用于其他用途,则可能会发生不良行为.

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.

此外,在复制示例代码时,请确保您了解其含义. sleep.h中的示例依赖于同时使用seicli互补.在您的代码中,您仅坚持在循环中重新启用中断,这在这里是没有意义的.

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.

编辑:由于您声称唤醒在空闲"模式下有效,因此您的下一个问题是,您希望通过将对中的(ISC00,ISC01)设置为(0,1) MCUCR.参见数据手册第9.2章中的注意,识别INT0上的下降沿或上升沿中断需要存在一个I/O时钟" ,而第7.1章中的表则说不存在 Clk_I/0 在掉电模式下.通过将MCUCR中的(ISC00,ISC01)设置为(0,0)对,可以选择使INT0外部中断在低电平上触发.

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.

这篇关于AVR睡眠模式并唤醒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆