Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как правильно выйти из "спящего режима"
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Jagupop
Махаюсь со своим первым проектом - возникает уйма вопросов, большинство из которых решается не без помощи настоящего форума.
Есть задача. ATTINY2313 "спит". По приходу лог. "0" (хотя, схемотехнически несложно поменять и на "1") на INT0 проц должен проснуться и выполнять определенные функции. В дальнейшем, этот же вывод процессора должен уже будет для этого же сигнала использоваться как вход порта. Вот кусок программы:

sei();
set_sleep_mode (SLEEP_MODE_IDLE);
cli ();
....

Процессор, вроде как не просыпается... хотя не уверен. А как определить? Подскажите, что неправильно в исходнике?

Спасибо!!!
Snaky
Цитата(Jagupop @ Jul 3 2007, 04:17) *
sei();
set_sleep_mode (SLEEP_MODE_IDLE);
cli ();
....

Процессор, вроде как не просыпается... хотя не уверен. А как определить? Подскажите, что неправильно в исходнике?

Видимо WinAVR? Если так, то set_sleep_mode() выбирает режим "сна", но еще не загоняет процессор в сон. Делать надо так:
Код
  set_sleep_mode(SLEEP_MODE_IDLE);    // выбираем "тип сна"
  sleep_enable();    // разрешаем "засыпать"
  ...    // код до засыпания
  sleep_cpu();    // заснуть
  .... // код после просыпания


И еще. Когда прерывание выводит процессор из спящего режима, то прежде чем перейти к обработчику прерывания, процессор выполнит сначала следующую за командой SLEEP команду. Поэтому следующей командой не стоит сразу ставить CLI, если хотите обеспечить обработку прерывания, а лучше поставить NOP.
defunct
Цитата(Snaky @ Jul 3 2007, 05:45) *
а лучше поставить NOP.

Лучше ничего не ставить, а просто правильно построить программу:

