LowPower库:掉电(睡眠)ATMega32u4可以工作,但唤醒并不会发生

时间:2017-10-07 23:48:05

标签: c++ arduino avr wakeup sleep-mode

情况:

我使用Pro Micro(ATMega32u4)制作/开发了这个控制器(具有许多功能),并希望在触摸它时使用唤醒功能(使用触摸传感器)对其进行扩展。这一切都是为了在不使用时节省一些能量。因此,当拾取/触摸设备时,设备会醒来。没有接触时,它会在一段时间后进入睡眠状态。触摸传感器的到达距离将通过壳体周围的小条铜带延长。

设备图片:

Image of device

我使用触摸传感器的引脚9和红外传感器的引脚16来唤醒,但它不起作用。两个设备功能都正常工作,我可以读取触摸状态(低=未接触或高=触摸),我可以接收IR命令,因为它已经完全实现。接收信号时,这些引脚将在一段时间内保持高电平。

软件问题:

我的代码有什么问题(参数错误吗?)?执行此代码时设备进入休眠状态(但从未醒过):

#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 ); 
}

我的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

注意:我已经测试过,只需延迟更换而不是睡觉,睡眠后的功能正常。所以我可以听到一声嘟嘟声,然后设备再次出现。在sleep()之后代码没有问题,它只是不想唤醒。

1 个答案:

答案 0 :(得分:0)

好的,我自己弄清楚了。似乎引脚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 );时,它似乎也能完美运行(因为已经为它定义了一个中断处理程序)。因此,设备也可以在接收IR命令时醒来。没想到这是可能的,但尝试了它,整洁的功能。