ATtiny85 не выходит из сна

Мой ATtiny 85 не просыпается!

Назначение устройства состоит в том, чтобы контролировать геркон и выдавать выходной импульс 20 мс при каждом попеременном положительном переходе входа геркона. Устройство должно перейти в спящий режим после 30 секунд бездействия. Он должен просыпаться при срабатывании геркона (подъеме или падении края).

/*
          ATMEL ATTINY 85
              +-\/-+
        PB5  1|    |8  Vcc
        PB3  2|    |7  PB2 (INT0) reed switch input (1 MΩ ext. pull-up)
        PB4  3|    |6  PB1        output
        GND  4|    |5  PB0 
              +----+
*/
#include <avr/sleep.h>
#include <avr/power.h>
#include <elapsedMillis.h>

const int hallPin = 2;            // Геркон в данном случае.
const int magnetPin =  1;         // Вывод.
const long debouncing_time = 15;  // Время снятия в миллисекундах.

volatile int hallState = 0;       // переменная для хранения счетчика холла
volatile bool hallMem = 0;        // Одноразовая память.
volatile unsigned long last_micros;

elapsedMillis timer;

void setup(){
  pinMode(magnetPin, OUTPUT);
  pinMode(hallPin, INPUT);
  // Присоединить прерывание к вектору ISR. НУЖНО ЛИ МНЕ ЭТО?
// attachInterrupt(0, pin_ISR, RISING); //по умолчанию вывод interupt всегда равен 0 на ATtiny85 (физический вывод 7).
  timer = 0;                             //Сброс таймера
}

void loop(){
  if(digitalRead(hallPin) && !hallMem){
    hallMem = true;               // Одноразовая память.
    hallState++;
    delay(debouncing_time);       // Keep it simple.
    timer = 0;
  }
  if(!digitalRead(hallPin)){
    hallMem = false;              // Разрешить повторный триггер.
  }
  if(hallState > 1) {
      digitalWrite(magnetPin, HIGH);        // Отправить импульс 20 мс на катушку активации датчика.
      delay(20);
      digitalWrite(magnetPin, LOW);
      hallState = 0;                        // Сброс триггера.
  }
  if(timer >= 30000) {                      // Нет активности.
    system_sleep();
  }
}

// От http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
  GIMSK |= _BV(PCIE);                     // Включить прерывания смены выводов
  PCMSK |= _BV(INT0);                     // Использовать INT0 (PB2) в качестве вывода прерывания
  ADCSRA &= ~_BV(ADEN);                   // ADC off
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // заменяет вышеприведенный оператор

  sleep_enable();                         // Устанавливает бит включения сна в регистре MCUCR (БИТ SE).
  sei();                                  // Включить прерывания
  sleep_cpu();                            // сон

  cli();                                  // Отключить прерывания
// PCMSK &= ~_BV (INT0); // Отключить INT0 (PB2) как вывод прерывания
  sleep_disable();                        // Clear SE bit
  ADCSRA |= _BV(ADEN);                    // ADC on

  sei();                                  // Включить прерывания  
  
  timer = 0;          // Сброс таймера сна при пробуждении.
}

ISR(PCINT0_vect) {
}

Может ли кто-нибудь заметить мою ошибку, которая мешает пробуждению?

Что делает инструкция включения АЦП? Нужно ли мне это?

Большое спасибо.

, 👍2

Обсуждение

Попробуйте заменить PCMSK |= _BV(INT0); на PCMSK |= _BV(PCINT2).;, @gbg

@gbg, это, кажется, что-то делает, спасибо. Я собираюсь добавить "Пробужденный", чтобы я мог контролировать состояние сна. В Ирландии пора спать., @Transistor


1 ответ


Лучший ответ:

3

Я считаю, что ваша проблема заключается вот в чем:

PCMSK |= _BV(INT0);  // Использовать INT0 (PB2) в качестве вывода прерывания

Похоже, вы перепутали два вида прерываний:

  1. INT0 (внешнее прерывание), которое работает только на выводе INT0 (т. Е. PB2) и может воспринимать низкоуровневый, восходящий край, падающий край или любые изменения.

  2. PCINT0 (прерывание смены pin), которое работает на любом выводе ввода-вывода, но может воспринимать только “любое изменение”.

Поскольку вы спите в режиме PWR_DOWN, прерывание смены pin является подходящим выбором. Вся ваша программа согласуется с этим выбором, но для строки выше.

Макрос INT0 имеет значение 6. Он представляет собой бит 6 GIMSK, который используется для включения прерывания INT0. Не то, что ты хочешь. Бит 6 PCMSK зарезервирован, поэтому вы не должны прикасаться к нему. Если вы хотите , чтобы прерывание смены pin воспринимало изменения в pin PB2 (он же PCINT2), вам необходимо:

PCMSK |= _BV(PCINT2);  // изменения смысла в PCINT2 = PB2
,

Спасибо за ясное объяснение. Теперь это работает. Могу ли я опустить строки "ADCSRA", поскольку я не использую никаких аналоговых функций?, @Transistor

@Transistor: Действительно, можете., @Edgar Bonet