Trouble with timer/counter interrupt on ATtiny 85

Hi all.

I am trying to use the ATtiny’s timer/counter 1 to perform an action a couple times per second. In this example I am just trying to toggle an LED. When I upload the code the LED doesnt go on or off at all. From what I can tell I have everything configured correctly, and have based my code off of others’ code like this video.

Any ideas are welcome :slight_smile:

//Red LED on PB0
//Clock is 8MHz internal
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

int ledState = 1;

void setup() {

  pinMode(0,OUTPUT);

  TCCR1 |= 0b00001111;  //select maximum CK/16384 prescaler Pg.89
  TIMSK |= 0b00000010;  //set TOIE1: Timer/Counter1 Overflow Interrupt Enable Pg.92
  sei();  //set global interrupt flag to enable interrupts
}

void loop() {
  
  digitalWrite(0,ledState); //write the state of the LED
}


//Timer counter ISR to change the flag for LED state
ISR(TIMER1_OVF_vect){
  if (ledState = 1) ledState = 0;
  else ledState = 1;
}

Couple of things:

  • Firstly, you must declare ledstate as volatile - it is updated/used in an interrupt routine.
  • You did not say what clock speed you have set for the ATtiny85, so I am going to assume 16MHz (16MHz (Using PLL)) - you are using ATTinyCore? (if not, you should).
  • With the above assumption you will get 976,5 clocks per second to the counter register.
  • Counter 1 being an 8 bit counter means you get an overflow about three times a second. So that LED will flicker quite rapidly.
  • In your loop, I would only do the digitalWrite on a ledstate change - as is you are going to digitalWrite thousands of times a second.
  • Lastly with "TIMSK |= 0b00000010;" you are enabling timer 0 for overflow. Use "TIMSK |= 0b000000100;" for timer 1 - do check the datasheet.
    Hope that helps.

Willem

Couple of things:

Firstly, you must declare ledstate as volatile - it is updated/used in an interrupt routine.
You did not say what clock speed you have set for the ATtiny85, so I am going to assume 16MHz (16MHz (Using PLL)) - you are using ATTinyCore? (if not, you should).
With the above assumption you will get 976,5 clocks per second to the counter register.
Counter 1 being an 8 bit counter means you get an overflow about three times a second. So that LED will flicker quite rapidly.
In your loop, I would only do the digitalWrite on a ledstate change - as is you are going to digitalWrite thousands of times a second.
Lastly with “TIMSK |= 0b00000010;” you are enabling timer 0 for overflow. Use “TIMSK |= 0b000000100;” for timer 1 - do check the datasheet.
Hope that helps.

Willem

Thank you very much for the detailed explanation!

-I completely forgot I needed to declare as volatile

-I am using the 8MHz internal clock. I was using the ATtiny core by David A. Mellis. I have now also installed the ATTiny core by SpenceKonde from your suggestion, the latter seems to have more features.

-With the 8MHz clock that gives about 2 triggers per second which is ok for my case, since this code is just a test of the counter. The actual application will be taking ADC measurements about twice a second.

-I have added code to only digitalWrite when the state changes, good point

-I have corrected TIMSK register, my stupid mistake

Here is the updated code:

//Red LED on PB0
//Clock is 8MHz internal
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

volatile uint8_t ledState = 1;
uint8_t prevLedState = 1;

void setup() {

  pinMode(0,OUTPUT);

  TCCR1 |= 0b00001111;  //select maximum CK/16384 prescaler Pg.89
  TIMSK |= 0b00000100;  //set TOIE1: Timer/Counter1 Overflow Interrupt Enable Pg.92
  sei();  //set global interrupt flag to enable interrupts
}

void loop() {
  if (prevLedState != ledState){
    digitalWrite(0,ledState); //write the state of the LED
    prevLedState = ledState;
  }
}

//Timer counter ISR to change the flag for LED state
ISR(TIMER1_OVF_vect){
  if (ledState = 1) ledState = 0;
  else ledState = 1;
}

Annoyingly even after the changes the LED does seem to be stuck constantly on, not flickering at all. I’m trying to figure out why it would be just constantly on now.

OK. All seems fine. I did not run your initial code but just did and yes, it does not work.

Here is your mistake:

 if (ledState = 1) ledState = 0;

You keep assigning ledstate = 1, which then is true and hence reassigned to 0.

A compare requires:

 if (ledState == 1) ledState = 0;

Should have picked that up on the first round. A classic C/C++ error.

On my 16MHz ATtiny85 it blinks with about a 0.7sec period. So, all as designed

Willem.

EDIT:

I was using the ATtiny core by David A. Mellis. I have now also installed the ATTiny core by SpenceKonde from your suggestion, the latter seems to have more features.

Unlike the DAMellis core, ATTinyCore is modern and actively maintained by our very own DrAzzy.

Oh dear, that is so frustrating, such a simple mistake, thank you for pointing it out. It all works as it should now. I've definitely never had so much trouble blinking an LED!

Glad I could assist in getting it all working.

We all have some of those days.

EDIT: Just as an after thought, you could do this (less prone to error):

  TIMSK |= 1 << TOIE1;    //0b00000100;  //set TOIE1: Timer/Counter1 Overflow Interrupt Enable Pg.92

Willem.