Библиотека LowPower: Powerdown (сон) ATMega32u4 работает, но пробуждения не происходит

Ситуация:

Я сделал / разработал этот контроллер (со многими функциями) с использованием Pro Micro (ATMega32u4) и хочу расширить его с помощью функции пробуждения при прикосновении к нему (с использованием сенсорного датчика). Это все для экономии энергии, когда не используется. Таким образом, когда устройство поднято / затронуто, устройство проснулось. Когда контакта нет, через некоторое время он засыпает. Расстояние до сенсорного датчика будет увеличено с помощью маленькой медной полоски вокруг корпуса.

Изображение устройства:

Изображение устройства

Я использую вывод 9 сенсорного датчика и вывод 16 ИК-датчика, чтобы проснуться, но он не работает. Обе функции устройства работают нормально, я могу прочитать состояние касания (низкий = нетронутый или высокий = касанный), и я могу получать ИК-команды, потому что оно уже полностью реализовано. При получении сигнала эти контакты будут высокими в течение некоторого периода.

Программный вопрос:

Что-то не так с моим кодом (неверные параметры?)? Устройство переходит в спящий режим при выполнении этого кода (но никогда не просыпается):

#include <avr/sleep.h>         // To enter sleep mode, save power
#include <LowPower.h>          // To enter sleep mode, save power 

......

#define TEP_IR_RECV_PIN         16
#define TEP_PIN_TOUCHSENSOR     9

......
......

void sleep()
{
  attachInterrupt( TEP_PIN_TOUCHSENSOR, wakeup, HIGH );
  attachInterrupt( TEP_IR_RECV_PIN, wakeup, HIGH ); 

  // Enter power down state with ADC and BOD module disabled.
  // Wake up when wake up pin is high.
  LowPower.powerDown( SLEEP_FOREVER, ADC_OFF, BOD_OFF );

  // Disable external pin interrupt on wake up pin.
  detachInterrupt( TEP_PIN_TOUCHSENSOR );
  detachInterrupt( TEP_IR_RECV_PIN ); 
}

Функция Sleep моего класса EnjoyPad (будет срабатывать при нажатии кнопки питания на пульте дистанционного управления или при достижении тайм-аута, если не трогать или ничего не делать):

void TEnjoyPad::setSleepMode()
{
  // Notify user device entering sleep mode, beep twice
  setBeep( 200 );
  setBeep( 200, 100, false );

  // To be sure: Trigger end / unhandled down events and reset states
  reset(init);

  // Handle sleep event
  eventSleep();

  // Stop all peripherals
  end();

  // Finally go to sleep, code stops here
  TEP_LIB_FUNCS::sleep();

  // Device woke up
  setBeep( 500, 100, false );

  // Restart all peripherals
  begin();

  // Handle wake up event
  eventAwake();
}

Есть идеи, что может быть не так? Если мне нужно изменить контакт для датчика касания, это возможно, но я хочу быть уверенным, что это правильный контакт, потому что мне нужно припаять его (не на макете). Осталось пинов: 10, 14 и A3

ВНИМАНИЕ: Я проверил, с заменой задержки вместо того, чтобы идти спать, функции после сна работают просто отлично. Я слышу звуковой сигнал, и устройство снова включается. После сна () нет проблем с кодом, он просто не хочет просыпаться.

1 ответ

Решение

Хорошо, я понял это сам. Кажется, что контакт 9 и контакт 16 не могут быть использованы с attachInterrupt(), поэтому он никогда не будет работать. Также использование не было правильным, это должно быть что-то вроде этого:

attachInterrupt( digitalPinToInterrupt( TEP_PIN_TOUCHSENSOR ), wakeup, HIGH );

Пришла идея использовать прерывание смены булавки, чтобы разбудить устройство, и это, кажется, работает. Тем не менее, восстановление из спящего режима не может восстановить все периферийные устройства без сбоя, поэтому он требует аппаратного сброса, он должен начинаться с нуля. Также из-за изменений во время сна, например, отсоединение кабеля от компьютера (он также имеет батарею) и потеря USB-соединения. Не все классы, которые я использую, являются моими и не оптимизированы для таких вещей при отключении питания.

В любом случае, я изменяю код на это, просто чтобы показать вам изменения, может быть, это может помочь другим:


#include <LowPower.h>          // To enter sleep mode, save power 
#include <avr/wdt.h>           // For watchDog device reset


......

#define TEP_IR_RECV_PIN         16
#define TEP_PIN_TOUCHSENSOR     9

    ......
    ......

