Arduino Forum

Using Arduino => Programming Questions => Topic started by: astroboy907 on Sep 18, 2012, 05:22 am

Title: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 18, 2012, 05:22 am
So I am trying to build a small watch project, I cant really go so much into detail as I am just prototyping. I am not exactly "great" in C, but know my way around the basics.

However, timer interrupts or fuse settings continue to boggle me.
At this point I have gotten counting and LEDs to light up on my board, good signs. Once that went good, I moved onto timing the danged thing. I am basing my code heavily off of sparkfuns "bigTime" watch code (on their website if you need it). Basically the clock is running off of a 32.768kHz crystal, as sort of an RTC. This is timed by generating interrupts on the clock pins. Unfortunately, my code doesnt seem to work. I have LEDs that light up, and my button interrupts work, but I CANNOT get the external crystal to trigger the interrupt.

Here is my code:

Code: [Select]

9/8/12

#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers

#define TRUE 1
#define FALSE 0

//Set this variable to change how long the time is shown on the watch face. In milliseconds so 1677 = 1.677 seconds
int show_time_length = 2000;
int show_the_time = FALSE;

//You can set always_on to true and the display will stay on all the time
//This will drain the battery in about 15 hours
int always_on = FALSE;

long seconds = 54;
int minutes = 24;
int hours = 3;


#define RED  1
int systemColor = RED;
int display_brightness = 15000; //A larger number makes the display more dim. This is set correctly below.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Pin definitions
int hour8 = A4; //Hour 8
int hour4 = A2; //Hour 4
int hour2 = 12; //Hour 2
int hour1 = 10; //Hour 1

int minute32 = A0; //Minute 32
int minute16 = A3; //Minute 16
int minute8 = A1; //Minute 8
int minute4 = 13; //Minute 4
int minute2 = 11; //Minute 2
int minute1 = 9; //Minute 1

int theButton = 2;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//The very important 32.686kHz interrupt handler
SIGNAL(TIMER2_OVF_vect){
 seconds += 8; //We sleep for 8 seconds instead of 1 to save more power
 //seconds++; //Use this if we are waking up every second

if(seconds > 59){
minutes++;
seconds = seconds - 59;
}

if(minutes > 59){
 hours++;
minutes = minutes - 59;
}


/*
//Update the minutes and hours variables
 minutes += seconds / 60; //Example: seconds = 2317, minutes = 58 + 38 = 96
 seconds %= 60; //seconds = 37
 hours += minutes / 60; //12 + (96 / 60) = 13
 minutes %= 60; //minutes = 36
*/

if(hours > 12) hours -= 12;
 
}
//The interrupt occurs when you push the button
SIGNAL(INT0_vect){
 //When you hit the button, we will need to display the time
 //if(show_the_time == FALSE)
 show_the_time = TRUE;

}

void setup() {                
 //To reduce power, setup all pins as inputs with no pullups
 for(int x = 1 ; x < 18 ; x++){
   pinMode(x, INPUT);
   digitalWrite(x, LOW);
 }

 pinMode(theButton, INPUT); //This is the main button, tied to INT0
 digitalWrite(theButton, HIGH); //Enable internal pull up on button

 //These pins are used to control the display
 pinMode(hour8, OUTPUT);
.....
 pinMode(minute1, OUTPUT);


 //Power down various bits of hardware to lower power usage  
 set_sleep_mode(SLEEP_MODE_PWR_SAVE);
 sleep_enable();

 //Shut off ADC, TWI, SPI, Timer0, Timer1

 ADCSRA &= ~(1<<ADEN); //Disable ADC
 ACSR = (1<<ACD); //Disable the analog comparator
 DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins
 DIDR1 = (1<<AIN1D)|(1<<AIN0D); //Disable digital input buffer on AIN1/0

 power_twi_disable();
 power_spi_disable();
 power_usart0_disable();
 //power_timer0_disable(); //Needed for delay_ms
 power_timer1_disable();
 //power_timer2_disable(); //Needed for asynchronous 32kHz operation
 
 //Setup TIMER2
 TCCR2A = 0x00;
 TCCR2B = (1<<CS22)|(1<<CS20); //Set CLK/128 or overflow interrupt every 1s
// TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); //Set CLK/1024 or overflow interrupt every 8s
 ASSR = (1<<AS2); //Enable asynchronous operation
 TIMSK2 = (1<<TOIE2); //Enable the timer 2 interrupt

 //Setup external INT0 interrupt
 EICRA = (1<<ISC01); //Interrupt on falling edge
 EIMSK = (1<<INT0); //Enable INT0 interrupt

 //System clock futzing
 //CLKPR = (1<<CLKPCE); //Enable clock writing
 //CLKPR = (1<<CLKPS3); //Divid the system clock by 256


 
 //Display brightness changes based on color
 if(systemColor == RED) {
   display_brightness = 4500; //The higher the number, the lower the brightness
 
 }
 else {
   display_brightness = 1;
   
 }


 showTime(); //Show the current time for a few seconds

 sei(); //Enable global interrupts
}

void loop() {
 if(always_on == FALSE)
   sleep_mode(); //Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button

 if(show_the_time == TRUE || always_on == TRUE) {

 
   showTime(); //Show the current time for a few seconds

   //If you are STILL holding the button, then you must want to adjust the time
   if(digitalRead(theButton) == LOW){ setTime();
   }
   show_the_time = FALSE; //Reset the button variable
 }
}

void showTime() {

   //Now show the time for a certain length of time
 long startTime = millis();
 while( (millis() - startTime) < show_time_length) {
 
   lightLeds();

 
     if(display_brightness > 0){ //PWM only if brightness is not full
   delayMicroseconds(display_brightness);
     }
 }

}



//Holding the button down will increase the time (accelerates)

void setTime(void) {

 
//Now show the time for a certain length of time
 long startTime = millis();
 while( (millis() - startTime) < show_time_length) {
 
   lightLeds();

 
     if(display_brightness > 0){ //PWM only if brightness is not full
   delayMicroseconds(display_brightness);
     }
 }
 
 int idleMiliseconds = 0;
 //This is the timeout counter. Once we get to ~2 seconds of inactivity, the watch
 //will exit the setTime function and return to normal operation

 int buttonHold = 0;
 //This counts the number of times you are holding the button down consecutively
 //Once we notice you're really holding the button down a lot, we will speed up the minute counter

 while(idleMiliseconds < 2000) {

   cli(); //We don't want the interrupt changing values at the same time we are!
if(seconds > 59){
minutes++;
seconds = seconds - 59;
}

if(minutes > 59){
 hours++;
 minutes = minutes - 59;
}


if(hours > 12) hours -= 12;

   sei(); //Resume interrupts
   
for(int x = 0 ; x < 20 ; x++) {
     lightLeds(); //Each call takes about 8ms, display the colon for about 100ms
     if(display_brightness > 0) {delayMicroseconds(display_brightness); //Wait before we paint the display again
   }
}
 
 

   //If you're still hitting the button, then increase the time and reset the idleMili timeout variable
   if(digitalRead(theButton) == LOW) {
     idleMiliseconds = 0;

     buttonHold++;
     if(buttonHold < 10)
       minutes++; //Advance the minutes
     else {
       //Advance the minutes faster because you're holding the button for 10 seconds
       //Start advancing on the tens digit. Floor the single minute digit.
       minutes /= 10; //minutes = 46 / 10 = 4
       minutes *= 10; //minutes = 4 * 10 = 40
       minutes += 10;  //minutes = 40 + 10 = 50
     }
   }
   else
     buttonHold = 0;

   idleMiliseconds += 200;
 }
}








  void lightLeds() {
    //Turns correct outputs on

 
switch(hours) {
   
  ...
 }
 
 
 switch(minutes){
 ...
 }
 
 
 if(display_brightness > 0){ //Only PWM if brightness is not full
   delayMicroseconds(display_brightness);
 
  digitalWrite(hour8, LOW); //write pins low to get "dimming" effect
....
 }
 
}





