[英]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指示灯打开,而is_sleeping
最初设置为零,则while循环处于空闲is_sleeping
。 第一个INT0中断触发LED(将其关闭)并设置is_sleeping
标志,以便while循环将在下一个回合中进入受保护的代码。 该代码使MCU在sleep_mcu()
行上进入睡眠状态。 一旦INT0中断等待MCU,它将从最后一个位置继续执行,即因为is_sleeping
仍被设置,所以is_sleeping
返回睡眠状态! (并且在您的代码中永远都不会变回false)。 这意味着MCU唤醒后,它几乎立即进入睡眠状态,直到下一个INT0中断都将关闭。
因此,要回答您的问题, 它永远不会醒来,我会说:它确实醒了,但时间很短。 如果测量电流(例如,使用示波器和分流电阻器),则在唤醒并立即进入睡眠状态时会观察到尖峰。
不管您遇到什么主要问题,都要注意代码质量。 嵌入式编程远非宽容,您可能会因琐碎的错误而停留数小时。 例如,始终对宏定义保持防御。 您将BUTTON
定义为1<<PB1
不带括号。 区别在于,稍后您会受到运算符优先级的打击。 例如,使用DDRB &= ~BUTTON
您将没有期望的结果。 您的右侧表达式展开为11111100
(因为~1<<1
是11111110 << 1
),而您想要的是11111101
(因为~(1<<1)
是~ 00000010
)。 如果将PB0用于其他用途,则可能会出现不良行为。
另外,在复制示例代码时,请确保您理解其含义。 sleep.h
的样本依赖于同时使用sei
和cli
互补。 在您的代码中,您仅坚持在循环中重新启用中断,这在这里是没有意义的。
编辑:由于您声称唤醒工作在“空闲”模式下,因此您的下一个问题是,您希望通过将MCUCR
(ISC00,ISC01)
对设置为(0,1)
来在下降沿唤醒系统。 请参见数据手册第9.2章中的内容, “注意在INT0上识别下降沿或上升沿中断需要有一个I / O时钟”,而第7.1章中的表则表明在掉电模式下不存在Clk_I / 0 。 通过将MCUCR
(ISC00,ISC01)
对设置为(0,0)
,可以唯一选择使INT0外部中断在低电平触发。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.