🛠 Programmer en registres AVR : timer 16 bits et interruption
Objectives
Step outside the Arduino framework: program the ATmega2560 in bare-metal C (avr-libc) to configure the 16-bit Timer1 in CTC mode (Clear Timer on Compare), enable the TIMER1_COMPA interrupt, and toggle the LED on pin 13 (PB7) at exactly 1 Hz. You will understand TCNT1 (16-bit counter, 0 to 65535, unlike the 8-bit Timer0/Timer2), the prescaler, OCR1A, and the interrupt vector.
Hardware
- 1 × Arduino Mega 2560 + USB cable
- avr-gcc / avr-binutils / avrdude toolchain (provided with the Arduino IDE or Microchip's AVR toolchain)
The original bootloader (stk500boot_v2 image, serial protocol at 115200 bauds) accepts a binary loaded via the "wiring" protocol. Documented note: the current bootloader refuses a complete chip erase via avrdude (problem "stk500v2_command: command failed"), hence the -D option below.
Complete code
/* Blink 1 Hz par Timer1 en CTC — ATmega2560 nu, sans core Arduino */
#define F_CPU 16000000UL /* quartz de la carte : 16 MHz */
#include <avr/io.h>
#include <avr/interrupt.h>
/* 16 000 000 / 1024 = 15 625 Hz ; OCR1A = 15 624 -> bascule à 1 Hz */
ISR(TIMER1_COMPA_vect) {
PORTB ^= (1 << PORTB7); /* toggle PB7 = broche Arduino 13 */
}
int main(void) {
DDRB |= (1 << DDB7); /* PB7 en sortie */
TCCR1A = 0; /* mode normal sur la partie A */
TCCR1B = (1 << WGM12) /* CTC : efface TCNT1 à OCR1A */
| (1 << CS12) | (1 << CS10); /* prédiviseur 1024 */
OCR1A = 15624; /* valeur de comparaison 16 bits */
TIMSK1 |= (1 << OCIE1A); /* autorise TIMER1_COMPA */
sei; /* active les interruptions */
for (;;) { /* le CPU dort utilement ici */ }
}
/* Compilation et flash :
avr-gcc -mmcu=atmega2560 -Os -o timer1.elf timer1.c
avr-objcopy -O ihex -R .eeprom timer1.elf timer1.hex
avrdude -p atmega2560 -c wiring -P COMx -b 115200 -D \
-U flash:w:timer1.hex
*/
Expected verification
The integrated LED toggles exactly once per second (full period of 2 s), without delay or millis: the rate comes from the 16 MHz crystal divided by 1024 then by 15625. By reading TCNT1 with a debugger or changing OCR1A, the frequency adjusts immediately.
Common errors
- Forgetting
sei: the interrupt is enabled in TIMSK1 but the global flag remains masked, so nothing happens. - OCR1A = 15625 instead of 15624: in CTC mode, the counter resets upon reaching OCR1A, so the period is OCR1A+1.
- Writing to TCNT1 without disabling interrupts: 16-bit modifications are done in two bytes, leading to aberrant intermediate values.
- Removing -D with the stock bootloader: the chip-erase fails (documented issue since 2013) and the flash is corrupted.
Other tutorials for this board
Code examples for this board
clignotante.inoArduinobouton-led.inoArduinodouble-servo.inoArduinopont-uart.inoArduinopwm-respiration.inoArduinopotentiometre-plotter.inoArduino