ATMEGA 8 спящий режим и TIMER 2
- Войдите на сайт для отправки комментариев
Втр, 13/04/2021 - 10:21
Здравствуйте, не могу разобраться с TIMER2. Загоняю атмегу в сон(режим POWER SAVE), от внешнего прерывания она просыпается, а вот от счетчика таймера TIMER2 ни в какую. Посмотрите пожалуйста код, что не так.
#include <MsTimer2.h> #include <avr/sleep.h> #include <avr/wdt.h> #include <avr/interrupt.h> //#include <util/delay.h> #define F_CPU 1000000UL byte flag = 0; byte intFlag = 0; #define ButtonOne 2 #define ButtonTwo 3 volatile int state = LOW; //********************************************************************** void flash() { static boolean output = HIGH; digitalWrite(12, output); output = !output; } void setup(){ //Save Power by writing all Digital IO LOW - note that pins just need to be tied one way or another, do not damage devices! for (int i = 0; i < 20; i++) { if (i != ButtonOne || i != ButtonTwo ) { pinMode(i, OUTPUT); digitalWrite(i, LOW); } } pinMode(12, OUTPUT); MsTimer2::set(500, flash); // 500ms period MsTimer2::start(); pinMode(13, OUTPUT); digitalWrite(13, LOW); pinMode(ButtonOne, INPUT_PULLUP); } //************************************************************************ void loop(){ if (intFlag==1) { state = !state; intFlag=0; } // тут код который должен выполняться при пробуждении ( можно обработать с какой именно кнопки нажата и сделать обработку для каждой кнопки свое действие ) digitalWrite(13, state); ADCSRA = 0; set_sleep_mode (SLEEP_MODE_PWR_SAVE); sleep_enable(); attachInterrupt(digitalPinToInterrupt(ButtonOne), sleepISR1, LOW); // LOW interrupts(); sleep_cpu(); } void sleepISR1() { // Запретить спящий режим, чтобы мы больше не заходили в него, кроме как намеренно, по коду sleep_disable(); //проснулись // код или действие при пробуждении по этому прерыванию if (digitalRead(ButtonOne)==LOW && flag==0 ) _delay_ms(200); { intFlag=1; flag=1; } if (digitalRead(ButtonOne)==HIGH && flag==1 ) { _delay_ms(50); flag=0; //снова заснули } detachInterrupt(digitalPinToInterrupt(ButtonOne)); // Теперь мы продолжаем запуск основной функции Loop () сразу после того, как мы пошли спать }
А разве должно? Таймер 2 только в асинхронном режиме может будить.
Не тот режим .
Нужен режим Idle, а включаешь Power save
gzp13,
Посмотрите даташит. Там (стр. 54) явно сказано, что таймер 2 будит из Power Save только в асинхронном режимет, т.е. когда в ASSR установлен бит AS2. А Вы этого не делаете.
Собственно, Вам это уже сказали в #1
- Вы будите утром свою жену?
- Конечно буду!
Какие то нездоровые ассоциации.))
Спасибо за подсказки, но я так понимаю ассинронный режим это работа только от внешнего кварца? И этот режим включается ASSR =(1<< AS2) ?
Обычно часовой кварц 32 кгц, даже конденсаторы не нужны. Только перед этим нужно переключиться на intrc.
Не очень понял куда переключиться. Тогда мне надо выставлять фьюзы на работу от внешнего кварца?
Хорошо,не получится как я понял мне задействовать режим POWER SAVE, а можно тогда применить режим POWER DOWN с WDT, чтобы WDT срабатывал через 2 часа и выполнялись какие то действия,потом снова засыпал. Пробую включить WDT что то не получается.
wdt_enable(WDTO_1S); //включаем сторожевой таймер со сбросом через 1 секунды
WDTCR |= (1<<WDCE) | (1<<WDE); //разрешение прерываний от сторожевого таймера
В Мега8 нет вектора WDT - только через RESET. Ну и 2 сек максимум.
intrc - это внутренний генератор.
т.е я не смогу реализовать на атмеге8 пробуждение из сна через каждые 2 часа?
т.е я не смогу реализовать на атмеге8 пробуждение из сна через каждые 2 часа?
На 328 максимальный вочдог 8 сек. Когда мне надо спасть 10 минут, я сплю в цикле 600/8 раз. Каждый раз проснувшись, смотрю от чего проснулся. Если от вочдога, ложусь спать дальше. Если же от внешнего прерывания - начинаю обрабатывать его.
Также и Вы можете спать по две секунды в цикле 3600 раз. Не совсем тоже самое, что спасть два часа, конечно, но лучше, чем ничего.
это я понимаю, не могу организовать это в скетче.
А чего там организовывать? Ну, попробуйте, если не получится, выкладывайте, посмотрим.
вот код,в спящий режим входит, но выходит из него по WDT а не по кнопке. Светодиод не загорается через 10сек по прерыванию от WDT. Совсем запутался.
Какой МК?
В любом случае надо не ИЛИ а И
24 if
(i != ButtonOne || i != ButtonTwo ) {
Дальше не проверял.
Не, ну так не делается. Здесь у Вас насажена куча деревьев, за которыми абсолютно не виден лес. Попробуйте всю низкоуровневую байду сложить в отдельные маленькие функции. Тогда, выписывая логику в этих функциях, Вы её (логику) хоть понимать будете.
Лес вроде просвечивается) Логику я понимаю, контроллер спит глубоким сном, WDT работает каждые 2сек и прибавляет счетчик count. Когда выполнится условие count>2 должен загореться светодиод. Но одновременно с WDT работает еще и прерывание INT0, при нажатии на кнопку контроллер тоже должен выйти из режима сна.
Вот так же доджен загораться диод от WDT?
Нет, не должен.
Каждый раз проснувшись, смотрю от чего проснулся. Если от вочдога, ложусь спать дальше. Если же от внешнего прерывания - начинаю обрабатывать его.
А не могли бы вы показать это кусочек кода ?
Да, показать-то нетрудно. ТОлько есть беда.
Вы пишете, что у Вас ATmega8, а потом в посте #19 используете вектор WDT_vect, которого у ATmega8 попросту нет.
Так, с каким контроллером Вы работаете? Для какого Вам нужен кусочек кода? C watchdog? Или без watchdog? Что Вам нужно-то?
про кусочек кода я не писал)Точнее не я писал. Работаю с ATMEGA8. Вот я бы тоже посмотрел на кусочек кода. Никак не могу добиться правильной работы WDT и режима сна. Т.е я не правильно указал имя прерывания от WDT?
Блин,получается у атмеги8 нет вектора прерывания???
Этого - нет. Если нужно не больше 6 ног, возьми тиньку, у нее есть
т.е я не смогу сделать пробуждение атмеги от wdt???
т.е я не смогу сделать пробуждение атмеги от wdt???
От WTD - нет, только перезагрузка. Можно взять тиньку или 328 - там нет проблем.
Ну, или будить от чего-нибудь другого (например, от 555 таймера).
А что у Вас там ещё в проекте есть? А то RTC тоже будить умеют (это их основная работа :-)
Ну я делаю автополив, будет дисплей, датчик почвы,температуры воздуха,мотор который я хочу подключить к LIPO аккумулятору 12В и контроллером измерять напряжение раз в сутки, чтобы не разрядить в ноль. Плюс хочу измерять питание самого контроллера,т.е нужно два аналоговых входа. Я вот думаю может прикрутить часы реального времени DS3231? https://tixer.ru/catalog/modules/rtc-modules/chasy_r_v_rtc_na_ds3231_dlya_raspberry_pi/
Эти подойдут я думаю?
Вообщем вывод по атмеге я сделал такой,для экономичных режимов она подходит только если работать от внешних прерываний, правильно?
Эти подойдут я думаю?
У этого модуля вывода INT нету, но его можно прям с ноги микросхемы взять, там ОК.
Для измерения питания самого контроллера не нужен аналоговый вход.
Модуль часов лучше возьмите нормальный, типа такого https://aliexpress.ru/item/4000004876793.html Он Вам и время посчитает, и разбудит, когда скажете.
На 328 ..... Каждый раз проснувшись, смотрю от чего проснулся. Если от вочдога, ложусь спать дальше. Если же от внешнего прерывания - начинаю обрабатывать его...
если не трудно , могли бы показать эту строчку?
а вообще на будущее,при задействовании большого количества пинов,лучше всего использовать для экономичных режимов атмегу 328?
для реально экономичных ARM или что-то похожее
А все таки если использовать режим SAVE,то можно использовать timer2 ,тогда нужен внешний кварци кварц на 32768кГц, как его нужно подключить?Точнее как подключить понятно, что нужно делать с фьюзами? В ардуино IDE нет прошивки с кварцем такой частоты.
а вообще на будущее,при задействовании большого количества пинов,лучше всего использовать для экономичных режимов атмегу 328?
Из AVR лучше те, которые picoPower - в документации написано. Например, ATtiny85
если не трудно , могли бы показать эту строчку?
Не жалко, только давайте я просто выдеру из готового проекта. Делать работающий пример, правда в лом. Вот смотрите. Это для 328. Функция sleeping спит total раз на время period. Обращаются к ней, например
сама функция и обработчик прерывания
собственно цикл сна в строке №13.
Только прежде, чем её вызывать, нужно убедиться. что ВСЕ пины находятся в понятном состоянии и не собираются меняться, а то она будет просыпаться не от WD, а от чего попало. Я это делаю, но на всякий случай таки обрабатываю ситуацию, если проснулась не от WD - это проверка и цикл в строках №№ 20-25. Т.е. проснулись от левого источника - тут же ложимся спать дальше. WD когда надо - разбудит.
Ну, конечно, перед сном (перед вызовом этой функции) надо выключать всё типа USART, SPI, TWI, таймеры, нехрен им батарейку жрать. Я это делаю вызовом power_all_disable(); ну а потом надо не забыть что надо включить и проинициализировать.
Скажите пожалуйста, зачем вы понижаете тактовую частоту перед сном?
Скажите пожалуйста, зачем вы понижаете тактовую частоту перед сном?
Низачем. Это не единственная лишняя вещь там. Например, выключение цифровых буферов на аналоговых пинах в режиме power down ничего не даёт, т.к. они там и так выключены. Это была заготовка в которую просто были собраны все "выключающие техники". И так и использовалось не особо вникая что нужно, а что не нужно в данном конкретном случае.
Евгений,
спасибо. пару уточнений для себя
1) в строчке 24 по замыслу автора мы просыпаемся от переполнения таймера ватчдога 8с. и только если мы проснулись от ватчдога согласно строчке 25 мы пойдём на следующий for. Но, правильно я понимаю, в случае если у нас отключенны все прерывания таймеры и тд кроме ватчдога то проснуться от чегото левого мы не можем в принципе ?
2) в строчке 16 мы очищаем , записывая ноль, соответсвующий бит в регистре. тут всё понятно. что с ногой на выход, что с флаговым регистром, что с другими (если не всеми) регистрами - 0 это очищаем, 1 это выставляем. Но вот просматривая даташит 328 касательно INTF1, не могу понять две вещи. Флаговый регистр при срабатывании выставляется в 1 а при очищении в 0. вроде всё понятно. но
а) там пишут что он автоматически очищается при срабатывании рутины прерывания. НО, также его можно альтернативно очистить... другими словами я понимаю в ручную имеется ввиду. но для каких случаев нам может понадобится очищать его в ручную если он сам автоматически очищается ? я наверно знаю только об одном случае - когда мы пишем низкоуровневый код с "нейкед" процедурами. есть ли другие случаи ?
б) как выше мы уже видели и читали этот флаг INTF1 при очищении выставляется в 0. НО, как тогда понять строчку в даташите что он может быть очищен записью в него единицы ? ведь запись единицы это поднятие флага
В принципе так, но тут есть нюанс. Я как-то наткнулся на то, за был закрыть SofwareSerial (самогонный аналог), а он, зараза, PCINT настраивает - вот и повод проснуться. В общем, я решил, что "на Аллаха надейся, а верблюда привязывай", мало кто ещё чего неочевидным образом настроит - этот цикл ничего не стоит - пусть типа будет.
В строке №14 мы запрещаем обработку прерываний. Значит, если прерывание прилетит между строками 14 и 16, оно не будет обработано, а флаг будет взведён, чтобы оно обработалось как только sei это разрешит. Вот мы его и "сбрасываем" от греха подальше. Это довольно стандартная практика.
Дружище, какой вариант есть еще для измерения напряжения питания контроллера?
Для измерения питания самого контроллера не нужен аналоговый вход.
Модуль часов лучше возьмите нормальный, типа такого https://aliexpress.ru/item/4000004876793.html Он Вам и время посчитает, и разбудит, когда скажете.
Дружище, какой вариант есть еще для измерения напряжения питания контроллера?
Дружище, какой вариант есть еще для измерения напряжения питания контроллера?
http://gammon.com.au/power - страница большая, поищите на ней через Ctrl+F раздел "Detecting low voltage"