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.
2 Answers 2
return 0
resets the device. Use while(1);
instead, to make it wait indefinitely.
-
1Just 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 frommain
is an easy way of achieving a device reset.2015年12月13日 03:51:35 +00:00Commented Dec 13, 2015 at 3:51
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.
return 0
reset the device? Trywhile(1);
to make it wait indefinitely.