Считывание аналогового входа ATtiny13A из режима Power down

Валерий К.

✩✩✩✩✩✩✩
4 Янв 2024
8
1
Здравствуйте, мастеровой народ!

Стоит задача организовать автономный датчик протока воды по пластиковой трубе. TTP223 не устраивал тем, что через 8 секунд выключался, а нужно подавать сигнал пока течет вода.
Часть задачи с определением потока организовал на библиотеке ADCTouch.h. Работает более-менее. Но вот с автономностью беда. Ток покоя 1 мА.
Стал смотреть режимы сна для Тиньки. Загнал тест с Каунт-зеро, запустил, ток покоя 17 мкА, вполне себе. Но вот пытаюсь в этот код загнать свой и не получается... То срабатывает по ватчдогу каждую секунду независимо от того есть сигнал или нет. То вообще спит беспробудно.
Вот точно рабочий пример кода. Неправильно, что я пытаюсь вместо первых строк условия процедуры ISR() вставить свое условие, гораздо большее? Может сначала нужно включить запрет прерывания, а в конце процедуры его снова выключить? Или вообще не здесь нужно вставлять, а в Main()?
Прошу совета... уже много чего перечитал, пытаюсь разбираться с регистрами и прерываниями, но пока туго доходит...

Sleep Mode ATtiny13a:
#include <avr/io.h>
#include <avr/wdt.h> // здесь организована работа с ватчдогом
#include <avr/sleep.h> // здесь описаны режимы сна
#include <avr/interrupt.h> // работа с прерываниями

volatile uint8_t i;
ISR (WDT_vect) {
 if ((++i%4) == 0)
         PORTB |= (1<<PB0); // включаем светодиод
 else
         PORTB &= ~(1<<PB0); // выключаем светодиод

         WDTCR |= (1<<WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
}

int main() {

        DDRB = (1<<PB0); // на этом пине висит светодиод
        i=0;

        //инициализация ватчдога
        wdt_reset(); // сбрасываем
        wdt_enable(WDTO_1S); // разрешаем ватчдог 1 сек
        WDTCR |= (1<<WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
        sei(); // разрешаем прерывания

        set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
        while(1) {
                sleep_enable(); // разрешаем сон
                sleep_cpu(); // спать!
        }
}
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
501
149
Покажите ваш не работающий код. (Минимально возможный вызывающий ошибку)

Так же рекомендуется прочитать даташит на МК - разделы про sleep и WDT
 
Изменено:

Геннадий П

★★★★★★✩
14 Апр 2021
1,975
635
45
1) Для считывания ADC вам нужно выводить контроллер из сна. Во сне ни один контроллер не считывает ADC.
2) Для уменьшения потребления в активном режиме понижайте частоту тактирования.
 

Валерий К.

✩✩✩✩✩✩✩
4 Янв 2024
8
1
Спасибо за быстрый ответ. Честно, я читаю, но то ли к 50 годам тупею понемногу, то ли нужно совсем с азов-азов начинать. Впрочем, нужно и хочется разобраться, но нужны примеры... апноуты Микрочипа сейчас недоступны, как я понимаю...

C++:
#include <avr/io.h>
#include <avr/wdt.h> // здесь организована работа с ватчдогом
#include <avr/sleep.h> // здесь описаны режимы сна
#include <avr/interrupt.h> // работа с прерываниями
#include <ADCTouch.h>
#include <util/delay.h>

// Sample each touch pin 32 times
const uint16_t ADCTouch::samples = 32;

// Touch reference values to zero out the offset
int16_t ref_A2 = Touch.read(A2);

// Touch threshold for turning on or off the LEDs. Lower is more sensitive
const uint8_t threshold = 6;

volatile uint8_t i;

