Context
I am building a small battery powered counting device. As with many other projects like this, saving power is critical. I am therefore trying to utilise the sleep mode wherever possible. This is using a 328P as a standalone MCU running on the 1MHz internal clock
The Hall Effect sensor I am using outputs Vcc when nothing is detected, and Ground when something is detected. It therefore seems well suited to being used as a trigger for an interrupt to wake up the 328P from sleep (so that I don't even need to use a watchdog timer.)
Below is an excerpt from my code. This code does put the processor into sleep as desired. However, from testing I have discovered that the device will not sleep when the magnet is left near the sensor, as its output stays LOW. As I only want to detect pulses of a moving piece of metal, this is wasting power. I only want to wake up when it is initially detected on each cycle.
void sleepLoop()
{
Serial.print("S");
delay(5); //scales to 40ms
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
noInterrupts();
attachInterrupt(digitalPinToInterrupt(countInterruptPin), sleepInterrupt, LOW);
interrupts();
sleep_cpu();
//The program will continue from here.
//First thing to do is disable sleep.
sleep_disable();
}
I therefore changed
attachInterrupt(digitalPinToInterrupt(countInterruptPin), sleepInterrupt, LOW);
to
attachInterrupt(digitalPinToInterrupt(countInterruptPin), sleepInterrupt, FALLING);
PROBLEM
Now my processor never goes to sleep. For debugging I have put in a serial print at the start of the loop so that I know it has entered this loop of code. Whether LOW
or FALLING
is used the 'S' is printed. I only know it is not sleeping because I am measuring the current flow.
I thought the sensor may be going LOW long enough to keep the device awake, but not long enough to register as a count (as I have a debounce in there) so I have checked the output from the sensor with an oscilloscope in case it was momentarily going LOW
, but I couldn't see any sign of this.
The findings from the oscilloscope make me feel like there is something about the interrupt function that I am overlooking. Any help would be greatly appreciated!
2 Answers 2
Only low level detect is possible with external interrupt pins (INT0/D2 and INT1/D3) in power down sleep mode. The signal must be low for a number of clock cycles to be detected and the interrupt will detected while the signal is low (and the interrupt is enabled). It is not a transition.
A pin change interrupt could be used instead.
For more details please see chap. 9.5 Power-down Mode and chap. 12. External Interrupts.
Cheers!
There is a more radical alternative, that could yield even higher power savings: use the HAL sensor to trigger a monostable circuit that normally would keep the uC (and the clock source) powered off.
When it starts, get it to update the counter and time the monostable so that it shortly puts the rest of the system back to off.
You can use the eeprom for the counter.
For improved efficiency, get rid of the bootloader and start executing your application right away. If you program from the ISP interface, you do not need the bootloader.
-
Were filtering contact/range bounce not likely necessary the ATmega counter timer block could probably be configured to count without waking up the processor at all. But wakeup is not that expensive and has nothing to do with the bootloader as it does not mean the CPU reboots.Chris Stratton– Chris Stratton12/03/2015 17:29:46Commented Dec 3, 2015 at 17:29
S
printed when signal is low (and sometimes when it goes back high). Are you sure your hall-effect sensor doesn't need a pull-up resistor? What kind of serial output do you get? What is the power-usage (normal, during sleep, during "apparently not sleep")?Serial.begin(38400); //Use Baud rate at 4800 on PC (due to 1MHz clock speed) // (38400/8)=4800