namespace TEP_LIB_FUNCS
{

void pciSetup(uint8_t iPin)
{
    *digitalPinToPCMSK( iPin ) |= bit( digitalPinToPCMSKbit( iPin ) );  // enable pin
    PCIFR|= bit( digitalPinToPCICRbit( iPin )); // clear any outstanding interrupt
    PCICR|= bit( digitalPinToPCICRbit( iPin )); // enable interrupt for the group
}

#if defined( TEP_PIN_TOUCHSENSOR )
 #if TEP_PIN_TOUCHSENSOR >= 8 && TEP_PIN_TOUCHSENSOR <= 13 
 ISR(PCINT0_vect) 
 {    
  #define TEP_SLEEP_WAKEUP_PIN_ENABLED 0 
  // Event handler for pins: D8 to D13 
  // Pin change wakeup event handler, does nothing but is required. 
  // Do not remove this.
 } 
 #elif defined(A0) && defined(A5) && TEP_PIN_TOUCHSENSOR >= A0 && TEP_PIN_TOUCHSENSOR <= A5 
 ISR(PCINT1_vect) 
 {    
  #define TEP_SLEEP_WAKEUP_PIN_ENABLED 1 
  // Event handler for pins: A0 to A5 
  // Pin change wakeup event handler, does nothing but is required. 
  // Do not remove this.
 } 
 #elif TEP_PIN_TOUCHSENSOR >= 0 && TEP_PIN_TOUCHSENSOR <= 7 
 ISR(PCINT2_vect) 
 {    
  #define TEP_SLEEP_WAKEUP_PIN_ENABLED 0 
  // Event handler for pins: A0 to A5 
  // Pin change wakeup event handler, does nothing but is required. 
  // Do not remove this.
 } 
 #endif
#endif

void sleep()
{
  // Possible pins Micro, Leonardo, other 32u4-based:  0, 1, 2, 3, 7.
  // Because we use all pins already by other functions, we cannot
  // use attachInterrupt(), it doesn't work.
  // see also: https://www.arduino.cc/en/Reference/AttachInterrupt
  // Instead of this we use a change event interrupt to wake up 
  // the device from sleep state.  
  //
  // The device can be woke up by using:
  // - The reset button
  // - The touch sensor

  // Okay, lets go
  // We enable interrupts here to be sure it is going to work
 interrupts();

 #ifdef TEP_SLEEP_WAKEUP_PIN_ENABLED
  // Set pin change interrupt enabled for sensor pin
  // (See also https://playground.arduino.cc/Main/PinChangeInterrupt)
   // old code: attachInterrupt( digitalPinToInterrupt( TEP_PIN_TOUCHSENSOR ), wakeup, HIGH );
   // old code: attachInterrupt( digitalPinToInterrupt( TEP_IR_RECV_PIN ), wakeup, HIGH ); 
  pciSetup( TEP_PIN_TOUCHSENSOR );
 #endif

 // Enter power down state with ADC and BOD module disabled.
 // Wake up when wake up pin has changed.
 LowPower.powerDown( SLEEP_FOREVER, ADC_OFF, BOD_OFF );

 // Disable external pin interrupt on wake up pin.
  // old code: detachInterrupt( TEP_PIN_TOUCHSENSOR );
  // old code: detachInterrupt( TEP_IR_RECV_PIN ); 
}


 void softReset()
 {
   wdt_enable(WDTO_15MS);  
   while(true) {}
 } 

  // Function Implementation
 void init(void)
 {
   MCUSR = 0;
   wdt_disable();
 }

} // end namespace TEP_LIB_FUNCS

А также функция сна моего класса EnjoyPad (будет срабатывать при нажатии кнопки питания на пульте дистанционного управления или при достижении тайм-аута, если не трогать или ничего не делать):

void TEnjoyPad::setSleepMode()
{
  // Notify user device entering sleep mode, beep twice
 setBeep( 200 );
 setBeep( 200, 100, false );

  // To be sure: Trigger end / unhandled down events and reset states
 reset(init);

  // Shut down any 
 broadcastSleepMode();

  // Handle sleep event
 eventSleep();

  // Stop all peripherals
 end();

  // Turn off onboard led
 digitalWrite( 13, LOW );
 pinMode( 13, INPUT ); 

  // Finally go to sleep, code stops here
 TEP_LIB_FUNCS::sleep();

  // Device woke up
 setBeep( 500, 100, false );

  // Handle wake up event
 eventAwake();

  // Restart whole device, start from scratch.
  // This seems to be the best way to guarantee all 
  // peripherals will be initialized properly
  // and without errors.
 TEP_LIB_FUNCS::softReset();
}

ВНИМАНИЕ: Перезапуск MCU этого типа происходит быстро, при пробуждении и продолжении или пробуждении и сбросе нет заметных различий в скорости.

Вот и все, танки для просмотра;-)

----------

РЕДАКТИРОВАТЬ: при добавлении pciSetup( TEP_IR_RECV_PIN ); это также, кажется, работает отлично (потому что для него уже определен обработчик прерываний). Поэтому устройство также может проснуться при получении ИК-команды. Не ожидал, что это возможно, но попробовал, аккуратная особенность.

Другие вопросы по тегам