/* Programme de chenillard illustrant l'utilisation d'un timer comme base de temps. Les LEDs sont connectées entre les pins du port D et la masse (=> allumées lorque l'I/O est à 1) Le principe est de faire "tourner" le timer 0, et de récupérer l'interruption à chaque passage de 255 à 0. Etant donné qu'on veut obtenir une cadence de défilement visible (envrion 2/10e de seconde, il faut cumuler plusieurs divisions du temps. 1/ on va appliquer un prescale de 1024 à l'horloge processeur. Etant donnée qu'elle est à 8 MHz, la période de base est de 125ns. Le precale va donc établir la période de l'incrément du compteur à 125nS * 1024, soit 128us. Un tour complet de compteur va donc durer 128us * 256, soit 33ms environ. C'est la période avec laquelle l'interruption sera déclenchée 2/ on va changer l'état des sorties toutes les n interruptions, de manière à avoir une cadence de défilement visible Cible : ATMega8 Quartz : 8MHz Compilateur : avr-gcc (WInAVR) */ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> // compteur du nombre d'interruptions timer volatile int tmr_cnt = 0 ; // vu le prescaling et l'étendue du compteur, un intervalle de 100ms correspond à 3 interruptions #define _100_MS 3 // la liste des patterns d'allumage des LEDs unsigned char patterns[] = { 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000, 0b00100000, 0b00001000, 0b00000010, 0b00000001, 0b00000100, 0b00010000, 0b01000000, 0b00000000, 0b10000000, 0b11000000, 0b11100000, 0b11110000, 0b11111000, 0b11111100, 0b11111110, 0b11111111, 0b01111111, 0b00111111, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001, 0b00000000, 0b10101010, 0b10101010, 0b01010101, 0b01010101, 0b10101010, 0b10101010, 0b01010101, 0b01010101, 0b10101010, 0b10101010, 0b01010101, 0b01010101, 0b11111111, 0b00000000, 0b11111111, 0b00000000, 0b11111111, 0b00000000 } ; // index du pattern courant unsigned char pattern = 0 ; /* Interrupt handler pour l'overflow du timer 0 */ SIGNAL (SIG_OVERFLOW0) { // mise à jour du compteur d'interruptions tmr_cnt++ ; // si on est arrivé au nombre nécessaire à l'obtention d'un délai de 0.2s, // il est temps de changer de motif if (tmr_cnt == 2 *_100_MS) { // remise à 0 du compteur d'interruptions tmr_cnt = 0 ; // on modifie l'état des sorties avec le pattern courant PORTD = patterns[pattern] ; // avance de l'index du pattern, avec rebouclage si en fin de séquence pattern = (pattern + 1) % sizeof(patterns) ; } } /* Initialisation des ports */ void port_init(void) { // configuration du port D // - toutes les I/O en sortie DDRD = 0xFF ; // - toutes les LEDs éteintes PORTD = 0x00 ; } /* Initialisation des périphériques */ void init_devices(void) { cli(); // inhibition des interruptions (pour avoir la paix) port_init(); // initialisation de prts // MCU Control Register // - interruptions externes sur niveau bas de la ligne // - sleep mode désactivé MCUCR = 0x00; // General Interrupt Control // - INT0 et INT1 inactives GICR = 0x00; // Timer/Counter Interrupt Mask // - activation de l'interrupt d'overflow du timer 0 TIMSK = 0x01; // Timer/Counter 0 Control Register // - pre-scaling réglé sur 1024 TCCR0 = 0x05; sei(); // autorisation des interruptions } //- -------------------------------------------------------------------------------- int main(void) { init_devices(); // rien à ajouter : tout est fait dans l'interrupt handler }