Доброго времени суток всем! Нужна Ваша помощь с простой задачкой - МК, на одном пине (PB3) которого - кнопка, на другом (PB4) - светодиод. Замыкаем кнопку -светодиод загорается на 4 секунды. Потом гаснет, независимо от состояния кнопки. А главное - пока кнопка не нажата - МК должен пребывать в глубоком сне и не жрать почти ни капли тока.
Собственно код:
Код:
#include <avr/io.h> // инициализация портов ввода-вывода МК #include <avr/wdt.h> // здесь организована работа с ватчдогом #include <avr/sleep.h> // здесь описаны режимы сна #include <avr/interrupt.h> // работа с прерываниями #include <avr/delay.h> // описание программных задержек
// Обработчик прерываний ISR (WDT_vect) { WDTCR |=_BV(WDE); // разрешаем прерывания по ватчдогу, иначе будет резет! }
// Основная программа int main() {
// Инициализация порта кнопки (PB3) DDRB &=~_BV(PB3); // ставит в DDRB в бит PB3 - "0" (инициирует его работу как "вход") PORTB |= _BV(PB3); // ставит в PORTB в бит PB3 - "1" (при замыкании пина на землю она становится нулем, при размыкании - еденицей)
// Инициализация цикла контроля ложного включения светодиода while ((PINB & (1 << PB3)) == 0) { // пока кнопка нажата (после завершения цикла включения светодиода)... PORTB &= ~_BV(PB4); // ...светодиод не горит (до отключения, и последующего включения кнопки) }
};
// Инициализация ватчдога wdt_reset(); // сброс wdt_enable(WDTO_120MS); // разрешение ватчдога раз в 120мс WDTCR |= _BV(WDE); // разрешение прерываний по ватчдогу (иначе будет резет)! sei(); // разрешение прерывания
// Инициализация режима сна set_sleep_mode (SLEEP_MODE_PWR_DOWN); while(1) { sleep_enable(); // разрешение режима сна sleep_cpu(); // активация режима сна } }
Я понимаю что код - не ахти (с МК вожусь считанные месяцы, через раз, по выходным), но в протеусе - работает как надо. А вот в реале - светодиод моргает непрерывно, пока нажата кнопка. Помогите пожалуста разобраться - где косяк?
1. Кнопка на вход прерывания по низкому уровню. Только прерывание низким уровнем разбудит МК из глубокого сна. 2. В векторе прерывания по низкому уровню отключаем IRQ по уровню чтоб постоянно не молотил, переключим на "по фронту" или вообще отключим если будем потом мониторить статус кнопок софтварно. Запускаем антидребезг кнопки(например таймер). 3. Когда отработал антидребезг реагируем на события(включаем светомузыку, лампочки, биперы и делаем что надо). 4. Ждем/ничего не делаем пока нажата кнопка. 5. Когда отпустили кнопку ждем антидребезг и снова разрешаем прерывание по низкому уровню, усыпляем проц.
Для прерывания по низкому уровню вход дожен быть подтянут резистором ввех, кнопка замыкает на землю. Можно параллельно кнопке малый кондер добавить чтоб от наводок всяких избавиться.
а кнопку будут держать дольше 4 секунд или не обязательно?
В том то и дело что дольше. Поэтому у меня такой кривоватый код в итоге получился.
Дребезг мне кажется тут маловероятен - подтягивающий резистор имеется, а кнопка - на самом устройстве там оптопара, и проверял я его зажигая светодиод оптопары от батарейки, то есть как мне представляется - там все достаточно стабильно.
А насчет IRQ - честно сказать не просвещен пока. В свое время удачно получилось режим глубокого сна организовать именно на Тини13 - power down. В этом режиме там почти все обесточено в МК, только независимо тактируемы вочдог фурычит. Вот от него то я и плясал. Поэтому и прерывания все - по вачдогу. Благо в Тини он несколько более широкими возможностями наделен, нежели в Мегах.
Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества.
тогда вообще зачем здесь микроконтроллер?))) одновибратор на 4 секунды, а кнопка включает питание одновибратора))) если обязательно с микроконтроллером, то можно аналогично кнопкой рулить питанием тиньки13, а в программе написать тупо:
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Товарищь, который меня попросил это сделать как раз с одновибратора и начинал, но у него что-то там не срослось. Вот он слезно попросил меня попробовать на МК. Плюс - тот самый режим энергосбережения. Схема по его задумке должна вечность пахать от батарейки.
Код:
LedOn(); delay_ms(4000); LedOff(); while(1);
вообще у меня практически это и сделано. Но что-то не работает оно как надо.
Будить МК по внешнему прерыванию у меня пока получается только из режима Idle. И этот вариант я оставил на крайний случай, если так не выйдет ничего. Из Power-Down так будить вообще не получится (если я правильно все понял), так как все лишнее обесточено. Остается только ватчдог. Да уже и бог бы с ним - просто интересно, в чем у меня-то проблема? В целях повышения образованности, так сказать, хотелось бы разобраться. Тем более что в симуляции все как надо работает...
ATTINY13 можно будить из powerdown либо watchdog-ом как Вы делаете, либо низким уровнем, но только на входе INT0, т.к. только при этом низкий уровень отслеживается асинхронно. Первый подход приводит к гораздо большему токопотреблению, по ДШ около 6 мкА при питании от 5в.
// Инициализация прерываний по INT0 GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1 MCUCR = 0b00000000; // при перепаде низком уровне на PB1 sei(); // Общее разрешение прерываний
// Инициализация режима сна set_sleep_mode (SLEEP_MODE_PWR_DOWN); while(1) { sleep_enable(); // разрешение режима сна sleep_cpu(); // активация режима сна } }
В симуляции работает (хотя это видимо не многого стоит) - подскажите, нет ли опять каких явных ошибок?
Также возник вопрос - почему перестала работать конструкция:
И еще - в обработчике прерывания пришлось опять вставить цикл, ждущий когда будет отпущена кнопка на PB1 (то же самое что мне не нравилось в предидущей версии программы). И все это время МК будет в нормальном режиме работать, а не энергосберегающем, можно ли как-то избавиться от этого? Все мои попытки привели пока только к тому что светодиод не гаснет, пока нажата кнопка...
// Обработчик прерываний INT0 SIGNAL(SIG_INTERRUPT0) // Прерывание по низкому уровню на PB1 {
PORTB |= _BV(PB4); // Выставить на PB4 - "1"
disable_int0(); //отключить INT0 IRQ, обязательно иначе тутже сюда залетим снова enable_timer1(); //включить таймер на 4 сек have_int0 = TRUE;//флаг было прерывание, можно пойти в IDLE }
// Обработчик прерываний TIM1 interrupt TIMER1_OVF_IRQ // 4 сек прошло - залетели сюда { PORTB &= ~_BV(PB4); // Выставить на PB4 - "0"
disable_timer1();// отключить TIM1 enable_int0(); // включить прерывание по низкому уровню goto_sleep = TRUE; //теперь можно полностью отключиться }
// Основная программа int main() { device_init();//настройка портов и периферии while(1) { if( have_int0 == TRUE ) { have_int0 = FALSE; sleep_idle();//усыпить в IDLE чтоб меньше жрало, но периферия работает }; if( goto_sleep == TRUE ) { goto_sleep = FALSE; sleep_power_down();//теперь все совсем отключено }; } }
uk8amk, спасибо! А насчет PORTB &= ~_BV(PB4); не подскажете? Почему оно вдруг перестало нормально работать? Разве это не то же самое что и PORTB = 0b11101111;??? Я проверил - дело именно в PORTB, а не DDRB.
Спасибо! Вроде разобрался. Вот еще задумался - я в самом начале фьюзы оставил все по дефолту. Только вотчдог разрешил. Старший байт - все 1. (Внутренний RC-генератор 9.6МГц; Задержка запуска: 14 тактов + 64мс) Младший байт: SPIOEN - 0; EESAVE -1; WDTON - 0; CKDIV8 - 0; SUT1 - 1; SUT0 - 0; CKSEL1 - 1; CKSEL0 - 0;
Заголовок сообщения: Re: ATTiny13 - помогите разобраться со sleep-mode!
Добавлено: Сб янв 06, 2018 20:45:27
Сверлит текстолит когтями
Карма: 9
Рейтинг сообщений: 19
Зарегистрирован: Ср мар 10, 2010 22:28:34 Сообщений: 1248 Откуда: Запад Беларуси
Рейтинг сообщения:0
Написал прошивку под этот контроллер, чтобы отправлял частоту в радиомодуль по I2C. Большую часть времени он будет ждать, когда нажмут на кнопку. Хочу загнать его в sleep mode, чтобы не молотил впустую. Никак не могу с ним разобраться. Контроллер не отправляет данные в TEA5767. Спойлер
Схема во вложении. Хочу сделать всё сразу, т.к. выпаивать микру очень неудобно, а надо прошивать "Тритоном", т.к. Reset используется как порт. Всё работает только когда отправляю в Idle режим. Как правильно настроить PCINT, чтобы правильно срабатывали кнопки? Чтобы можно было отправлять в PWR_DOWN.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения