Code for a blinking LED with a timer on ATmega8

Edit: The solution is four posts below

Hey there,

my goal is to pulse an IR LED at 38 kHz but I still occupy myself with blinking LEDs visibly for debugging.
So the following sketch should do the same like the blink example: turning the LED on/off every second - only with a timer.

I want to do this with timers because I don't know any other method that is as accurate as timers. I need this accuracy because the IR reciever's sensitivity drops at 40 % if the transmission frequency is about +/- 10 % wrong. What a pity.

I've got an ATmega8 (still on a breadboard). (I burned the bootloader on it with the UNO as "Arduino NG or older w/ ATmega8")
Every sketch worked as it should except the examples including timers.

This is the code I am talking about:

volatile int val=0;

void setup() {
  pinMode(13,OUTPUT);
  
  OCR1A = 15624;
  TCCR1B |= (1 << WGM12);
  // Mode 4, CTC on OCR1A
  TIMSK |= (1 << OCIE1A);
  //Set interrupt on compare match
  TCCR1B |= (1 << CS12) | (1 << CS10);
  // set prescaler to 1024 and start the timer
  sei();
  // enable interrupts
}

void loop() {
}


ISR (TIMER1_COMPA_vect) {
    if (val == 1) {
      digitalWrite(13, HIGH);
      val = 0;
    } else {
      digitalWrite(13, LOW);
      val = 1;
    }
}

I found this example right here (in C):
https://sites.google.com/site/qeewiki/books/avr-guide/timer-on-the-atmega8
It looks pretty good to me so I expected it to work.

But the LED doesn't light up unfortunatley. (It has nothing to do with the circuit because the blink example works on the same pin)

I would be very thankful if you could tell me where I have a mistake in the code.
Or what else is wrong. Or any other ideas :wink:

Thank you very much

Alex

Btw. the TimerOne library worked pretty well for me as long as I was working on the UNO. But unfortunatley it only is constructed for ATmega168/328 :frowning:

  1. using digitalWrite() inside an ISR is a baaad thing. You want an ISR to finish quickly.
  2. where is your #include <interrupt.h> at the top?

May I suggest something like this for the ISR:

ISR (TIMER1_COMPA_vect) {
  PORTB ^= _BV(PB5);
}

Of course it is less portable.

volatile int val=0;
    if (val == 1) {
      digitalWrite(13, HIGH);
      val = 0;
    } else {
      digitalWrite(13, LOW);
      val = 1;
    }

For values of 0 or 1, you need an int?

madworm:

  1. using digitalWrite() inside an ISR is a baaad thing. You want an ISR to finish quickly.

madworm:

ISR (TIMER1_COMPA_vect) {

PORTB ^= _BV(PB5);
}

I was also using this snippet in my sketch for the UNO, in which I could simply attach the timer with TimerOne. But I wanted to eliminate every possible source of errors so I chose this style, which is much more accessible for me (as long as I'm testing).

madworm:
2) where is your #include <interrupt.h> at the top?

Arduino doesn't notice me about missing anything. The size of the compiled file is also the same if I put "#inclue <avr/interrupt.h>" on top or not. So, is this really necessary inside the Arduino enviroment?

PaulS:
For values of 0 or 1, you need an int?

No, of course not. :wink: I also could have taken a string. Just joking - as just mentioned above, I wanted to make it more accessible. Thank you for your coding style advice though.

The problem is solved finally. A colleague just helped me out with this great code.
So for anybody with the same problem who finds this thread via the board search or google, I post the code below.

It is actually like this:

void setup()
{
    pinMode(13,OUTPUT);
    
    // Disable interrupts while loading registers
    cli();
    
    // Set the registers; don't leave in the stuff with which
    // Arduino has initialized them.
    TCCR1A = 0;
    // Set mode
    TCCR1B = (1 << WGM12);
    
    // Set prescale values. (Could be done in same statement
    // as setting the WGM12 bit.)
    TCCR1B |= (1 << CS12) | (1 << CS10);
    
     // TIMSK1 for ATmega328, TIMSK for ATmega8
    TIMSK1 |= (1 << OCIE1A);
    
    // Set OCR1A after the mode selection, not before.
    OCR1A = 15624;
    
    // Enable global interrupts
    sei();
}

So, the prescale value in TCCR1B, which is in this case 1024 (see ATmega8 datasheet page 98), and the value in the Output Compare Register OCR1A define the frequency of the blinking LED on port 13:

ISR (TIMER1_COMPA_vect) {
  PORTB ^= _BV(PB5);
}

PB5 is the actual name of Arduino's pin 13. Everytime Timer1 hits OCR1A the function ISR (TIMER1_COMPA_vect) { } will be executed. In this case it's togglin pin 13 every second. Notice it's CTC-Mode which means the timer will be cleared every time the interrupt happens (it only counts up to the value in OCR1A and not the the full 16 bit which would be 65536).^

Greetings

Alex

Ah yes! Been there, done that.

The default control register values mentioned in the AVR datasheets are not necessarily valid when using the arduino security blanket.

It's better to explicitly set/clear all the bits that you need.