ISR (WDT_vect) {
  if ((++i % 4) == 0) {
    if ((Touch.read(A2) - ref_A2) > threshold) {
      for (int k = 0; k < 4; k++) {
        PORTB |= (1 << PB3); // включаем светодиод
        _delay_ms(50);
        PORTB &= ~(1 << PB3); // выключаем светодиод
        _delay_ms(50);
      }
    }
  }
  else
    PORTB &= ~(1 << PB3); // выключаем светодиод
  WDTCR |= (1 << WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
}

int main() {
  DDRB = (1 << PB3); // на этом пине висит светодиод
  i = 0;
  //калибровка сенсора
  for (int j = 0; j < 10; j++) {
    ref_A2 += Touch.read(A2);
    _delay_ms(10);
  }
  ref_A2 /= 10;

  PORTB |= (1 << PB3); // пищим, что калибровка прошла
  _delay_ms(500);
  PORTB &= ~(1 << PB3); // выключаем

  //инициализация ватчдога
  wdt_reset(); // сбрасываем
  wdt_enable(WDTO_1S); // разрешаем ватчдог 1 сек
  WDTCR |= (1 << WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
  sei(); // разрешаем прерывания

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
  while (1) {
    sleep_enable(); // разрешаем сон
    sleep_cpu(); // спать!
  }
}
 

Валерий К.

✩✩✩✩✩✩✩
4 Янв 2024
8
1
Для эксперимента ввожу не в Power_Down режим, но все равно дальше не идет. Ток 0,3 мА.
C++:
set_sleep_mode(SLEEP_MODE_ADC);
Сейчас попробую выводить из сна ЦПУ, а потом снова усыплять...
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
501
149
Сейчас попробую выводить из сна ЦПУ, а потом снова усыплять...
Если есть работающий скетч. То как вариант - добавляйте в него понемногу, до ошибки.
Приведенный вами скетч (сообщение #4) вообще не компилируется.
Как вы понимаете, что скетч дальше не идет? Может у вас АЦП не выдает нужный сигнал.

Из общих замечаний (Не важных может быть в вашем случае)
  • Не обязательно делать весь обработчик в прерывании, можно писать код после sleep. В вашем случае это не особо важно, но при пробуждении по внешнему сигналу иногда влияет, если сигнал очень короткий по длительности.
  • Если используете длительный по времени обработчик в прерывании, то надо подсчитать, сколько времени он будет выполняться и на что эта длительность может повлиять.
  • На всякий случай сбрасывайте флаг WDRF в самом начале скетча MCUSR = 0; Т.к. он влияет на WDE если вдруг произойдет ресет по WDT
Bit 3 – WDE: Watchdog System Reset Enable
WDE is overridden by WDRF in MCUSR. This means that WDE is always set when WDRF is
set. To clear WDE, WDRF must be cleared first. This feature ensures multiple resets during conditions
causing failure, and a safe start-up after the failure.

- Даташиты есть не только на сайте микрочипа, поиск выдает меного доступных ссылок.

Дополнение.
Разбираться и отлаживать наверное лучше на UNO, выводя в Serial контрольные данные или моргая разными светодиодами.
 
Изменено:

Валерий К.

✩✩✩✩✩✩✩
4 Янв 2024
8
1
Спасибо.
По-поводу прерывания... я думал, что будет проще организовать прерывание по ватчдогу и уже внутри него опрашивать порт, потому что порт сенсорный и, наверное, могут быть флуктуации. С другой стороны, максимум раз в 8 секунд система будет потреблять значительный ток и об энергосбережении уже трудно говорить...
Меня бы вполне устроила сенсорная кнопка ttp223, если бы она через 8 секунд непрерывного воздействия не уходила в power down режим. Говорят, в этих микросхемах до 2017 года такой функции не было...
Даташит я скачал, даже распечатал раздел по регистрам, но пока не врубаюсь до конца. Апноуты - я имел ввиду примеры.

Самый верхний код из статьи на Каунт-зеро. Он работает четко: спит, просыпается, моргает и опять засыпает. Как я понимаю, для установки порта в высокий уровень не нужно ничего и никого ждать? С аналоговым портом такое не пройдёт? Нужна задержка на пробуждение АЦП? И правильно ли в прерывания пользоваться делеями?
Я не прошу сделать за меня. Я прошу дать совет, как организовать работу по чтению порта. Желательно в формате Ардуино, мне пока так понятнее.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
501
149
Я прошу дать совет, как организовать работу по чтению порта.
Я не знаю, как работает ADCTouch.h, сколько надо измерений для стабильного обнаружения и т.д.

Повторю. (Может вы не заметили дополнение, написанное позже)
Разбираться и отлаживать лучше на UNO, выводя в Serial короткие контрольные сообщения и (или) моргая разными светодиодами. Там же можно оценить время выполнения.
И правильно ли в прерывания пользоваться делеями?
В общем случае не рекомендуется. Но можно. Обычно рекомендуется обрабатывать в прерываниях флаги.
Оставьте в прерывании только WDTCR |= (1<<WDTIE);
Остальной код вызывайте после sleep_cpu();
 
  • Лойс +1
Реакции: Валерий К.

poty

★★★★★★✩
19 Фев 2020
3,265
950
delay в прерывании не работает, так же, как millis. micros можно использовать, но с ограничениями.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
501
149
@poty,
У ТС используется
_delay_ms
его можно использовать в прерывании (если надо).
 

Валерий К.

✩✩✩✩✩✩✩
4 Янв 2024
8
1
Спасибо, буду пробовать. К сожалению, программатор не завёлся, Дьюд предлагает обновить фирмваре... все пропаял, проверил, без толку. Пишут, нужен ещё один программатор, чтобы оживить этот).
Пришлось УНО приспособить под программатор для Тиньки. Не получится на ней экспериментировать.
Сколько делал самоделок на ардуинке, все было относительно просто, а тут... полез в дебри) Спасибо, что откликаетесь и не посылаете.
 

Jerej

✩✩✩✩✩✩✩
2 Окт 2022
16
2
Изучал ассемблерную компиляцию делэев!
Это просто вставка кода с зацикливанием по счётчику, где счёт идёт по количеству времени процессора на ассемблерную команду. Считаются и джампы и инкризы регистров...
Короче _delay_ms() прокатит везде, а вот millis() в прерывании сделает так 👋