I need my nano to run a motor for 20 seconds (via l298n), then stop, go to sleep for 8 seconds for 99 times, on the 100th time, it should wake up and run the motor again, then continue with its 8 second wakes. The 8 second wakes is to pulse the battery pack so it wont fall asleep.
I just want to double check before running this on the nano since Ive read that sleeping the chip the wrong way may ruin it.
My code:
#include <avr/wdt.h> // library for default watchdog functions
#include <avr/interrupt.h> // library for interrupts handling
#include <avr/sleep.h> // library for sleep
#include <avr/power.h> // library for power control
int nbr_sleeps=0;
#define led 13 //used only as indicator
#define motorPin 10
#define pulsePin 8
ISR(WDT_vect){
// not hanging, just waiting
// reset the watchdog
wdt_reset();
}
void configure_wdt(void){
cli(); // disable interrupts for changing the registers
MCUSR = 0; // reset status register flags
// Put timer in interrupt-only mode:
WDTCSR |= 0b00011000; // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// using bitwise OR assignment (leaves other bits unchanged).
WDTCSR = 0b01000000 | 0b100001; // set WDIE: interrupt enabled
// clr WDE: reset disabled
// and set delay interval (right side of bar) to 8 seconds
sei(); // re-enable interrupts
}
void sleep(int ncycles){
nbr_sleeps =+;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_adc_disable();
sleep_mode();
// CPU is now asleep and program execution completely halts!
// Once awake, execution will resume at this point if the
// watchdog is configured for resume rather than restart
// When awake, disable sleep mode
sleep_disable();
power_all_enable();
}
void setup(){
// use led 13 and put it in low mode
pinMode(led, OUTPUT);
pinMode(pulsePin, OUTPUT); // for pulse
// configure the watchdog
configure_wdt();
}
void loop(){
// sleep for 8 seconds
sleep(1);
digitalWrite(pulsePin, HIGH);
delayMicroseconds(100); // Approximately 10% duty cycle @ 1KHz
digitalWrite(pulsePin, LOW);
delayMicroseconds(1000 - 100);
if (nbr_sleeps==99) runMotor();
}
void runMotor() {
// blink three times to indicate motor will run
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
//Turn motor on
digitalWrite(motorPin, HIGH);
delay(20000);
digitalWrite(motorPin, LOW);
}
Ok im using this code and instead of a motor and a led, Im using 2 leds for now. So one led blinks every 8 seconds, 1 sleep cycle, and the other blinks every 100 cycles of 800 seconds.
The 8 second led blinks fine, every 8, but the battery pack turns off after about 1.5 minutes:
#include <avr/wdt.h> // library for default watchdog functions
#include <avr/interrupt.h> // library for interrupts handling
#include <avr/sleep.h> // library for sleep
#include <avr/power.h> // library for power control
int nbr_sleeps=0;
#define led 13
#define motorPin 10
#define pulsePin 7
ISR(WDT_vect){
// not hanging, just waiting
// reset the watchdog
wdt_reset();
}
void configure_wdt(void){
cli(); // disable interrupts for changing the registers
MCUSR = 0; // reset status register flags
// Put timer in interrupt-only mode:
WDTCSR |= 0b00011000; // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// using bitwise OR assignment (leaves other bits unchanged).
WDTCSR = 0b01000000 | 0b100001; // set WDIE: interrupt enabled
// clr WDE: reset disabled
// and set delay interval (right side of bar) to 8 seconds
sei(); // re-enable interrupts
}
void sleep(int ncycles){
nbr_sleeps ++;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_adc_disable();
sleep_mode();
// CPU is now asleep and program execution completely halts!
// Once awake, execution will resume at this point if the
// watchdog is configured for resume rather than restart
// When awake, disable sleep mode
sleep_disable();
power_all_enable();
}
void setup(){
Serial.begin(9600);
// use led 13 and put it in low mode
pinMode(led, OUTPUT);
pinMode(pulsePin, OUTPUT); // for pulse
// configure the watchdog
configure_wdt();
}
void loop(){
Serial.println("will sleep...");
// sleep for 8 seconds
sleep(1);
digitalWrite(pulsePin, HIGH);
delayMicroseconds(1000); // Approximately 10% duty cycle @ 1KHz
digitalWrite(pulsePin, LOW);
delayMicroseconds(1000 - 100);
Serial.println("pulsed led...");
if (nbr_sleeps==99) {
Serial.println("running motor...");
runMotor();
nbr_sleeps=0;
}
}
void runMotor() {
//Turn motor on
digitalWrite(motorPin, HIGH);
delay(20000);
digitalWrite(motorPin, LOW);
}
Is the battery pack like what you would use to charge a phone? Most battery packs will automatically switch off after a timeout when no load is detected. It may be that the load imposed by the brief 'wakeup' is not enough to keep the battery pack turned on. Not a bad feature to preserve the life of the battery. You may find that a small delay during your wakeup (try 1ms to start) will keep the battery pack alive.
Yes, that is what Im trying to do, keep it awake. So I could either add it in the sleep() function after it wakes up:
void sleep(int ncycles){
nbr_sleeps ++;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_adc_disable();
sleep_mode();
// CPU is now asleep and program execution completely halts!
// Once awake, execution will resume at this point if the
// watchdog is configured for resume rather than restart
delay(1000);
// When awake, disable sleep mode
sleep_disable();
power_all_enable();
}
Your problem caused me to run a test. My battery pack has three discernible modes: off, sleep and on. When using SLEEP_MODE_IDLE, the pack remained on all the time. With SLEEP_MODE_PWR_DOWN, the pack would come on for about 12 seconds (WDT set at 8 ) and then go to sleep for 2-3 minutes before turning on again for another 12 seconds (or so). All the while the UNO kept running. This I know as I flash the LED for 30ms during wakeup. That 30ms LED flash may be enough to keep the pack alive as I also know that under normal circumstances, when a device is removed from the pack it switches (after a delay) to sleep mode before turning off.
I added a 1 second delay with the LED ON, so that the pulsePin which is connected to an LED, stays on for 1 second, but even then the battery pack powers down after 1.5 minutes. Here is the code Im using:
#include <avr/wdt.h> // library for default watchdog functions
#include <avr/interrupt.h> // library for interrupts handling
#include <avr/sleep.h> // library for sleep
#include <avr/power.h> // library for power control
int nbr_sleeps=0;
#define led 13
#define motorPin 10
#define pulsePin 7
ISR(WDT_vect){
// not hanging, just waiting
// reset the watchdog
wdt_reset();
}
void configure_wdt(void){
cli(); // disable interrupts for changing the registers
MCUSR = 0; // reset status register flags
// Put timer in interrupt-only mode:
WDTCSR |= 0b00011000; // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// using bitwise OR assignment (leaves other bits unchanged).
WDTCSR = 0b01000000 | 0b100001; // set WDIE: interrupt enabled
// clr WDE: reset disabled
// and set delay interval (right side of bar) to 8 seconds
sei(); // re-enable interrupts
}
void sleep(int ncycles){
nbr_sleeps ++;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_adc_disable();
sleep_mode();
// CPU is now asleep and program execution completely halts!
// Once awake, execution will resume at this point if the
// watchdog is configured for resume rather than restart
// When awake, disable sleep mode
sleep_disable();
power_all_enable();
}
void setup(){
Serial.begin(9600);
// use led 13 and put it in low mode
pinMode(led, OUTPUT);
pinMode(pulsePin, OUTPUT); // for pulse
// configure the watchdog
configure_wdt();
}
void loop(){
Serial.println("will sleep...");
// sleep for 8 seconds
sleep(1);
digitalWrite(pulsePin, HIGH);
//delayMicroseconds(1000); // Approximately 10% duty cycle @ 1KHz
delay(1000);
digitalWrite(pulsePin, LOW);
delayMicroseconds(1000 - 100);
Serial.println("pulsed led...");
if (nbr_sleeps==99) {
Serial.println("running motor...");
runMotor();
nbr_sleeps=0;
}
}
void runMotor() {
//Turn motor on
digitalWrite(motorPin, HIGH);
delay(20000);
digitalWrite(motorPin, LOW);
}
If i plug in my phone to the battery pack, the battery pack keeps charging my phone for quite a while, I dunno how long, I haven't timed it but it gets it up to 70-80% charge from 20% or so, so it takes about an hour or more.
If I plug the nano to it, it shuts down, with this code and the LED, after 1.5 minutes or so.
If i plug it into the nano without the sleep code, with a different code like this one that sends rf data constantly, the nano turns off after about 1.5 minutes as well...
// Include RadioHead Amplitude Shift Keying Library
#include <RH_ASK.h>
// Include dependant SPI Library
#include <SPI.h>
#include "Wire.h" //For communicate
#include "I2Cdev.h" //For communicate with MPU6050
#include "MPU6050.h" //The main library of the MPU6050
//Define the object to access and cotrol the Gyro and Accelerometer (We don't use the Gyro data)
MPU6050 mpu;
int16_t ax, ay, az;
int16_t gx, gy, gz;
//Define packet for the direction (X axis and Y axis)
int data[2];
// Create Amplitude Shift Keying Object
RH_ASK rf_driver;
void setup() {
Serial.begin(9600);
mpu.initialize(); //Initialize the MPU object
// Initialize ASK Object
rf_driver.init();
}
void loop() {
delay(2000); // Delay so DHT-22 sensor can stabalize
//With this function, the acceleration and gyro values of the axes are taken.
//If you want to control the car axis differently, you can change the axis name in the map command.
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
//In two-way control, the X axis (data [0]) of the MPU6050 allows the robot to move forward and backward.
//Y axis (data [0]) allows the robot to right and left turn.
data[0] = map(ax, -17000, 17000, 300, 400 ); //Send aX axis data
data[1] = map(ay, -17000, 17000, 100, 200); //Send aY axis data
rf_driver.send((const uint8_t*)data, sizeof(data));
//(uint8_t *)msg, strlen(msg));
rf_driver.waitPacketSent();
Serial.println(data[0]);
Serial.println(data[1]);
}
One thing you'll have to correct in your code is in function sleep, nbr_sleeps =+; should be nbr_sleeps ++;.
Take set_sleep_mode out and put it in setup.
The parameter you're passing does nothing, but I'll assume that's for code yet to come?
I've made the changes I mentioned above and included nbr_sleeps = 0; at the end of runMotor as it needs to be reset. Compiles fine (with the exception of the unused parameter).
I added a 30ms led flash during each wakeup.
In loop I changed if (nbr... to if (nbr_sleeps==3) runMotor; and it runs fine. Haven't tested it for 15 minutes with my battery pack, but I see no reason that it should stop.
The only other thing I'm going to suggest just now, is to set your sleep mode to idle and run your test again. See if that keeps your battery pack alive.
It's after 0100 where I am and I need a few hours rest.
I do not think that you can brick your arduino with sleep (please correct me if I'm wrong), but you can brick it by changing fuses - but I'm not sure that is possible on a nano.
Whenever I program a stand alone AVR/MCU, I dedicate a single digital input pin as sort of a "sleep aborter" by wiring a R10K from GND to PIN (not really nescessary). When I want to cancel any sleep, I rewire it to R1K from VIN to PIN. The code would be something like:
Different battery packs have radically different behavior with regards to turning themselves off under low/no load.
Some will only turn off if the load is damned near zero, so waking up and blinking an led would be enough. Others require loads on the order of 100mA to stay awake (I have one that won't charge my Go-tcha (a fitbit-sized companion device for pokemon go - it turns off because charging the tiny battery doesn't draw enough current to keep it from turning off). And of course, this parameter is never spec'ed by the manufacturer.
You can't brick an arduino using sleep mode. You can nearly-soft-brick nano (except the "new bootloader" official ones manufactured this year) and pro mini with the WDT if it's used to generate a reset event (when this happens the WDT stays on after the reset, with the minimum timeout, and if the bootloader isn't smart enough to check for this and turn it off, it will reset-loop while the bootloader is running) - this can be recovered from by manually resetting to upload (IIRC even reset doesn't turn it off, so you need to power cycle it and hold reset until the right point in the upload process) or by rebootloading with an ISP programmer. It can be prevented entirely by bootloading them as an Uno and treating them as such within the IDE.
Danois90:
I dedicate a single digital input pin as sort of a "sleep aborter" by wiring a R10K from GND to PIN (not really nescessary)
Yes it is, otherwise the pin will float and reads will yield a random value. Better to set it input_pullup, and trigger the abort by grounding it.
But as noted above, it's not possible to brick a board with sleep mode. The reset pin will always bring it back.
You don't think I've heard all the Sherlock jokes. One reason I keep my education quiet.
Seems like I've got myself a pretty useful battery pack, the only one in fact that hasn't given op the ghost. It goes into it's own power down mode while still maintaining a trickle current. Wakes up every couple of minutes for 12 seconds to see if anything is still attached and keeps on plugging. Seems to be branded for the local market (Indonesia) using the same name as the local beer, All I can say is I got it at Ace Hardware.