Hi,
I'm having a problem with SLEEP_MODE_PWR_DOWN and a pin change interrupt wake up.
I have a little egg timer project based on an attiny 4313. I am using CB's arduino-tiny core. My IDE is 1.6.5.
So the code I have now works like this. At the start the 4 digit display shows 0002 (short egg time for debugging.) I have three buttons (start, add minute, add second/clear display). I hit the start button and the display counts down as expected. 0001... 0000... and the piezo buzzer rings. Great so far. then there is a slight delay and the Attiny goes to sleep.
Now when I hit start the Attiny wakes up and the display starts at 0002 which seems reasonable. but I'm not sure what state the program is in now. If I hit start nothing happens. If I hit 'add minute' the minute appears on the display like 0102, but when I hit start the display goes back to 0002 and nothing happens.
I can get out of this state now by adding more than 4 seconds.... co if i hit the add second button 4 times and get to this: 0006, and then hit the start button the timer counts down 0005.... 0004.... 003... 0002... 0001... 0000... beeeep. Great. Until after a brief delay the Tiny goes back to sleep and now will not wake at all.
Can anyone tell me where I'm going wrong here. Is there a flag I have to clear after an INT to allow it to go off again?
I took most of the sleep code from Jack's MillionOhms project, and all the credit for the stuff that works goes to him. The mistakes I am sure are all mine.
Here is my code, the sleep stuff is in a function near the bottom and the ISR is the last function. The rest is a lot of bit twiddling to write to the display:
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <util/delay.h>
boolean button1state = 0;
boolean lastButton1state = 0;
boolean button2state = 0;
boolean lastButton2state = 0;
boolean button3state = 0;
boolean lastButton3state = 0;
boolean timeIsRunning = 0;
int minutes = 0;
int seconds = 2;
unsigned long oneSecond = 1000UL;
unsigned long startTime = 0;
unsigned long lastCheck = 0;
// Hardware Setup:
// A0 address select PA1
// A1 address select PA0
// WR PB0
// SW_1 PB1
// SW_2 PB2
// SW_3 PB3
void setup() {
//seconds = seconds + 60 * minutes; // 90 seconds
setupPins();
blankDisplay();
}
void setupPins() {
seconds = seconds + 60 * minutes;
DDRD = 0b01111111;
PORTD = 0b00000000; //PORTD is the ASCII data for the display, set output and start LOW
DDRA = 0b00000011; //PA0 & PA1 output
DDRB = 0b00000001; //PB0 output
PORTB = 0b00001110; //Pullups on switches
lastCheck = millis();
}
void loop() {
button1state = digitalRead(10);
button2state = digitalRead(11);
button3state = digitalRead(12);
if (button1state != lastButton1state) {
if (button1state == LOW) {
addMinute();
}
lastButton1state = button1state;
}
if (timeIsRunning == 0) {
if (button2state != lastButton2state) {
if (button2state == LOW) {
addSecond();
}
lastButton2state = button2state;
}
} else {
if (button2state != lastButton2state) {
if (button2state == LOW) {
resetTimer();
}
lastButton2state = button2state;
}
}
if (button3state != lastButton3state) {
if (button3state == LOW) {
startTimer();
}
delay(5);
lastButton3state = button3state;
}
if (timeIsRunning == 1) {
updateTime();
} else {
displayRemainingTime();
}
}
void updateTime() {
if (millis() - lastCheck >= oneSecond)
{
seconds--;
lastCheck = millis();
if (seconds < 0) {
endTime();
seconds = 5;
}
unsigned long timeMinutes = floor(seconds / 60);
unsigned long timeSeconds = seconds - (timeMinutes * 60);
int digit4 = timeSeconds % 10;
int digit3 = (timeSeconds / 10) % 10 ;
int digit2 = (timeMinutes) % 10;
int digit1 = (timeMinutes / 10) % 10 ;
PORTA = 0b00000011;
PORTB &= ~0x01; //take WR pin LOW
PORTD = digit1 + '0';
PORTB |= 0x01; //take WR pin HIGH
PORTA = 0b00000001;
PORTB &= ~0x01;
PORTD = digit2 + '0';
PORTB |= 0x01;
PORTA = 0b00000010;
PORTB &= ~0x01;
PORTD = digit3 + '0';
PORTB |= 0x01;
PORTA = 0b00000000;
PORTB &= ~0x01;
PORTD = digit4 + '0';
PORTB |= 0x01;
}
}
void displayRemainingTime() {
unsigned long timeMinutes = floor(seconds / 60);
unsigned long timeSeconds = seconds - (timeMinutes * 60);
int digit4 = timeSeconds % 10;
int digit3 = (timeSeconds / 10) % 10 ;
int digit2 = (timeMinutes) % 10;
int digit1 = (timeMinutes / 10) % 10 ;
PORTA = 0b00000011;
PORTB &= ~0x01;
PORTD = digit1 + '0';
PORTB |= 0x01;
PORTA = 0b00000001;
PORTB &= ~0x01;
PORTD = digit2 + '0';
PORTB |= 0x01;
PORTA = 0b00000010;
PORTB &= ~0x01;
PORTD = digit3 + '0';
PORTB |= 0x01;
PORTA = 0b00000000;
PORTB &= ~0x01;
PORTD = digit4 + '0';
PORTB |= 0x01;
delay(50);
}
void addMinute() {
seconds += 60;
}
void resetTimer() {
timeIsRunning = 0;
seconds = 0;
}
void addSecond() {
seconds += 1;
}
void startTimer() {
timeIsRunning = !timeIsRunning;
}
void endTime() {
timeIsRunning = 0;
seconds = 0;
tone(13, 2800, 400);
delay(1000);
goToSleep();
}
void blankDisplay() {
//digit3
PORTA = 0b00000011;
PORTB &= ~0x01;
PORTD = ' ';
PORTB |= 0x01;
//digit2
PORTA = 0b00000001;
PORTB &= ~0x01;
PORTD = ' ';
PORTB |= 0x01;
//digit1
PORTA = 0b00000010;
PORTB &= ~0x01;
PORTD = ' ';
PORTB |= 0x01;
//digit0
PORTA = 0b00000000;
PORTB &= ~0x01;
PORTD = ' ';
PORTB |= 0x01;
}
void displayChar(const char myChar, int myPos) {
switch (myPos) {
case 0:
PORTA = 0b00000011;
break;
case 1:
PORTA = 0b00000001;
break;
case 2:
PORTA = 0b00000010;
break;
case 3:
PORTA = 0b00000000;
break;
}
PORTB &= ~0x01;
PORTD = myChar;
PORTB |= 0x01;
}
void goToSleep() {
blankDisplay();
DDRD = 0b00000000;
DDRA = 0b00000000;
DDRB = 0b00000000;
PORTB = 0b00001000; //leave pullup on PCINT3.
GIMSK |= (1 << INT0); //enable INT0
GIMSK |= (1 << PCIE0); // enabel pin Change 0
MCUCR |= (1 << ISC00) | (1 << ISC01); // any logic change on INT 0
PCMSK |= (1 << PCINT3);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
cli();
sei(); //ensure interrupts enabled so we can wake up again
sleep_cpu();
//----zzzz----zzzz----zzzz----zzzz
cli(); //wake up here, disable interrupts
GIMSK = 0x00; //disable INT0
sleep_disable();
sei();
setupPins();
}
ISR(INT0_vect)
{
GIMSK = 0x00; //disable INT0
}
Thanks,
Jimmy