SapegoAL 0 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба Не ругайте сильно и не отсылайте пожалуйста к литературе. Перечитал всё что мог, но не смог разобраться полностью. Наверное тупею с годами. К тому же не очень очевидно, ну и хочу заметить себе в оправдание, что IAR жутко скупится на примеры. Те же примеры которые я нашёл, оставили некоторые вопросы. Сначала опишу задачу. Может её кто по другому решал и я зря огород горожу. Стоит M8. Обслуживает некоторые датчики и часы реального времени. На вход Int0 поступает сигнал от внешнего (не батарейного) питания. Мне надо чтобы она заснула как можно быстрее. Опрос не проходит, так как в теле очень много временных интервалов формируется и везде вставлять выход на точку засыпания не получается. Короче формирую прерывание по провалу питания. Хочу из обработчика прерывания перейти на сон. Естественно с сохранением стеков. Остальное не волнует. После сна инициализация по новый. Вопросы такие 1) возможно ли это (написано что из более высокоуровневой только). 2) Как это сделать я пробую так .... // Голова. Вот сюда я хочу перейти по провалу питания setjmp(Adr_sleep); if((INT0_PIN & (1<<INT0))==0) { // При нормальном питании - не выполнять // Вырубание переферии для уменьшения потребления ...... ...... #pragma vector=INT0_vect // Пропадание питания __interrupt static void Power(void) { //========================================= if((INT0_PIN & (1<<INT0))==0){ PWR_BAT_ON; // Если питание пропало, то включить батарейку #if __ATmega88__ EIMSK=0; // прерывание от INT0 запретить #else GICR=0x0; // прерывание от INT0 запретить #endif longjmp(Adr_sleep,1); // И перейти на сон } } .... Пожалуйста не обращайте внимание на мелочи. Просто правлю по живому. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба 1. на IAR не надо пенять не должен он содержать примеры по чистому "C" - рискну :) отослать к литературе. 2. Выпрыгивать хрен знает куда из обработчика прерывания это сильно "задумано" :(. Естественно абсолютно неработоспособно. Пожалуйста не обращайте внимание на мелочи К вопросу о мелочах: В давние времена когда компьютеры были большими а железо которым они управляли было очень большое и тупое, один коллега за несколько часов до торжественной сдачи объекта начиненного герконовыми реле коммутирующими "вcухую" по 7,5A решил слегка подправить программу.... Фраза произнесенная им после залипания нескольких сотен герконов стала крылатой - "Странно, один бит и ничего не работает". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prottoss 0 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба ... Возможно, есть смысл из прирывания прыгать не куда то а на NULL? То бишь, при начальной инициализации, проверять все что надо проверять, и потом делать выводы, спать или работать... По крайней мере тогда о стеке можно забыть... Пока сочинял текст, еще одно решение пришло на ум: 1. Пишем подпрограмму: void MySleep(void){ SPEEP(); /* asm("sleep") */ } 2. При анализе в прерывании, если надо заснуть топим в стек адрес MySleep: UCHAR ha = HIBYTE((UINT16)MySleep); UCHAR la = LOBYTE((UINT16)MySleep); PUSH(ha); PUSH(la); И приспокойно выходим из прерывания, ни чего при этом не ломая Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба я пробую такА что мешает засыпать прямо в прерывании? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prottoss 0 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба я пробую такА что мешает засыпать прямо в прерывании?Интересно, а если заснуть в прерывании, разве разве может МК проснуться??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба я пробую такА что мешает засыпать прямо в прерывании?Интересно, а если заснуть в прерывании, разве может МК проснуться??? Хм. В остальных встречавшихся мне процессорах мог. Причем в зависимости от того запрещены или разрешены прерывания глобально он после выхода из спячки либо выполнял обработчик прерывания либо просто продолжал выполнение с команды после sleep. В доке на мегу8 об этом ничего не нашел кроме фразы If an enabled interrupt occurs while the MCU is in a sleep mode, the MCU wakes up. The MCU is then halted for four cycles in addition to the start-up time, it executes the interrupt routine, and resumes execution from the instruction following SLEEP И если понятие "enabled interrupt" выводить как противоположность от If the Global Interrupt Enable bit is cleared, none of the interrupts are enabledто выходит что при глобально запрещенных прерываниях не проснется никогда, что само по себе странно и неестественно. Надо будет проверить это на живом проце. Однако даже это не мешает перед засыпанием запретить прерывание, в обработчике которого находимся и глобально разрешить прерывания. После выхода из спячки и исполнения разбудившего обработчика делаем обратное - запрещаем глобально и разрешаем текущее прерывание. Не забыть только что стека потребуется для обоих обработчиков - текущего и будильника. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prottoss 0 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба я пробую такА что мешает засыпать прямо в прерывании?Интересно, а если заснуть в прерывании, разве может МК проснуться??? Хм. В остальных встречавшихся мне процессорах мог. Год назад я проводил подобные опыты с ATtiny2313 - и помнится программа умирала после sleep в прерывании... по моему Однако даже это не мешает перед засыпанием запретить прерывание, в обработчике которого находимся и глобально разрешить прерывания. После выхода из спячки и исполнения разбудившего обработчика делаем обратное - запрещаем глобально и разрешаем текущее прерывание. Не забыть только что стека потребуется для обоих обработчиков - текущего и будильника. А не проще ли сделать, как я выше предложил с записью в стек программ адреса sleep? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба А не проще ли сделать, как я выше предложил с записью в стек программ адреса sleep?В стек возвратов. Да, наверное проще, но есть недостаток - оптимизатор может объединить некоторые куски обработчика в подпрограммы и запись в стек возвратов может оказаться внутри одной (а может и не одной) из таких подпрограмм. Тогда мы подменим не адрес возврата из обработчика, а адрес возврата из такой подпрограммы. И ситуация может меняться от добавления/удаления одной команды. Придется вручную контролировать куда попадает запись после каждой компиляции, что утомительно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prottoss 0 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба А не проще ли сделать, как я выше предложил с записью в стек программ адреса sleep?В стек возвратов. Да, наверное проще, но есть недостаток - оптимизатор может объединить некоторые куски обработчика в подпрограммы и запись в стек возвратов может оказаться внутри одной (а может и не одной) из таких подпрограмм. Тогда мы подменим не адрес возврата из обработчика, а адрес возврата из такой подпрограммы. И ситуация может меняться от добавления/удаления одной команды. Придется вручную контролировать куда попадает запись после каждой компиляции, что утомительно. Это будет только в том случае, если компилятор решит операторыUCHAR ha = HIBYTE((UINT16)MySleep); UCHAR la = LOBYTE((UINT16)MySleep); PUSH(ha); PUSH(la); загнать в подпрограмму и вызывать через call... Конечно, не самый лучший выбор, во всяком случае куда лучше чем прыжок неизвесно куда Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 24 января, 2007 Опубликовано 24 января, 2007 · Жалоба 2 prottoss подставить адрес возврата, - я такое делал на асме для x51 в структуре типа case. Экономилось много памяти. ret - 1 байт, jmp - 2-3. На Си мягко говоря не очень будет смотреться. На мой взгляд. Прога работает. В общем то. Но хочется лучше, как всегда. Тут в соседней ветке у человека Tiny13 мрут как мухи :) (по его словам 10 циклов перезаписи) так он отвечает что ему на ночь от 5 до 10 штук требуется. :) Я так понимаю это отладка уже. Я не так силён. В том плане, что за ночь могу разных версий штуки три рабочих выдать. Ну и 10 переписываний мне за глаза. :) Это я zltigo обращаюсь. Я понимаю что значит один бит. Без ошибок конечно не обходится, но при возникновении работоспособность восстанавливаю быстро. Ну там веду штук 10 последних версий (для отката) проверяю по частям, прежде чем заливать проверяю раз несколько. :) Переход в 0 пробовал, правда после просыпания. Хотя какая разница соб-сно. Смысл в том что у меня часы. Так во время сна они тикают. Ну и структура со временем реальным __no_init. Уж не знаю как, но если перезапуск делаю, то адрес этой структуры текёт. Минуты становятся секундами и т.д. Не стал разбираться, по тому как это мне тоже не очень нравится. Хотелось бы максимально в рамках языка. Ладно попробую в прерывании. Разрешение не фокус сделать на сон грядущий, а прерывания от Int0 (пропадание питания) я и так запрещаю, так как судя по даташиту, если я правильно понял, только по уровню работает. Подал внешнее питание ч/з диод шотки, батарейка CR2032 на прямую, а землю батарейки корочу транзистором КП505 об землю по сигналу с порта. Кондёра 500мкФ хватает чтобы включить. Пробую так. Но общий вывод неутишительный. Практически Mega8 не предназначена для использования в качестве часов реального времени, что и подтверждают ответы других несчастных. M88 намного лучше, и вроде проблем нет, но теперь у меня уже мондраж. Я хочу солидный запас иметь. И спать спокойно. Дополнительная обвеска микрухи, для того чтобы она работала без DS1307 получается дороже самой DS1307. Повоюю ещё день, и если нет то откажусь. В новых платах предусмотрю DS1307. Спасибо всем откликнувшимся. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться