我正在尝试让我的 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 循环自 is_sleeping
起空闲。最初设置为零。第一个 INT0 中断切换 LED(将其关闭)并设置 is_sleeping
标志,以便 while 循环在下一轮进入 protected 代码。该代码使 MCU 进入休眠状态 sleep_mcu()
线。一旦 INT0 中断等待 MCU,它就会从最后一个位置继续,即它会返回 sleep 状态,因为 is_sleeping
仍然设置! (并且在您的代码中永远不会变回 false)。这意味着 MCU 唤醒后几乎立即进入休眠状态,并关闭直到下一个 INT0 中断。
所以回答你的问题它永远不会醒来我会说:它确实会醒来,但时间很短。如果您测量电流(例如使用示波器和分流电阻器),您会在电流唤醒和立即休眠时观察到尖峰。
无论你的主要问题是什么,都要注意代码质量。嵌入式编程绝不是宽容的,您可能会因为一些微不足道的错误而陷入数小时的困境。例如,始终对宏定义保持防御态度。您定义了BUTTON
如1<<PB1
没有括号。不同之处在于,稍后您会受到运算符优先级的影响。例如使用 DDRB &= ~BUTTON
你没有得到你所期望的。你的右侧表情展开为 11111100
(因为 ~1<<1
是 11111110 << 1
)而你想要 11111101
(因为 ~(1<<1)
是 ~ 00000010
)。如果您将 PB0 用于其他用途,您可能会遇到不需要的行为。
此外,在复制示例代码时,请确保您了解它的含义。 sleep.h
中的样本依赖于同时使用 sei
和cli
补充。在您的代码中,您只坚持在循环中重新启用中断,这在这里毫无意义。
编辑:由于您声称唤醒工作在“空闲”模式下,那么您的下一个问题是您希望系统通过设置对(ISC00,ISC01)
在下降沿唤醒。至(0,1)
在MCUCR
。请参阅数据表第 9.2 章“请注意,识别 INT0 上的下降沿或上升沿中断需要存在 I/O 时钟”,而第 7.1 章中的表则指出“Clk_I/0 不存在” 在掉电模式下。您唯一的选择是通过设置对 (ISC00,ISC01)
使 INT0 外部中断在低电平触发。至(0,0)
在MCUCR
.
关于c - avr sleep 模式和唤醒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47504614/