Код
main()
{
   set_sleep_mode(xx)
   sei();

   for(;;)
   {
       do_smth();
       sleep();
   }

}
Jagupop
Цитата
main()
{
set_sleep_mode(xx)
sei();

for(;;)
{
do_smth();
sleep();
}


Прошу прощения... А можно "разжевать" построчно - что для чего? Чтой-то недопонимаю. Маловато еще знаний. Спасибо.
defunct
Цитата
А можно "разжевать" построчно - что для чего?

можно.

Код
начало программы

    настроить периферию (порты, ацп, uart и т.п. все с чем собираетесь работать)
    разрешить режим сна (bit SE в MCUCR)
    разрешить прерывания (sei)
    
    Далее бесконечный цикл
10:
         Выполнить какие-то поточные действия
         Уснуть до следующего прерывания
goto 10


При старте программы настраивается периферия, разрешается режим сна и прерывания, выполняются какие-то рутинные действия и проц засыпает на команде sleep.
При возникновении любого прерывания (в режиме Idle) проц проснется, первой инструкцией которую он выполнит будет GOTO 10, потом он войдет в обработчик прерывания которое его пробудило, выполнит обработку прерывания, потом вернется к строчке 10: - выполнит какие-то поточные действия и на команде sleep() снова уснет... и так по кругу.
MSprut
Вообще даташиты рекомендуют выбирать и разрешать режим сна непосредственно перед командой SLEEP.
Jagupop
Прям не знаю...


GIMSK = 0b01000000;

set_sleep_mode (SLEEP_MODE_IDLE);
sleep_enable ();
sei();
sleep_cpu ();
sleep_disable ();
PORTB = 0xFF; // проверяю подключенным светодиодом.

На INT0 появляестя лог. "1" . Не пойму то ли не "засыпает" то ли не "просыпается". Контролирую подключенным к порту B светодиодом. В чем ошибка?
defunct
Цитата(MSprut @ Jul 5 2007, 16:38) *
Вообще даташиты рекомендуют выбирать и разрешать режим сна непосредственно перед командой SLEEP.

Давайте еще и уарт будем инициализировать перед отправкой каждого байта.
Вообще нет таких рекомендаций в даташитах и быть не может.


Цитата(Jagupop @ Jul 5 2007, 21:34) *
На INT0 появляестя лог. "1" . Не пойму то ли не "засыпает" то ли не "просыпается". Контролирую подключенным к порту B светодиодом. В чем ошибка?

Обработчик INT0 у вас есть?
Полный код приведите.

sleep_disable() - делать не нужно.
сам по себе mcu не уснет.
Jagupop
Ну вот полный...

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

#define Freq 4000000

unsigned char z;

int zaziganie (z)
{
char i;

z = 0;
for (i=0; i<60; i+=1)
{
if ((PIND & 0x04) == 0);
else z += 1;
_delay_loop_2 (100);
}
return z;
}


//void presskey (void)


int main (void)
{
DDRD = 0x00;
PORTD = 0xFF;
DDRB = 0b11111100;
PORTB = 0b00000000;
ACSR = 0b00000000;
GIMSK = 0b01000000;
label1:

set_sleep_mode (SLEEP_MODE_IDLE);
sleep_enable ();
sei();
sleep_cpu ();
sleep_disable ();
PORTB = 0xFF;
zaziganie (z);
if (z < 30) goto label1;
_delay_loop_2 (1000);
PORTB = (PINB^0b10010000);
//presskey ();
label2:
zaziganie (z);
if (z > 30) goto label2;
else goto label1;
}
acex2
Цитата(defunct @ Jul 6 2007, 02:38) *
Вообще нет таких рекомендаций в даташитах и быть не может.


Datasheet ATMega88, стр.43:
"To avoid the MCU entering the sleep mode unless it is the programmer’s purpose, it is recommended to write the Sleep Enable (SE) bit to one just before the execution of the SLEEP instruction and to clear it immediately after waking up"
defunct
Jagupop
Проэмулировал вашу программу в железе.
Чип пробуждается по 0 на INT0 и прыгает по адресу 0x0001, оттуда в "аварийный" обработчик, который отправляет его уже по RESET вектору адрес 0x0000, далее повторный запуск main и все. Дальше иструкции sleep естессно код не исполняется, и со стороны видно как-будто чип не пробуждается.

чтобы все работало добавьте в программу хотя бы пустой обработчик Int0
Цитата
SIGNAL (INT0_vect)
{
}


Еще, Int0 - у вас настроен "по уровню", а лучше настроить "по фронту".
Jagupop
ЛЮДИ!!! ЧЕЛОВЕКИ!!! Помогите!!! Задолбался совсем. Ну нихрена не пойму - что не так?



GIMSK = 0b01000000; //разрешение прерываний по входу INT0

for (a=0; a<100; a+=1)

{

_delay_loop_2 (30000); //задержка

}


set_sleep_mode (SLEEP_MODE_IDLE); //выбор типа SLEEP MODE

sleep_mode (); // спи, гад!

sei (); //глобальное разрешение прерываний

ISR (INT0_vect);

PORTB = (PINB^0x08); //включить светодиод 1
cli ();
label1:

goto label1;


С появлением лог. "0" на INT0 должен загореться светодиод. Пробую по-разному. Или не загорается вовсе или загорается сам по себе. Уже махаюсь немеряно времени. Что не так? Не пинайте сильно - учусь, учусь...
Спасибо.
defunct
Цитата(Jagupop @ Jul 10 2007, 02:50) *
Ну нихрена не пойму - что не так?

Я вам написал "что не так" в вашей программе. Вы пост то предыдущий хоть прочитали, прежде чем крик души изливать?
Jagupop
defunct, я Вас пыталсявыловить в ICQ - все безрезультатно. В общем, когда вставляю в программу:

SIGNAL (INT0_vect)
{
}

при трансляции появляются такие warning'и:

main.c: In function `main':
main.c:43: warning: static declaration of '__vector_1' follows non-static declaration
main.c:42: warning: previous declaration of '__vector_1' was here

А результат - тот же.
defunct
Цитата(Jagupop @ Jul 12 2007, 20:03) *
defunct, я Вас пыталсявыловить в ICQ - все безрезультатно.

bb-offtopic.gif
Я только дома аську читаю, уже вам отписал.

Цитата
при трансляции появляются такие warning'и:
main.c: In function `main':
main.c:43: warning: static declaration of '__vector_1' follows non-static declaration
main.c:42: warning: previous declaration of '__vector_1' was here

Вынесите обработчик прерывания из main():

SINGAL (INT0_vect)
{
}

main()
{
..
}
Jagupop
С прерываниями разобрался - проц. по приходу сигнала на INT0 "просыпается", выполняет поставленную задачу и снова "засыпает". Все красиво. Спасибо конференции. НО (!). Есть несколько другая задача, которую я не знаю как решить из-за небольшого опыта. В общем, проц. "спит". На INT0 постоянно сидит лог. 1. При появлении лог. 0 проц должен проснуться и выполнять, что ему указано. При этом на INT0 - лог. 0 держится постоянно. Лишь с появлением на INT0 лог.1 проц. должен выполнить определенные предпмсания и "заснуть" в ожидании очередного лог. 0 на INT0. Вот как это реализовать? Я так понимаю, в процессе работы INT0 должен "превращаться" в PD2? Спасибо.
Pyku_He_oTTyda
Цитата
При появлении лог. 0 проц должен проснуться и выполнять, что ему указано.

Прерывание по спаду уровня(falling edge).
перестраиваем
Перенастроить прерывание по фронту(rising edge) и вот
Цитата
Лишь с появлением на INT0 лог.1 проц. должен выполнить определенные предпмсания и "заснуть" в ожидании очередного лог. 0 на INT0.
Jagupop
Чуток не так... По falling edge проц выходит из спящего режима уходит на подпрограмму обработки прерывания. На INT0 все это время "сидит" лог. 0. Тут все хорошо. Но "заснуть"снова он должен после прихода на INT0 логической единицы! А не перед этим. Как это осуществить? Спасибо.
Pyku_He_oTTyda
если так?
Цитата
По falling edge проц выходит из спящего режима уходит на подпрограмму обработки прерывания.

Цитата
На INT0 все это время "сидит" лог. 0.

Залетаем в прерывание и анализируем наличие"0", если, верно, делаем что либо. Заодно перенастраиваем прерывание по фронту.
При появлении фронта, залетаем в прерывание и снова проверяем наличие "0", его нет соответственно, делаем другое, то есть отправляем спать.
В прерывании лучше много не делать, а устанавливать флаги. Их обрабатывать а программе.
Jagupop
Цитата
Залетаем в прерывание и анализируем наличие"0",


А разве можно в прерывании процессор снова заставить "уснуть"? А куда процессор уйдет после просыпания в этом случае? Разве не на эту же самую подпрограмму обработки прерывания, в которой он и так уже находится?
defunct
Цитата(Jagupop @ Jul 19 2007, 16:17) *
А разве можно в прерывании процессор снова заставить "уснуть"? А куда процессор уйдет после просыпания в этом случае? Разве не на эту же самую подпрограмму обработки прерывания, в которой он и так уже находится?

Один из возможных вариантов:

Код
volatile U8 StateMachine = 0;

SIGNAL(INT0)
{
   StateMachine = 1;
}


main()
{
      ...    
      for(;;)
      {
          switch( StateMachine)
          {
                case 1: // Работать
                     DoSmth(); // выполнять какое-то повторяющееся действие (пока присутсвует лог 0 на Int0)
                     break;
                case 0: // Спать
                default:
                     sleep();
                     break;
           }

           if (PIND & 0x4)  // единица на INT0 - переключение состояния
               StateMachine = 0;
      }
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.