4

I'm taking my first wobbly steps outside the Arduino IDE and I'm not having much success with timers / interrupts. I can set a pin to output and light an LED with registers fine but I cannot for the life of me get it to blink using a timer. I have tried numerous tutorials and followed the Atmel ATmega328 datasheet very closely.

Using an Arduino Uno R3 & Atmel ICE (ISP.) My dev system is Raspbian (Debian) with the GNU AVR toolchain (avr-gcc, avr-objcopy, avrdude.) Apart from not having a bootloader it's a bog standard board (including fuses.)

Here's my current code:

#include <avr/io.h>
#include <avr/interrupt.h>

ISR(TIMER0_COMPA_vect)
{
    PORTB ^= (1 << PB5); // Toggle Arduino Pin #13
}

int main (void)
{
    DDRB = (1 << DDB5); // Arduino Pin #13 is Output

    cli(); // Clear Interrupts

    OCR0A = (unsigned char)0xFF; // Compare Register A = 255
    TIMSK0 = (1 << OCIE0A); // Enable Interrupt for Comp. Reg. A
    TCCR0A = (1 << WGM01); // CTC Mode

    sei(); // Set Interrupts
    TCCR0B = (1 << CS02) | (1 << CS00); // Divide by 1024 Prescaler (GO!)

    return 0;
}

I don't know if I'm just not seeing something or if I've set registers in the wrong order but it's driving me crazy.

  • 1
    doesn't return 0 reset the device? Try while(1); to make it wait indefinitely. – Gerben Dec 2 '15 at 16:42
  • I am going to scream. Thank you! (Do you do the Answer Question thing or do I?) – Ashlyn Black Dec 2 '15 at 17:02
  • The commenter should convert it into an answer. – dlu Dec 2 '15 at 18:03
3

return 0 resets the device. Use while(1); instead, to make it wait indefinitely.

  • 1
    Just to clarify, doing a return from main does not reset the device, as I showed in my answer. I mention this in case people read this answer and think that returning from main is an easy way of achieving a device reset. – Nick Gammon Dec 13 '15 at 3:51
2

Returning from main does not reset the device (it would start up again and do it all over in that case). It calls exit which turns interrupts off and loops indefinitely.

00000068 <__ctors_end>:
  68:   11 24           eor r1, r1
  6a:   1f be           out 0x3f, r1    ; 63
  6c:   cf ef           ldi r28, 0xFF   ; 255
  6e:   d8 e0           ldi r29, 0x08   ; 8
  70:   de bf           out 0x3e, r29   ; 62
  72:   cd bf           out 0x3d, r28   ; 61
  74:   0e 94 52 00     call    0xa4    ; 0xa4 <main>
  78:   0c 94 61 00     jmp 0xc2    ; 0xc2 <_exit>

...

000000a4 <main>:
  a4:   80 e2           ldi r24, 0x20   ; 32
  a6:   84 b9           out 0x04, r24   ; 4
  a8:   f8 94           cli
  aa:   8f ef           ldi r24, 0xFF   ; 255
  ac:   87 bd           out 0x27, r24   ; 39
  ae:   82 e0           ldi r24, 0x02   ; 2
  b0:   80 93 6e 00     sts 0x006E, r24
  b4:   84 bd           out 0x24, r24   ; 36
  b6:   78 94           sei
  b8:   85 e0           ldi r24, 0x05   ; 5
  ba:   85 bd           out 0x25, r24   ; 37
  bc:   80 e0           ldi r24, 0x00   ; 0
  be:   90 e0           ldi r25, 0x00   ; 0
  c0:   08 95           ret

000000c2 <_exit>:
  c2:   f8 94           cli

000000c4 <__stop_program>:
  c4:   ff cf           rjmp    .-2         ; 0xc4 <__stop_program>

You can see at address 0x74 it calls main, and then jumps to exit. exit turns off interrupts.

With interrupts off your ISR will not toggle pin 13.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.