/*
ARTHUR: What?
TIM: There he is!
ARTHUR: Where?
TIM: There!
ARTHUR: What, behind the rabbit?
TIM: It is the rabbit!

(\_/)
(o.O) ----Grrrrrrrrrrr.
(>< )
/_|_\

*/



Sorry its pretty long, but most of the stuff is in the top part. The rest is just variables :)


Things i have tried: different crystal, random bits of the "same" code off of google searches, etc. Not much, but Ive been searching for a few days on this and come to nothing. Grr.

I am uploading using arduino 1.01 and an AVRISP MKII !CLONE! but that seems to work perfectly. Even in AVR studio! ;) *shameless plug, cost me $12 for a kit to build it and it WORKS! happy dance*

THANKS so much for any help you can give. At this point its kind of exceeding my limits...


Stupid forum limits... had to take out half my code :(
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Sep 18, 2012, 09:06 am
You can attach files to posts you know. Like, your code.

And you should do an auto-format. Your indentation is all over the place.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: PaulS on Sep 18, 2012, 01:10 pm
Code: [Select]
//The interrupt occurs when you push the button
SIGNAL(INT0_vect){
  //When you hit the button, we will need to display the time
  //if(show_the_time == FALSE)
  show_the_time = TRUE;
}

The button? What button?

Does your code work if you quit trying to sleep? What use is a sleeping watch?

Code: [Select]
  TCCR2B = (1<<CS22)|(1<<CS20); //Set CLK/128 or overflow interrupt every 1s
// TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); //Set CLK/1024 or overflow interrupt every 8s

In the interrupt handler, you assume that 8 seconds have elapsed. I'm confused as to why?

Code: [Select]
  if(always_on == FALSE)
Explicit comparisons to true or false look silly.
Code: [Select]
  if(!always_on)
looks like someone who knew what they were doing wrote the code.

Code: [Select]
  if(show_the_time == TRUE || always_on == TRUE) {
likewise should be
Code: [Select]
  if(show_the_time || always_on)
  { // Down here, where it belongs


Code: [Select]
      if(display_brightness > 0){ //PWM only if brightness is not full
    delayMicroseconds(display_brightness);
      }

I fail to see how a delay will decrease brightness.

Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 18, 2012, 03:45 pm
Auto-formatted code:
Code: [Select]
9/8/12

#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers

#define TRUE 1
#define FALSE 0

//Set this variable to change how long the time is shown on the watch face. In milliseconds so 1677 = 1.677 seconds
int show_time_length = 2000;
int show_the_time = FALSE;

//You can set always_on to true and the display will stay on all the time
//This will drain the battery in about 15 hours
int always_on = FALSE;

long seconds = 54;
int minutes = 24;
int hours = 3;


#define RED  1
int systemColor = RED;
int display_brightness = 15000; //A larger number makes the display more dim. This is set correctly below.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Pin definitions
int hour8 = A4; //Hour 8
int hour4 = A2; //Hour 4
int hour2 = 12; //Hour 2
int hour1 = 10; //Hour 1

int minute32 = A0; //Minute 32
int minute16 = A3; //Minute 16
int minute8 = A1; //Minute 8
int minute4 = 13; //Minute 4
int minute2 = 11; //Minute 2
int minute1 = 9; //Minute 1

int theButton = 2;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//The very important 32.686kHz interrupt handler
SIGNAL(TIMER2_OVF_vect){
  seconds += 8; //We sleep for 8 seconds instead of 1 to save more power
  //seconds++; //Use this if we are waking up every second

  if(seconds > 59){
    minutes++;
    seconds = seconds - 59;
  }

  if(minutes > 59){
    hours++;
    minutes = minutes - 59;
  }


  /*
//Update the minutes and hours variables
   minutes += seconds / 60; //Example: seconds = 2317, minutes = 58 + 38 = 96
   seconds %= 60; //seconds = 37
   hours += minutes / 60; //12 + (96 / 60) = 13
   minutes %= 60; //minutes = 36
   */

  if(hours > 12) hours -= 12;

}
//The interrupt occurs when you push the button
SIGNAL(INT0_vect){
  //When you hit the button, we will need to display the time
  //if(show_the_time == FALSE)
  show_the_time = TRUE;

}

void setup() {               
  //To reduce power, setup all pins as inputs with no pullups
  for(int x = 1 ; x < 18 ; x++){
    pinMode(x, INPUT);
    digitalWrite(x, LOW);
  }

  pinMode(theButton, INPUT); //This is the main button, tied to INT0
  digitalWrite(theButton, HIGH); //Enable internal pull up on button

  //These pins are used to control the display
  pinMode(hour8, OUTPUT);
  .....
    pinMode(minute1, OUTPUT);


  //Power down various bits of hardware to lower power usage 
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  sleep_enable();

  //Shut off ADC, TWI, SPI, Timer0, Timer1

  ADCSRA &= ~(1<<ADEN); //Disable ADC
  ACSR = (1<<ACD); //Disable the analog comparator
  DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins
  DIDR1 = (1<<AIN1D)|(1<<AIN0D); //Disable digital input buffer on AIN1/0

  power_twi_disable();
  power_spi_disable();
  power_usart0_disable();
  //power_timer0_disable(); //Needed for delay_ms
  power_timer1_disable();
  //power_timer2_disable(); //Needed for asynchronous 32kHz operation

  //Setup TIMER2
  TCCR2A = 0x00;
// TCCR2B = (1<<CS22)|(1<<CS20); //Set CLK/128 or overflow interrupt every 1s
   TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); //Set CLK/1024 or overflow interrupt every 8s
  ASSR = (1<<AS2); //Enable asynchronous operation
  TIMSK2 = (1<<TOIE2); //Enable the timer 2 interrupt

  //Setup external INT0 interrupt
  EICRA = (1<<ISC01); //Interrupt on falling edge
  EIMSK = (1<<INT0); //Enable INT0 interrupt

  //System clock futzing
  //CLKPR = (1<<CLKPCE); //Enable clock writing
  //CLKPR = (1<<CLKPS3); //Divid the system clock by 256



  //Display brightness changes based on color
  if(systemColor == RED) {
    display_brightness = 4500; //The higher the number, the lower the brightness

  }
  else {
    display_brightness = 1;

  }


  showTime(); //Show the current time for a few seconds

  sei(); //Enable global interrupts
}

void loop() {
  if(always_on == FALSE)
    sleep_mode(); //Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button

  if(show_the_time == TRUE || always_on == TRUE) {


    showTime(); //Show the current time for a few seconds

    //If you are STILL holding the button, then you must want to adjust the time
    if(digitalRead(theButton) == LOW){
      setTime();
    }
    show_the_time = FALSE; //Reset the button variable
  }
}

void showTime() {

  //Now show the time for a certain length of time
  long startTime = millis();
  while( (millis() - startTime) < show_time_length) {

    lightLeds();


    if(display_brightness > 0){ //PWM only if brightness is not full
      delayMicroseconds(display_brightness);
    }
  }

}



//Holding the button down will increase the time (accelerates)

void setTime(void) {


  //Now show the time for a certain length of time
  long startTime = millis();
  while( (millis() - startTime) < show_time_length) {

    lightLeds();


    if(display_brightness > 0){ //PWM only if brightness is not full
      delayMicroseconds(display_brightness);
    }
  }

  int idleMiliseconds = 0;
  //This is the timeout counter. Once we get to ~2 seconds of inactivity, the watch
  //will exit the setTime function and return to normal operation

  int buttonHold = 0;
  //This counts the number of times you are holding the button down consecutively
  //Once we notice you're really holding the button down a lot, we will speed up the minute counter

  while(idleMiliseconds < 2000) {

    cli(); //We don't want the interrupt changing values at the same time we are!
    if(seconds > 59){
      minutes++;
      seconds = seconds - 59;
    }

    if(minutes > 59){
      hours++;
      minutes = minutes - 59;
    }


    if(hours > 12) hours -= 12;

    sei(); //Resume interrupts

    for(int x = 0 ; x < 20 ; x++) {
      lightLeds(); //Each call takes about 8ms, display the colon for about 100ms
      if(display_brightness > 0) {
        delayMicroseconds(display_brightness); //Wait before we paint the display again
      }
    }



    //If you're still hitting the button, then increase the time and reset the idleMili timeout variable
    if(digitalRead(theButton) == LOW) {
      idleMiliseconds = 0;

      buttonHold++;
      if(buttonHold < 10)
        minutes++; //Advance the minutes
      else {
        //Advance the minutes faster because you're holding the button for 10 seconds
        //Start advancing on the tens digit. Floor the single minute digit.
        minutes /= 10; //minutes = 46 / 10 = 4
        minutes *= 10; //minutes = 4 * 10 = 40
        minutes += 10;  //minutes = 40 + 10 = 50
      }
    }
    else
      buttonHold = 0;

    idleMiliseconds += 200;
  }
}








void lightLeds() {
  //Turns correct outputs on


  switch(hours) {

    ...
  }


  switch(minutes){
    ...
  }


  if(display_brightness > 0){ //Only PWM if brightness is not full
    delayMicroseconds(display_brightness);

    digitalWrite(hour8, LOW); //write pins low to get "dimming" effect
    ....
  }

}








Ok, as for this:
Code: [Select]


//The interrupt occurs when you push the button
SIGNAL(INT0_vect){
  //When you hit the button, we will need to display the time
  //if(show_the_time == FALSE)
  show_the_time = TRUE;
}

The button? What button? - there is a button interrupt attached to pin D2 i believe. This is used to wake the watch from sleep.

Does your code work if you quit trying to sleep? What use is a sleeping watch? - No and no, when I set always on to true, the timer2 interrupt is still running but never called, never incrementing the timer/clock variables. Watch is sleeping to save massive amounts of power.

Code: [Select]

  TCCR2B = (1<<CS22)|(1<<CS20); //Set CLK/128 or overflow interrupt every 1s
// TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); //Set CLK/1024 or overflow interrupt every 8s

In the interrupt handler, you assume that 8 seconds have elapsed. I'm confused as to why?
Sorry, typo on my part. the two lines should be commented differently.

Code: [Select]

  if(always_on == FALSE)

Explicit comparisons to true or false look silly.
Keeping this because it is so much easier for a beginner to find this and know what to do with it. Its harder to spot the not ! in it.

Code: [Select]

  if(!always_on)

looks like someone who knew what they were doing wrote the code.
Yeah, well I don't sometimes so :P. Lol JK, just trying to keep the variable easier to spot.

Code: [Select]

      if(display_brightness > 0){ //PWM only if brightness is not full
    delayMicroseconds(display_brightness);
      }

I fail to see how a delay will decrease brightness.
More of a virtual PWM as I do not have 10 PWM pins for 10 LEDs. This is more of "bursting" the LEDs to appear not as bright.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: PaulS on Sep 18, 2012, 04:03 pm
Quote
Watch is sleeping to save massive amounts of power.

Not working saves even more power? Just trying to eliminate possible areas of conflict.

Quote
there is a button interrupt attached to pin D2 i believe.

I'd check... I also don't see where you connect that ISR to that pin. The attachInterrupt() function is usually called to make an association.

I think, at this point, that we need to see all of your code.

Quote
This is timed by generating interrupts on the clock pins.

Which pins would that be? What code, of yours, is supposed to respond to those interrupts?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: MarkT on Sep 18, 2012, 04:45 pm
We need to see your circuit to understand this, some of your code suggests you are clocking timer2's prescaler at 32768Hz, is this true and if so how?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 18, 2012, 11:45 pm
Ok, here goes

Code is attached in arduino formatting (as INO file). Code also references a couple LIBs but they should be in arduino program by default. This is literally all the code i have on this, soo...

Also attached is the schematic and rough board layout in EAGLE.


Posted by: MarkT
Insert Quote
We need to see your circuit to understand this, some of your code suggests you are clocking timer2's prescaler at 32768Hz, is this true and if so how?

To be honest, I have no idea what you just said. I am just trying to get timer2 to inturrupt every 8s from a 32.768 crystal. Most of my code was copied from sparkfuns example, so it *should* work, but as I said, hardware and software level inturrupts are not exactly my strongpoint.


Posted by: PaulS
Not working saves even more power? Just trying to eliminate possible areas of conflict.

Yep :D, well at least at the moment...

I'd check... I also don't see where you connect that ISR to that pin. The attachInterrupt() function is usually called to make an association.
I think this deos it
Code: [Select]

//Setup external INT0 interrupt
 EICRA = (1<<ISC01); //Interrupt on falling edge
 EIMSK = (1<<INT0); //Enable INT0 interrupt


Which pins would that be? What code, of yours, is supposed to respond to those interrupts?
Pins TOSC1 & TOSC2 if I got the names right. Just XTAL1 and XTAL2 on the schematic. This code is what is supposed to be run when it interrupts.
Code: [Select]

SIGNAL(TIMER2_OVF_vect){
 seconds += 8; //We sleep for 8 seconds instead of 1 to save more power
 //seconds++; //Use this if we are waking up every second

 if(seconds > 59){
   minutes++;
   seconds = seconds - 59;
 }

 if(minutes > 59){
   hours++;
   minutes = minutes - 59;
 }

Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: MarkT on Sep 19, 2012, 12:10 am
Can't read those files, despite having Eagle, wrong version - if you export as image then its much more friendly to us (not everyone uses Eagle).  In general it helps to present all the relevant information (provide links, photos, etc)

Looking at the bigTime thing on sparkfun it seems all confused (comments about not using delay / delayMicroseconds, yet it does use them.  It seems to be using a non-standard fuse option on the ATmega, namely the internal RC oscillator (allowing TOSC1/2 to be used as timer clock).  Is your microcontroller suitable programmed with the right fuse options?  Note if using the internal oscillator you may have to use an ICMP programmer to upload sketches (I may be a bit rusty about this).

The quality control on sparkfun site is not the best I've seen BTW, so I wouldn't trust the online files to necessarily be up-to-date or even self-consistent (if not tell them so they notice and fix it for others).

Other comments on the sparkfun page imply a standard Arduino Mini 8MHz can be used, which obviously is not the case as the crystal is hard-wired on that board yet the sparkfun schematic shows a 32,768Hz xtal, not an 8MHz one.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 19, 2012, 12:28 am
Images! :)
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 19, 2012, 12:41 am
I used an ICSP programmer to set the fuse settings accordingly. I think they are correct, AVR studio 4 says its using the internal oscillator. I will email sparkfun and see if that is the most recent version of the code and see what they are doing- anything specific i need to ask?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 01:18 am
I'm a little curious about this bit:

Code: [Select]

  if(seconds > 59){
    minutes++;
    seconds = seconds - 59;
  }

  if(minutes > 59){
    hours++;
    minutes = minutes - 59;
  }


Aren't there 60 seconds to a minute, and 60 minutes to an hour?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: MarkT on Sep 19, 2012, 01:19 am
Hmmm, have you proof that the 32768 xtal is actually oscillating?  Have you calculated load caps as per table 8-8 and associated text in the datasheet?  Have you read section 17.9 of the datasheet and checked the code is DTRT?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 01:28 am
Why do you have 0.1 uF caps between the crystal and earth? That wasn't in the Sparkfun circuit.

Here, to save other people searching for it: https://www.sparkfun.com/products/10870
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 19, 2012, 02:02 am
They are not used at the moment, they are just places for xtal load caps but I havnt loaded the crystal at all.


*******
I'm a little curious about this bit:

Code:
  if(seconds > 59){
    minutes++;
    seconds = seconds - 59;
  }

  if(minutes > 59){
    hours++;
    minutes = minutes - 59;
  }

Aren't there 60 seconds to a minute, and 60 minutes to an hour?

Yes, but I am using > not >=. So anything greater than 59 (60), will go back down to 1. Course I need to add 0s to it but havnt yet.




*****
Hmmm, have you proof that the 32768 xtal is actually oscillating?  Have you calculated load caps as per table 8-8 and associated text in the datasheet?  Have you read section 17.9 of the datasheet and checked the code is DTRT?

I don't have an oscilloscope but I can check (earliest I could do it is tomorrow). I think somewhere else in the data sheet it says not to use load crystals for that slow of a crystal, I have not added them (but can).

Read through 17.9 and didnt undertand much of it :( , or rather, I understood most of it, just not how to create a practical example.



Thank you all so much with your help thus far, I really appreciate it and am eager to learn more. Sorry my coding is not up to par, but i really dont code that often so I never quite "learned" it. Mostly just taught myself...
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 02:34 am
May I suggest you learn how to use the "quote" button above the posting box? Putting your comments and other people's all together looks confusing. eg.

Quote
Yes, but I am using > not >=. So anything greater than 59 (60), will go back down to 1. Course I need to add 0s to it but havnt yet.


60 is not the only thing greater than 59. For example, 61 is. And since you are adding 8 it is more likely you will get from 56 to 64.

Code: [Select]
  seconds += 8; //We sleep for 8 seconds instead of 1 to save more power
  //seconds++; //Use this if we are waking up every second

  if(seconds > 59){
    minutes++;
    seconds = seconds - 59;
  }


My point is that after adding 1 to the number of minutes, surely you need to subtract 60 from the number of seconds? Not 59?

Quote
They are not used at the moment, they are just places for xtal load caps but I havnt loaded the crystal at all.


So the circuit you posted is not the one you are using?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 19, 2012, 03:01 am

60 is not the only thing greater than 59. For example, 61 is. And since you are adding 8 it is more likely you will get from 56 to 64.


I am adding 8s, but taking off 60 will keep the timing in check. If I reset every 60, the timer could be anywhere up to 8 seconds off. Makes sense to me.
Eg:
Seconds = 56,
then the timer overflows, seconds now = 64. Seconds - 60 = 4. Now if I went to 0 on that, what happened to the extra 4 seconds the timer counted??




My point is that after adding 1 to the number of minutes, surely you need to subtract 60 from the number of seconds? Not 59?
True, thanks for correcting me on that. Guess I got messed up on timing in my head :P . Wasnt exactly having a great day when I wrote it :D



So the circuit you posted is not the one you are using?

Everything is the exact circuit I am using, but I put the load caps in for my board design, just in case I needed some load caps on the crystal. They are merely placeholders. Sorry for the confusion this might have caused.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: GoldStar611 on Sep 19, 2012, 03:59 am
I don't see any variables being declared as volatile. If an interrupt service routine is going to update variables they should be marked as volatile.

Specifically:
seconds -- TIMER2_OVF_vect
minutes -- TIMER2_OVF_vect
hours -- TIMER2_OVF_vect
show_the_time -- INT0_vect
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 19, 2012, 04:33 am
Like this?
Code: [Select]

volatile long seconds = 54;
volatile int minutes = 24;
volatile int hours = 3;


So... volatile just means they are handled from RAM instead of being loaded and changed from a memory bank?

Edit: BTW doing this even with the show_the_time variable didn't seem to change anything, still no incrementing.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: GoldStar611 on Sep 19, 2012, 04:52 am
Consider this code which "checks" the value of foo, a global variable that gets updated via ISR
Code: [Select]

unsigned int foo = 0;
ISR(blahblah)
{
//update foo here
}

void loop ()
{
while (foo == 0); /wait for foo to get updated
//do stuff after foo gets updated
}


Your while loop would never exit, because the compiler will read from the register(memory bank) which previously held "latest" value of foo instead of force reading the actual value from RAM.

Check out Nicks awesome page about interrupts: http://www.gammon.com.au/forum/?id=11488 (http://www.gammon.com.au/forum/?id=11488)

Is there any way you can add in some debugging functions to send some output to the serial port, etc? I think that will be the easiest way to debug whats going on instead of just eye-balling the code and making changes
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: GoldStar611 on Sep 19, 2012, 05:01 am
I also didn't see anything referring to #include <interrupts.h> (I didn't need to in my case) nor interrupts() or sei()
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 19, 2012, 05:11 am
Ok, will read through the page. Looks very interesting and I am understanding most of what I read so far.

I /can/ create a debug version, sorta. Mainly the only thing I have that does serial is an arduino board (Uno), or my avrisp mkii/UsbASP (which I dont know if it does serial).

I suppose I could just program the board to output serial, and then just connect RX and TX to the respective/opposite (RX to TX, TX to RX, etc) pins on my Uno board? (I assume RX and TX are all thats needed for the serial output?). That shouldnt be hard. If I am right about the serial comms, it shouldnt be hard...
Title: Re: Timer2 Interrupts REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 05:36 am
Let's get down to basics. You want the timer interrupt to work, right? All the rest is mumbo-jumbo for now. Here is a cut-down sketch:

Code: [Select]

#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers

const byte LED = 8;

//The very important 32.686kHz interrupt handler
ISR (TIMER2_OVF_vect)
{
}

//The interrupt occurs when you push the button
void buttonPress (void)
{
}

void setup()
 {                
 pinMode (LED, OUTPUT);  
 digitalWrite (2, HIGH);  // pull-up

 //Power down various bits of hardware to lower power usage  
 set_sleep_mode (SLEEP_MODE_PWR_SAVE);

 //Shut off ADC, TWI, SPI, Timer1

 ADCSRA &= ~ _BV (ADEN);     // Disable ADC
 ACSR = _BV (ACD);           // Disable the analog comparator
 DIDR0 = 0x3F;               // Disable digital input buffers on all ADC0-ADC5 pins
 DIDR1 = _BV (AIN1D) | _BV (AIN0D); //Disable digital input buffer on AIN1/0

 power_twi_disable();
 power_spi_disable();
 power_usart0_disable();
 power_timer1_disable();
 
 //Setup TIMER2
 TCCR2A = 0;
 TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);
 ASSR   = _BV (AS2);         // Enable asynchronous operation
 TIMSK2 = _BV (TOIE2);       // Enable the timer 2 interrupt

 attachInterrupt (0, buttonPress, FALLING);
 }

void loop()
 {
 digitalWrite (LED, LOW);
 sleep_mode();   //  Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button
 digitalWrite (LED, HIGH);  
 }


On my Uno (which has a 16 MHz resonator) this outputs a pulse on pin 8 with a period of 16.327 mS which is what you expect.

Code: [Select]
1/16 MHz = period of 62.5 nS
62.5 nS * 1024 * 256 = 16.384 mS


(The figure isn't exact, but the resonator would be off by about 0.2% or so).

The 1024 is the prescaler and the 256 is how many counts the timer does before overflowing.

An LED on pin 8 glows faintly (you could make it brighter by putting a small delay after writing it high.

So I suggest you test that. If you can't get the LED to glow there is something fundamentally wrong with the hardware.
Title: Re: Timer2 Interrupts REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 06:44 am
For my own interest I wired up a "bare bones" board and uploaded that exact program. It worked!

(http://www.gammon.com.au/images/Arduino/Arduino_forum_123285.png)

Note that there was a gap of 8 seconds between pulses.

This is the board:

(http://www.gammon.com.au/images/Arduino/Arduino_forum_123285b.jpg)


The current drain during the sleeping part was 21 uA.

You can save a considerable amount of power by turning off brown-out enable. This amended sketch does that:

Code: [Select]

#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers

const byte LED = 8;

//The very important 32.686kHz interrupt handler
ISR (TIMER2_OVF_vect)
  {
  }

//The interrupt occurs when you push the button
void buttonPress (void)
  {
  }

void setup()
  {               

  pinMode (LED, OUTPUT); 
  digitalWrite (2, HIGH);  // pull-up

  //Power down various bits of hardware to lower power usage 
  set_sleep_mode (SLEEP_MODE_PWR_SAVE);
  sleep_enable();

  //Shut off ADC, TWI, SPI, Timer1

  ADCSRA &= ~ _BV (ADEN);     // Disable ADC
  ACSR = _BV (ACD);           // Disable the analog comparator
  DIDR0 = 0x3F;               // Disable digital input buffers on all ADC0-ADC5 pins
  DIDR1 = _BV (AIN1D) | _BV (AIN0D); //Disable digital input buffer on AIN1/0

  power_twi_disable();
  power_spi_disable();
  power_usart0_disable();
  power_timer1_disable();
 
  //Setup TIMER2
  TCCR2A = 0;
  TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);
  ASSR   = _BV (AS2);         // Enable asynchronous operation
  TIMSK2 = _BV (TOIE2);       // Enable the timer 2 interrupt

  attachInterrupt (0, buttonPress, FALLING);
  }  // end of setup

void loop()
  {
  digitalWrite (LED, LOW);
  // turn off brown-out enable in software
  MCUCR = _BV (BODS) | _BV (BODSE);  // turn on brown-out enable select
  MCUCR = _BV (BODS);        // this must be done within 4 clock cycles of above
  sleep_cpu ();              // sleep within 3 clock cycles of above
  digitalWrite (LED, HIGH); 
  }  // end of loop


Running that sketch, while the LED was not flashing (ie. during the 8 second interval) it used 1.4 uA of current.

Note that the flash is extremely hard to see. Even with a higher-power LED it is almost invisible. But the logic analyzer detected it.
Title: Re: Timer2 Interrupts REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 11:59 am
http://www.gammon.com.au/power
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Sep 19, 2012, 11:43 pm
Further tests show that if you drop the supply voltage to 3.3V (which may be reasonable) you can reduce the sleep power consumption to around 1 uA.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: MarkT on Sep 20, 2012, 02:34 am
Which implies years from a lithium button cell, 10 years at 1uA ~= 87mAh
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 20, 2012, 04:52 am
Ok, tested Nicks sketch (Oh, hey nick!!! Love your work, great page on power savings. Muchas Gracias :) ). Nothing.

I tested a bare bones board as well as an arduino board, and got some pulses on pin 8 (I could very faintly see them on an oscilloscope, and added a delay(100); after the pin high so I could see it on a bare bones. This was all done with a 16mHz crystal, so it IS working.

However, I tried it with 4 different 32.768 crystals from 2 different manufacturers. Nothing, nada, zilch, uno (oh wait, that means one...). Anyways, no overflows, nothing in the oscilloscope. I got *some* results trying to test if the oscillator was running but I heard you cant do it with an oscilloscope very well, and am anyways not sure what the results should be..

So it seems I am the victim of possibly a very bad run of crystals... Or maybe something else is up that wont let the low speed crystals run. Any thoughts? Where do you get your verified crystals from? I prefer digikey (where most of these xtals are from) (digikey ships to me in < 3 days, on the cheapest shipping, yay!), but am open to other suggestions.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Sep 20, 2012, 04:58 am
I can't remember where I got mine (it was a while ago), maybe Element14. You could try a 20 pf cap between each leg and ground, but that's just a guess. I didn't use one as you can see from the photo.

Are you sure you have the processor configured to run off the internal oscillator? It would be slow if it is using the crystal for its processor clock.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Sep 30, 2012, 11:45 pm
Sorry i got back late.... nothing. Only keeping clock settings as normal provided blinking... anything with the internal clock just fails on me.... WHY?? :( really ticked at myself... this is starting to get out of hand...
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 01, 2012, 12:27 am
What fuses are you using??
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 02, 2012, 05:25 am
These ones, according to my fuse calculator sketch:

Code: [Select]

Atmega fuse calculator.
Written by Nick Gammon.
Entered programming mode OK.
Signature = 0x1E 0x95 0x0F
Processor = ATmega328P
Flash memory size = 32768
LFuse = 0xE2
HFuse = 0xDA
EFuse = 0xFD
Lock byte = 0xEF
Clock calibration = 0x85
External Reset Disable.................. [ ]
Debug Wire Enable....................... [ ]
Enable Serial (ICSP) Programming........ [X]
Watchdog Timer Always On................ [ ]
Preserve EEPROM through chip erase...... [ ]
Boot into bootloader.................... [X]
Divide clock by 8....................... [ ]
Clock output............................ [ ]
Bootloader size: 2048 bytes.
Start-up time: SUT0: [X]  SUT1: [ ] (see datasheet)
Clock source: calibrated internal oscillator.
Brownout detection at: 2.7V.



Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 07, 2012, 02:00 am
My gosh I dont have clue what is up with this stupid timer2.

I have discarded the interrupts for now. It seems it is a different problem.

After uploading an Arduino Pro 8mhz bootloader to the chip, the LED blinks at around 1/2 second pulses (using an UNO board). Going into AVR studio, apparently this sets the fuses to select the crystal on the board as oscillator. Change that to internal, and the LED blinks every second.

However, it seems not to use timer2 whatsoever. Nada. Zilch. And I have no idea why it simply refuses to use any timer asynchronously. Everything seems to base off the internal timer- wther or not there is a timer connected to the TOSC pins or not.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 07, 2012, 03:45 am
Can you show a photo of your setup? And your current code.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: JChristensen on Oct 07, 2012, 03:59 am
I did a project a while back that has some similar features, namely clocking Timer2 from a 32.768kHz crystal, generating an interrupt every 8 seconds, and sleeping in between interrupts:
http://adventuresinarduinoland.blogspot.com/2012/02/high-tech-night-light.html

Code and schematic are on github, see link at the end of the post.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 07, 2012, 10:17 pm
Ok, my setup

I am using an arduino Uno, connected via ICSP to an Amtel MKII programmer (clone) (I should note that the clone seems to work perfectly).

(also, sorry for the blurrycam photos and jumbled wiring. Using a cell phone and the wiring, though jumbled, is working)

Ignore the chip in the breadboard too- that one is fried. Just using it to show the pinout of things. At the moment I am just trying to get this to work on the UNO board before moving to a breadboard

The code i am using is the code you posted on the last page.
Code: [Select]
#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers

const byte LED = 8;

//The very important 32.686kHz interrupt handler
ISR (TIMER2_OVF_vect)
{
}

//The interrupt occurs when you push the button
void buttonPress (void)
{
}

void setup()
 {                
 pinMode (LED, OUTPUT);  
 digitalWrite (2, HIGH);  // pull-up

 //Power down various bits of hardware to lower power usage  
 set_sleep_mode (SLEEP_MODE_PWR_SAVE);

 //Shut off ADC, TWI, SPI, Timer1

 ADCSRA &= ~ _BV (ADEN);     // Disable ADC
 ACSR = _BV (ACD);           // Disable the analog comparator
 DIDR0 = 0x3F;               // Disable digital input buffers on all ADC0-ADC5 pins
 DIDR1 = _BV (AIN1D) | _BV (AIN0D); //Disable digital input buffer on AIN1/0

 power_twi_disable();
 power_spi_disable();
 power_usart0_disable();
 power_timer1_disable();
 
 //Setup TIMER2
 TCCR2A = 0;
 TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);
 ASSR   = _BV (AS2);         // Enable asynchronous operation
 TIMSK2 = _BV (TOIE2);       // Enable the timer 2 interrupt

 attachInterrupt (0, buttonPress, FALLING);
 }

void loop()
 {
 digitalWrite (LED, LOW);
 sleep_mode();   //  Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button
 digitalWrite (LED, HIGH);  
 }


Running that on the UNO seems to work- as long as you are not running off the internal oscillator.


As for the chip itself, I have attached a photo of what the fuse settings are (currently). At this time I was trying a different bootloader which is why the bootloader fuse size is kinda off. Re-burning it to UNO bootloader.Have tried with UNO bootloader, Pro 8mhz bootloader, etc, with and without changing fuse settings to internal oscillator
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 07, 2012, 10:18 pm
Last photo, dang forum limitations :)
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 07, 2012, 10:31 pm
Quote
Ignore the chip in the breadboard too- that one is fried. Just using it to show the pinout of things. At the moment I am just trying to get this to work on the UNO board before moving to a breadboard


I'm confused now. You aren't using the breadboard? So the point of that photo is?

Quote
At the moment I am just trying to get this to work on the UNO board before moving to a breadboard ...


So we can discard the breadboard, and you are talking about getting the Timer2 to work on a Uno? With or without the 32 KHz crystal?

Quote
Everything seems to base off the internal timer- wther or not there is a timer connected to the TOSC pins or not.


How would you get to those pins on the Uno?
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 07, 2012, 10:47 pm
Aha! Finally something...
To test to see if I could actually count using the interrupt, I tried this sketch:
Code: [Select]

   
   
   
   
   #include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers

const byte LED = 8;
long time;

//The very important 32.686kHz interrupt handler
ISR (TIMER2_OVF_vect)
{time++;}

//The interrupt occurs when you push the button
void buttonPress (void)
{
}

void setup()
 {      
time = 0;    
 pinMode (LED, OUTPUT);  
 digitalWrite (2, HIGH);  // pull-up

 //Power down various bits of hardware to lower power usage  
 set_sleep_mode (SLEEP_MODE_PWR_SAVE);

 //Shut off ADC, TWI, SPI, Timer1

 ADCSRA &= ~ _BV (ADEN);     // Disable ADC
 ACSR = _BV (ACD);           // Disable the analog comparator
 DIDR0 = 0x3F;               // Disable digital input buffers on all ADC0-ADC5 pins
 DIDR1 = _BV (AIN1D) | _BV (AIN0D); //Disable digital input buffer on AIN1/0

 power_twi_disable();
 power_spi_disable();
 power_usart0_disable();
 power_timer1_disable();
 
 //Setup TIMER2
/* TCCR2A = 0;
 TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);
 ASSR   = _BV (AS2);         // Enable asynchronous operation
 TIMSK2 = _BV (TOIE2);       // Enable the timer 2 interrupt
*/

TIMSK2 = 0;                        //stop timer2 interrupts while we set up
   ASSR = _BV(AS2);                   //Timer/Counter2 clocked from external crystal
   TCCR2A = 0;                        //override arduino settings, ensure WGM mode 0 (normal mode)
   TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);    //prescaler clk/1024 -- TCNT2 will overflow once every 8 seconds
   TCNT2 = 0;                         //start the timer at zero
   while (ASSR & (_BV(TCN2UB) | _BV(TCR2AUB) | _BV(TCR2BUB))) {}    //wait for the registers to be updated    
   TIFR2 = _BV(OCF2B) | _BV(OCF2A) | _BV(TOV2);                     //clear the interrupt flags
   TIMSK2 = _BV(TOIE2);               //enable interrupt on overflow
   
   
 attachInterrupt (0, buttonPress, FALLING);
 }

void loop()
 {
 digitalWrite (LED, LOW);
 delay(time);
 sleep_mode();   //  Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button
 digitalWrite (LED, HIGH);  
 delay(time);
 }


An LED on pin 8 blinked really quickly than slowed.

So this proves that the timer is interrupting, however, this was done with the fuses set as
Extended : 0xFE
High : 0xD6
Low : 0xFF (external 8 mHz oscillator)

Edit: To Nick
Sorry, my prototyping process is a bit edgy at the moment. I have not really had any experience actually trying to, well, /professionally/ prototype something.
I am simply using the breadboard to test things I cannot on the UNO board (example, taking off the oscillator, or trying a different speed crystal).

Actually... well, now I see some of my mistakes... Im just gonna move the whole thing to a breadboard and wire up ICSP to that. I have a 16mhz crystal so I can upload fine using ICSP...
The final product I want is an arduino chip that has an RTC running off Timer2 interrupts, whilst using the internal oscillator to run code that the interrupt will eventually trigger
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 09, 2012, 06:00 am
Whole thing is on a breadboard, still nothing. Asking around for some new chips, etc. IDK whats wrong with this..


-My internal timer seems to work, I can do LED stuff and the timing works without a crystal
-Interrupts *seem* to work when I have the fuses set to use an EXTERNAL oscillator

So I think perhaps something is up when the chip goes into asynchronous timer mode. I'm guessing somehow my chip doesnt get there.

Only think i can find different between your chips and mine in terms of fuses is the clock calibration fuse, which I don't exactly know what that is...
Oh, one more thing, what bootloader did you format your chips on before doing this?
I know this is a pretty weird problem, and I hate to spend a lot of your time on it, but any help would be appreciated greatly.
Thanks!!
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 09, 2012, 06:19 am
You don't really "format" a chip with a bootloader. I personally just uploaded the sketch, I think (it was 19th September) by using my "sketch uploader" here:

http://www.gammon.com.au/forum/?id=11638

Or maybe it had a bootloader on it. The important thing is, you get your sketch into "low" program memory (where sketches normally go).

If you replicate what I had here:

(http://www.gammon.com.au/images/Arduino/Arduino_forum_123285b.jpg)

It should work. Judging by what I posted further up:

Code: [Select]

Atmega fuse calculator.
Written by Nick Gammon.
Entered programming mode OK.
Signature = 0x1E 0x95 0x0F
Processor = ATmega328P
Flash memory size = 32768
LFuse = 0xE2
HFuse = 0xDA
EFuse = 0xFD
Lock byte = 0xEF
Clock calibration = 0x85
External Reset Disable.................. [ ]
Debug Wire Enable....................... [ ]
Enable Serial (ICSP) Programming........ [X]
Watchdog Timer Always On................ [ ]
Preserve EEPROM through chip erase...... [ ]
Boot into bootloader.................... [X]
Divide clock by 8....................... [ ]
Clock output............................ [ ]
Bootloader size: 2048 bytes.
Start-up time: SUT0: [X]  SUT1: [ ] (see datasheet)
Clock source: calibrated internal oscillator.
Brownout detection at: 2.7V.


The chip had a bootloader on it, and the fuses are as stated there.

Quote
-Interrupts *seem* to work when I have the fuses set to use an EXTERNAL oscillator


I think you are getting confused. Interrupts work, whether or not you are using the external oscillator.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 10, 2012, 04:53 am
FINALLY!!!!!! I dont know exactly what I did, but it works. Odd.
I think I basically had to set the fuses to use the internal oscillator, then proceed to burn a bootloader that makes use of the internal oscillator (I just used the stock "Arduino on a breadboard option")
From there I uploaded the sketch, and it worked

Still not verifying that was exactly what I did, I was basically just messing around, trying to get ANYTHING to work on the chip.

Working on debugging my code currently. It works for the mostpart but by button interrupt stops working after it is used 3 times... Weird.

Thanks so much for your help!!!!
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 10, 2012, 05:15 am
Looks good, glad it's working now.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: astroboy907 on Oct 11, 2012, 05:45 am
Nah, I'm back for more....

Ok, so basically I got my code up and mostly running, but this time I am having trouble with the hardware interrupts.

My code:
Code: [Select]


#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers
//#include <interrupts.h>
#include <avr/interrupt.h>


#define TRUE 1
#define FALSE 0

//Set this variable to change how long the time is shown on the watch face. In milliseconds so 1677 = 1.677 seconds
int show_time_length = 2000;
volatile int show_the_time = FALSE;

//You can set always_on to true and the display will stay on all the time
//This will drain the battery in about 15 hours
int always_on = FALSE;

volatile long seconds = 54;
volatile int minutes = 24;
volatile int hours = 3;



//Careful messing with the system color, you can damage the LEDs if
//you assign the wrong color. If you're in doubt, set it to red and load the code,
//then see what the color is.
#define RED  1
int systemColor = RED;
int display_brightness = 15000; //A larger number makes the display more dim. This is set correctly below.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Pin definitions
int hour8 = A4; //Hour 8
int hour4 = A2; //Hour 4
int hour2 = 12; //Hour 2
int hour1 = 10; //Hour 1

int minute32 = A0; //Minute 32
int minute16 = A3; //Minute 16
int minute8 = A1; //Minute 8
int minute4 = 13; //Minute 4
int minute2 = 11; //Minute 2
int minute1 = 9; //Minute 1

int theButton = 2;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//The very important 32.686kHz interrupt handler
//The very important 32.686kHz interrupt handler
ISR (TIMER2_OVF_vect)
{
 seconds += 8; //We sleep for 8 seconds instead of 1 to save more power
 //seconds++; //Use this if we are waking up every second

 if(seconds > 59){
   minutes++;
   seconds = seconds - 59;
 }

 if(minutes > 59){
   hours++;
   minutes = minutes - 59;
 }


 /*
//Update the minutes and hours variables
  minutes += seconds / 60; //Example: seconds = 2317, minutes = 58 + 38 = 96
  seconds %= 60; //seconds = 37
  hours += minutes / 60; //12 + (96 / 60) = 13
  minutes %= 60; //minutes = 36
  */

 if(hours > 12) hours -= 12;

}
//The interrupt occurs when you push the button


ISR(INT0_vect){

 //When you hit the button, we will need to display the time
 //if(show_the_time == FALSE)
 show_the_time = TRUE;

}


void setup() {                
 //To reduce power, setup all pins as inputs with no pullups
 for(int x = 1 ; x < 18 ; x++){
   pinMode(x, INPUT);
   digitalWrite(x, LOW);
 }

 pinMode(theButton, INPUT); //This is the main button, tied to INT0
 digitalWrite(theButton, HIGH); //Enable internal pull up on button

 //These pins are used to control the display
 pinMode(hour8, OUTPUT);
 pinMode(hour4, OUTPUT);
 pinMode(hour2, OUTPUT);
 pinMode(hour1, OUTPUT);

 pinMode(minute32, OUTPUT);
 pinMode(minute16, OUTPUT);
 pinMode(minute8, OUTPUT);
 pinMode(minute4, OUTPUT);
 pinMode(minute2, OUTPUT);
 pinMode(minute1, OUTPUT);


//Power down various bits of hardware to lower power usage  
 set_sleep_mode (SLEEP_MODE_PWR_SAVE);

 //Shut off ADC, TWI, SPI, Timer1

 ADCSRA &= ~ _BV (ADEN);     // Disable ADC
 ACSR = _BV (ACD);           // Disable the analog comparator
 DIDR0 = 0x3F;               // Disable digital input buffers on all ADC0-ADC5 pins
 DIDR1 = _BV (AIN1D) | _BV (AIN0D); //Disable digital input buffer on AIN1/0

 power_twi_disable();
 power_spi_disable();
 power_usart0_disable();
 power_timer1_disable();
 
 //Setup TIMER2
/* TCCR2A = 0;
 TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);
 ASSR   = _BV (AS2);         // Enable asynchronous operation
 TIMSK2 = _BV (TOIE2);       // Enable the timer 2 interrupt
*/

TIMSK2 = 0;                        //stop timer2 interrupts while we set up
   ASSR = _BV(AS2);                   //Timer/Counter2 clocked from external crystal
   TCCR2A = 0;                        //override arduino settings, ensure WGM mode 0 (normal mode)
   TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);    //prescaler clk/1024 -- TCNT2 will overflow once every 8 seconds
   TCNT2 = 0;                         //start the timer at zero
   while (ASSR & (_BV(TCN2UB) | _BV(TCR2AUB) | _BV(TCR2BUB))) {}    //wait for the registers to be updated    
   TIFR2 = _BV(OCF2B) | _BV(OCF2A) | _BV(TOV2);                     //clear the interrupt flags
   TIMSK2 = _BV(TOIE2);               //enable interrupt on overflow
   


//Setup external INT0 interrupt
 EICRA = (1<<ISC01); //Interrupt on falling edge
EIMSK = (1<<INT0); //Enable INT0 interrupt



sei(); //Enable global interrupts

 //System clock futzing
 //CLKPR = (1<<CLKPCE); //Enable clock writing
 //CLKPR = (1<<CLKPS3); //Divid the system clock by 256



 //Display brightness changes based on color
 if(systemColor == RED) {
   display_brightness = 4500; //The higher the number, the lower the brightness

 }
 else {
   display_brightness = 1;

 }


 showTime(); //Show the current time for a few seconds

 sei(); //Enable global interrupts
 
 
  // open the serial port at 9600 bps:
 Serial.begin(9600);
 
 Serial.println("Hola!!");
 
}

void loop() {
 if(always_on == FALSE)
 Serial.println("Hola!!");
 Serial.println("Hola!!");
 
   sleep_mode(); //Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button

 if(show_the_time == TRUE || always_on == TRUE) {

   /*Serial.print(hours, DEC);
    Serial.print(":");
    Serial.print(minutes, DEC);
    Serial.print(":");
    Serial.println(seconds, DEC);*/

   showTime(); //Show the current time for a few seconds

   //If you are STILL holding the button, then you must want to adjust the time
   if(digitalRead(theButton) == LOW){
     setTime();
   }
   show_the_time = FALSE; //Reset the button variable
 }
}

void showTime() {

 //Here is where we display the time and PWM the LEDs
 

 //Now show the time for a certain length of time
 long startTime = millis();
 while( (millis() - startTime) < show_time_length) {

   lightLeds();

   
   if(display_brightness > 0){ //PWM only if brightness is not full
     delayMicroseconds(display_brightness);
   }
 }

}





void lightLeds() {
 //Turns correct outputs on
 

 //Pin assignments
 //Minutes





 switch(hours) {

 case 12:
   digitalWrite(hour8, HIGH); // Hour is 12
   digitalWrite(hour4, HIGH);
   digitalWrite(hour2, LOW);
   digitalWrite(hour1, LOW);
   break;

// ....

 case 1:
   digitalWrite(hour8, LOW); // Hour is 1
   digitalWrite(hour4, LOW);
   digitalWrite(hour2, LOW);
   digitalWrite(hour1, HIGH);
   break;


 }


 switch(minutes){

 case 59:
   digitalWrite(minute32, HIGH); //Minute is 59
   digitalWrite(minute16, HIGH);
   digitalWrite(minute8, HIGH);
   digitalWrite(minute4, LOW);
   digitalWrite(minute2, HIGH);
   digitalWrite(minute1, HIGH);
   break;

// .....

 case 1:
   digitalWrite(minute32, LOW); //Minute is 1
   digitalWrite(minute16, LOW);
   digitalWrite(minute8, LOW);
   digitalWrite(minute4, LOW);
   digitalWrite(minute2, LOW);
   digitalWrite(minute1, HIGH);
   break;

 }


 if(display_brightness > 0){ //Only PWM if brightness is not full
   delayMicroseconds(display_brightness);

   digitalWrite(hour8, LOW); //write pins low to get "dimming" effect
   digitalWrite(hour4, LOW);
   digitalWrite(hour2, LOW);
   digitalWrite(hour1, LOW);

   digitalWrite(minute32, LOW);
   digitalWrite(minute16, LOW);
   digitalWrite(minute8, LOW);
   digitalWrite(minute4, LOW);
   digitalWrite(minute2, LOW);
   digitalWrite(minute1, LOW);
 }

}





Heres the problem point
Code: [Select]

//The interrupt occurs when you push the button


ISR(INT0_vect){

 //When you hit the button, we will need to display the time
 //if(show_the_time == FALSE)
 show_the_time = TRUE;

}


If I have it just set as
Code: [Select]

ISR(INT0_vect)


The interrupt is only able to be called once or twice, then the arduino seems to not respond to the interrupt anymore.

Setting it to
Code: [Select]

ISR(EXT_INT0_vect)


seems to fix it, but then the 32khz clock doesn't "tick" forward (perhaps a bit of interrupt clashing here?)

I dont really know what is going on, I have checked most of the code but i don't get what is causing the problem.
I am just using a wire-to-ground to trigger the interrupt, maybe i need to wire in a straight button... I'm not sure. Looks and seems a bit like a debounce issue to me.
I did have to edit my code to fit into the forum, cutting out the time-setting part, and some of the comments. Just ask if you need the full deal, I kept all the loop() code in though
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 11, 2012, 05:54 am
Just use attachInterrupt. You don't need to muck around with ISR(blah) and doing it all yourself. It just gets confusing.

I wouldn't be doing this:

Code: [Select]

  Serial.println("Hola!!");


That's likely to be generating interrupts.
Title: Re: Timer2 Interrups REFUSE to work! :(
Post by: nickgammon on Oct 11, 2012, 05:54 am
http://www.gammon.com.au/interrupts