Jagupop
Jul 2 2007, 21:17
Махаюсь со своим первым проектом - возникает уйма вопросов, большинство из которых решается не без помощи настоящего форума.
Есть задача. ATTINY2313 "спит". По приходу лог. "0" (хотя, схемотехнически несложно поменять и на "1") на INT0 проц должен проснуться и выполнять определенные функции. В дальнейшем, этот же вывод процессора должен уже будет для этого же сигнала использоваться как вход порта. Вот кусок программы:
sei();
set_sleep_mode (SLEEP_MODE_IDLE);
cli ();
....
Процессор, вроде как не просыпается... хотя не уверен. А как определить? Подскажите, что неправильно в исходнике?
Спасибо!!!
Цитата(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
Jul 3 2007, 18:03
Цитата(Snaky @ Jul 3 2007, 05:45)

а лучше поставить NOP.
Лучше ничего не ставить, а просто правильно построить программу:
Код
main()
{
set_sleep_mode(xx)
sei();
for(;;)
{
do_smth();
sleep();
}
}
Jagupop
Jul 3 2007, 21:44
Цитата
main()
{
set_sleep_mode(xx)
sei();
for(;;)
{
do_smth();
sleep();
}
Прошу прощения... А можно "разжевать" построчно - что для чего? Чтой-то недопонимаю. Маловато еще знаний. Спасибо.
defunct
Jul 3 2007, 22:01
Цитата
А можно "разжевать" построчно - что для чего?
можно.
Код
начало программы
настроить периферию (порты, ацп, uart и т.п. все с чем собираетесь работать)
разрешить режим сна (bit SE в MCUCR)
разрешить прерывания (sei)
Далее бесконечный цикл
10:
Выполнить какие-то поточные действия
Уснуть до следующего прерывания
goto 10
При старте программы настраивается периферия, разрешается режим сна и прерывания, выполняются какие-то рутинные действия и проц засыпает на команде sleep.
При возникновении любого прерывания (в режиме Idle) проц проснется, первой инструкцией которую он выполнит будет GOTO 10, потом он войдет в обработчик прерывания которое его пробудило, выполнит обработку прерывания, потом вернется к строчке 10: - выполнит какие-то поточные действия и на команде sleep() снова уснет... и так по кругу.
Вообще даташиты рекомендуют выбирать и разрешать режим сна непосредственно перед командой SLEEP.
Jagupop
Jul 5 2007, 18:34
Прям не знаю...
GIMSK = 0b01000000;
set_sleep_mode (SLEEP_MODE_IDLE);
sleep_enable ();
sei();
sleep_cpu ();
sleep_disable ();
PORTB = 0xFF; // проверяю подключенным светодиодом.
На INT0 появляестя лог. "1" . Не пойму то ли не "засыпает" то ли не "просыпается". Контролирую подключенным к порту B светодиодом. В чем ошибка?
defunct
Jul 5 2007, 22:38
Цитата(MSprut @ Jul 5 2007, 16:38)

Вообще даташиты рекомендуют выбирать и разрешать режим сна непосредственно перед командой SLEEP.
Давайте еще и уарт будем инициализировать перед отправкой каждого байта.
Вообще нет таких рекомендаций в даташитах и быть не может.
Цитата(Jagupop @ Jul 5 2007, 21:34)

На INT0 появляестя лог. "1" . Не пойму то ли не "засыпает" то ли не "просыпается". Контролирую подключенным к порту B светодиодом. В чем ошибка?
Обработчик INT0 у вас есть?
Полный код приведите.
sleep_disable() - делать не нужно.
сам по себе mcu не уснет.
Jagupop
Jul 6 2007, 06:38
Ну вот полный...
#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;
}
Цитата(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
Jul 8 2007, 12:59
JagupopПроэмулировал вашу программу в железе.
Чип пробуждается по 0 на INT0 и прыгает по адресу 0x0001, оттуда в "аварийный" обработчик, который отправляет его уже по RESET вектору адрес 0x0000, далее повторный запуск main и все. Дальше иструкции sleep естессно код не исполняется, и со стороны видно как-будто чип не пробуждается.
чтобы все работало добавьте в программу хотя бы пустой обработчик Int0
Цитата
SIGNAL (INT0_vect)
{
}
Еще, Int0 - у вас настроен "по уровню", а лучше настроить "по фронту".
Jagupop
Jul 9 2007, 23:50
ЛЮДИ!!! ЧЕЛОВЕКИ!!! Помогите!!! Задолбался совсем. Ну нихрена не пойму - что не так?
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
Jul 10 2007, 10:03
Цитата(Jagupop @ Jul 10 2007, 02:50)

Ну нихрена не пойму - что не так?
Я вам написал "что не так" в вашей программе. Вы пост то предыдущий хоть прочитали, прежде чем крик души изливать?
Jagupop
Jul 12 2007, 17:03
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
Jul 12 2007, 20:22
Цитата(Jagupop @ Jul 12 2007, 20:03)

defunct, я Вас пыталсявыловить в ICQ - все безрезультатно.
Я только дома аську читаю, уже вам отписал.
Цитата
при трансляции появляются такие 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
Jul 17 2007, 11:09
С прерываниями разобрался - проц. по приходу сигнала на INT0 "просыпается", выполняет поставленную задачу и снова "засыпает". Все красиво. Спасибо конференции. НО (!). Есть несколько другая задача, которую я не знаю как решить из-за небольшого опыта. В общем, проц. "спит". На INT0 постоянно сидит лог. 1. При появлении лог. 0 проц должен проснуться и выполнять, что ему указано. При этом на INT0 - лог. 0 держится постоянно. Лишь с появлением на INT0 лог.1 проц. должен выполнить определенные предпмсания и "заснуть" в ожидании очередного лог. 0 на INT0. Вот как это реализовать? Я так понимаю, в процессе работы INT0 должен "превращаться" в PD2? Спасибо.
Pyku_He_oTTyda
Jul 17 2007, 11:34
Цитата
При появлении лог. 0 проц должен проснуться и выполнять, что ему указано.
Прерывание по спаду уровня(falling edge).
перестраиваем
Перенастроить прерывание по фронту(rising edge) и вот
Цитата
Лишь с появлением на INT0 лог.1 проц. должен выполнить определенные предпмсания и "заснуть" в ожидании очередного лог. 0 на INT0.
Jagupop
Jul 19 2007, 12:26
Чуток не так... По falling edge проц выходит из спящего режима уходит на подпрограмму обработки прерывания. На INT0 все это время "сидит" лог. 0. Тут все хорошо. Но "заснуть"снова он должен после прихода на INT0 логической единицы! А не перед этим. Как это осуществить? Спасибо.
Pyku_He_oTTyda
Jul 19 2007, 12:43
если так?
Цитата
По falling edge проц выходит из спящего режима уходит на подпрограмму обработки прерывания.
Цитата
На INT0 все это время "сидит" лог. 0.
Залетаем в прерывание и анализируем наличие"0", если, верно, делаем что либо. Заодно перенастраиваем прерывание по фронту.
При появлении фронта, залетаем в прерывание и снова проверяем наличие "0", его нет соответственно, делаем другое, то есть отправляем спать.
В прерывании лучше много не делать, а устанавливать флаги. Их обрабатывать а программе.
Jagupop
Jul 19 2007, 13:17
Цитата
Залетаем в прерывание и анализируем наличие"0",
А разве можно в прерывании процессор снова заставить "уснуть"? А куда процессор уйдет после просыпания в этом случае? Разве не на эту же самую подпрограмму обработки прерывания, в которой он и так уже находится?
defunct
Jul 19 2007, 15:08
Цитата(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;
}
}
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.