🛠 Programmer en registres AVR : timer 16 bits et interruption
Objectifs
Sortir du cadre Arduino : programmer l'ATmega2560 en C AVR nu (avr-libc) pour configurer le timer 16 bits Timer1 en mode CTC (clear timer on compare), armer l'interruption TIMER1_COMPA et basculer la LED de la broche 13 (PB7) à 1 Hz exacte. Vous comprendrez TCNT1 (compteur 16 bits, 0 à 65535, contre les timers 8 bits Timer0/Timer2), le prédiviseur, OCR1A et le vecteur d'interruption.
Matériel
- 1 × Arduino Mega 2560 + câble USB
- Chaîne d'outils avr-gcc / avr-binutils / avrdude (fournie avec l'IDE Arduino ou le toolchain AVR de Microchip)
Le bootloader d'origine (image stk500boot_v2, protocole série à 115200 bauds) accepte un binaire chargé avec le protocole « wiring ». Note documentée : le bootloader actuel refuse l'effacement complét de la puce par avrdude (problem « stk500v2_command: command failed »), d'où l'option -D ci-dessous.
Code complet
/* 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
*/
Vérification attendue
La LED intégrée bascule exactement une fois par seconde (période complète de 2 s), sans delay ni millis : la cadence vient du quartz 16 MHz divisé par 1024 puis par 15625. En lisant TCNT1 avec un débogueur ou en changeant OCR1A, la fréquence suit immédiatement.
Erreurs fréquentes
- Oublier
sei: l'interruption est armée dans TIMSK1 mais le drapeau global reste masqué, rien ne se passe. - OCR1A = 15625 au lieu de 15624 : en CTC le compteur s'efface en atteignant OCR1A, la période vaut OCR1A+1.
- Écrire dans TCNT1 sans couper les interruptions : les modifications 16 bits se font en deux octets, d'où des valeurs intermédiaires aberrantes.
- Retirer -D avec le bootloader stock : l'effacement chip-erase échoue (problème documenté depuis 2013) et le flash est corrompu.
Autres tutoriels pour cette carte
Exemples de code pour cette carte
clignotante.inoArduinobouton-led.inoArduinodouble-servo.inoArduinopont-uart.inoArduinopwm-respiration.inoArduinopotentiometre-plotter.inoArduino