Greetings. Looking for a bit of help on some code that kinda works, but is flaky and I can't figure out why. Ultimately what I am trying to achieve is a lower power variant of "delay" that can readily be interrupted by key presses. Or, another way of putting it, I want a timed sleep function. My first thought was to use the watchdog timer - which I know is not precise, but these delays do not need to be precise (flashing LEDs, etc).
In my code below, I put the micro to sleep until a pin interrupt is triggered. If the pin interrupt is from the pin sensing the presence of USB voltage (USB_Sense), the micro enters a flashing cycle which enables the watchdog timer. You can see that basically what I am doing right now is turning on an LED, turning the watchdog timer on for a cycle, turning off the LED, then turning the watchdog timer off for a cycle. I understand that it is silly that I am turning the watchdog timer on and off considering the interval is the same, but ultimately I want to end up with code where I can pass in to my delay_WD function both the watchdog timer cycle time and the number of cycles I want it to run, so I have more flexibility over my pseudo-delay.
While USB_Sense is held high, and delay_WD is doing its thing, I want the code to be interruptable by an external button press. If that interrupt is sensed, the code will enter the "button" function, and will turn on another LED while the button is held down. If USB_Sense is still high after the press, the flashing cycle resumes.
The big issue I am having is when I bring USB_Sense high, the proper LED lights, but it stays lit for 20s or so before the flashing begins. If I press the external button, the other LED will light appropriately, turn off when the button is released, and then the flashing cycle begins (almost like the button press "kick-starts" the cycle). I must not be enabling something or handling initial conditions correctly - or doing something horribly wrong and I've just gotten lucky. Any help would be greatly appreciated.
-Chris
#include <avr/sleep.h>
#include <avr/wdt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
int BUTTON = 2; //user feedback button
int PCC_GLED = 5; //PCC Green LED
int PCC_RLED = 6; //PCC Red LED
int USB_SENSE = 9; //USB presence sensor
volatile int inter_check = 0;
volatile boolean f_wdt = 0;
void setup(){
sbi(GIMSK,PCIE0); // Turn on Pin Change interrupt 0
sbi(GIMSK,PCIE1); // Turn on Pin Change interrupt 1
sbi(PCMSK0,PCINT2); // Feedback switch
sbi(PCMSK0,PCINT3); // ECig sense
sbi(PCMSK1,PCINT9); // USB sense
pinMode(PCC_GLED, OUTPUT);
pinMode(PCC_RLED, OUTPUT);
pinMode(BUTTON, INPUT);
pinMode(USB_SENSE, INPUT);
digitalWrite(PCC_GLED, HIGH);
digitalWrite(PCC_RLED, HIGH);
digitalWrite(BUTTON, HIGH);
digitalWrite(USB_SENSE, LOW);
wdt_reset();
MCUSR=0;
wdt_disable();
}
void loop(){
//USB_STATE = digitalRead(USB_SENSE);
//BUTTON_STATE = digitalRead(BUTTON);
//ECIG_PRES_STATE = digitalRead(ECIG_PRES);
if (digitalRead(USB_SENSE)==HIGH){ //send to USB charging if bounced out of ECig charge
USB_Charging();
}
inter_check = 0;
system_sleep();
}
void USB_Charging() {
while(digitalRead(USB_SENSE)==HIGH) {
digitalWrite(PCC_GLED, LOW);
delay_WD(6,1); //wdtimer setting 6, 1 cycle, 1s
digitalWrite(PCC_GLED, HIGH);
delay_WD(6,1); //wdtimer setting 8, 1 cycle, 2s
}
}
void button() {
digitalWrite(PCC_GLED, HIGH);
while(digitalRead(BUTTON)==LOW) {
digitalWrite(PCC_RLED, LOW);
}
digitalWrite(PCC_RLED, HIGH);
}
void delay_WD (int WD_set, int WD_cycle) {
//setup
byte bb;
int ww;
if (WD_set > 9 ) WD_set=9;
bb=WD_set & 7;
if (WD_set > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCSR = bb;
WDTCSR |= _BV(WDIE);
//end setup
system_sleep();
wdt_reset();
MCUSR=0;
wdt_disable();
}
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
if (inter_check == 1){
if (digitalRead(USB_SENSE)==HIGH){
USB_Charging();
}
}
else if (inter_check == 2){
if (digitalRead(BUTTON)==LOW){
button();
}
}
}
ISR(WDT_vect) {
f_wdt=1; // set global flag
}
ISR(PCINT0_vect) {
inter_check=2; //button
}
ISR(PCINT1_vect){
inter_check=1;
}