У этих микроконтроллеров есть несколько рабочих режимов - обычный, когда ядро молотит программу на полной скорости; "холостой", когда ядро и флэш-память отключены, но работает вся периферия; "энергосберегающий" (когда работает только _асинхронная_ периферия, в т.ч. медленный таймер); "отключенный" (когда работает только асинхронная периферия, но БЕЗ медленного таймера) и режим "ожидания", когда всё то же самое, как и в "отключенном", только жрёт на 10 мА больше.
Я всегда использую "энергосберегающий" - не потому, что я весь из себя такой гринписный чувак, а потому что батарейки менять лучше всё-таки пореже. И до сих пор всё прекрасно работало - я инициализировал таймер, разрешал его прерывания, прописывал нужный режим сна и, собсно, давал команду SLEEP.
Но теперь всё то же самое не работает. Просто нету прерываний, и всё тут. Можно, конечно, использовать "холостой" режим - он тоже заметно снижает потребление по сравнению с обычным ходом, но мне не нужно 10..12 мА потребления, мне надо не более 3 мА. Почему всё вдруг поломалось, я не знаю и не могу понять.
Самое печальное, что отладчик рапортует бодро, мол, всё в порядке, вот прерывание"... Но прерывания реально НЕТ!
Неужели проц глючный?
#include <inttypes.h> #include <ctype.h> #include <avr/io.h> #include <avr/sleep.h> #include <avr/interrupt.h> ISR (TIMER2_COMP_vect) /* Асинхронный таймер, работает всегда Это единственный источник событий, способный разбудить ЦПУ. */ { } int main(void) { /* настроим пин как вход (а то вдруг он думает, что он выход?) */ DDRE &= (uint8_t)~(1<<PORTE5); PORTE &= (uint8_t)~(1<<PORTE5); /* настроим пин как выход (а то вдруг он думает, что он вход?) */ DDRG |= (1<<PORTG0); PORTG |= (1<<PORTG0); /* Настроим T2 для асинхронной работы */ TIMSK2 &= (uint8_t)~( (1<<OCIE2A) ); ASSR = (1<<AS2); while (ASSR & (1<<TCN2UB)) asm("nop"); TCNT2 = 0x00; while (ASSR & (1<<OCR2UB)) asm("nop"); OCR2A = 31; while (ASSR & (1<<TCR2UB)) asm("nop"); TCCR2A = ((1<<WGM21) | (0<<WGM20) | (1<<CS22) | (1<<CS21) | (1<<CS20)); TIFR2 |= ( (1<<TOIE2) | (1<<OCIE2A) ); TIMSK2 |= ( (1<<OCIE2A) ); sei(); for (;;) /* вечно по кругу */ { SMCR |= ((0<<SM2) | (1<<SM1) | (1<<SM0)); sleep_enable(); sleep_cpu(); /* Здесь процессор заснёт */ sleep_disable(); PORTG ^= (1<<PORTG0); /* если sleep работает, то мы увидим медленный меандр на пине PG0*/ } return 0; }
Это, разумеется, не "боевая" программа - просто тест захода в спящий режим. И вот он -- не работает.