🛠 Programmer en registres AVR : timer 16 bits et interruption
Objetivos
Salir del marco de Arduino: programar el ATmega2560 en C AVR puro (avr-libc) para configurar el temporizador de 16 bits Timer1 en modo CTC (clear timer on compare), habilitar la interrupción TIMER1_COMPA y alternar el LED del pin 13 (PB7) a una frecuencia exacta de 1 Hz. Comprenderá TCNT1 (contador de 16 bits, de 0 a 65535, frente a los temporizadores de 8 bits Timer0/Timer2), el prescaler, OCR1A y el vector de interrupción.
Material
- 1 × Arduino Mega 2560 + cable USB
- Cadena de herramientas avr-gcc / avr-binutils / avrdude (proporcionada con el IDE de Arduino o la cadena de herramientas AVR de Microchip)
El bootloader original (imagen stk500boot_v2, protocolo serie a 115200 baudios) acepta un binario cargado con el protocolo « wiring ». Nota documentada: el bootloader actual rechaza el borrado completo del chip mediante avrdude (problema « stk500v2_command: command failed »), de ahí la opción -D que se muestra a continuación.
Código completo
/* 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
*/
Verificación esperada
El LED integrado alterna exactamente una vez por segundo (período completo de 2 s), sin delay ni millis: la frecuencia proviene del cristal de 16 MHz dividido por 1024 y luego por 15625. Al leer TCNT1 con un depurador o al cambiar OCR1A, la frecuencia se ajusta inmediatamente.
Errores frecuentes
- Olvidar
sei: la interrupción está habilitada en TIMSK1, pero la bandera global permanece enmascarada, por lo que no ocurre nada. - OCR1A = 15625 en lugar de 15624: en modo CTC, el contador se borra al alcanzar OCR1A, por lo que el período es OCR1A+1.
- Escribir en TCNT1 sin deshabilitar las interrupciones: las modificaciones de 16 bits se realizan en dos bytes, lo que genera valores intermedios aberrantes.
- Eliminar -D con el bootloader de fábrica: el borrado completo del chip (chip-erase) falla (problema documentado desde 2013) y la memoria flash se corrompe.
Otros tutoriales para esta placa
Ejemplos de código para esta placa
clignotante.inoArduinobouton-led.inoArduinodouble-servo.inoArduinopont-uart.inoArduinopwm-respiration.inoArduinopotentiometre-plotter.inoArduino