/* Tutoriaux AvrX Utilisation de sémaphores pour synchroniser 2 tâches. Une tâche est utilisée pour faire clignoter une LED, l'autre pour scruter une entrée. La LED change d'état à chaque appui sur le poussoir connecté entre PA0 et la masse Cible : ATMega163 Quartz : 8MHz Compilateur : avr-gcc (WInAVR) */ #include <avr/io.h> #include <avr/interrupt.h> #include "avrx.h" #include "hardware.h" // définition des timers utiliser AVRX_TIMER (timer) ; // lecture de l'entrée /* Timer 0 Overflow Interrupt Handler Structure typique : . Switch en contexte kernel . gestion de l'interruption . retour au context initial */ AVRX_SIGINT(SIG_OVERFLOW0) { // here, you can insert specific handling stuff not related to AvrX IntProlog(); // Switch to kernel stack/context EndCritical(); // autorise à nouveau les interruptions TCNT0 = TCNT0_INIT; // reset timer counter to its start point AvrXTimerHandler(); // Call Time queue manager Epilog(); // back to initial context } // le sémaphore de communication entre les tâches AVRX_MUTEX(sem) ; /* * Définition des tâches * * Elles sont au nombre de 2 : * tâche 1 : gestion de la LED * tâche 2 : gestion de l'entrée */ /* * Cette tâche attend que le sémaphore soit levé pour basculer * l'état de la LED */ AVRX_GCC_TASKDEF(task1, 8, 3) { while (1) { // reset du sémaphore et attente AvrXWaitSemaphore(&sem) ; // le sémaphore a été levé => bascule l'état de la LED LED = LED ^ 0x01; } } /* * Cette tâche scrute l'entrée toute les 100ms et lève le sémaphore * si elle détecte un front descendant (correspondant à l'appui du poussoir) * Pour vérifier l'appui du poussoir, on allume une deuxième LED comme témoin */ AVRX_GCC_TASKDEF(task2, 8, 2) { char is_pressed, was_pressed ; was_pressed = 0 ; // initialisation de la mémoire d'état while (1) { is_pressed = (SWITCH & 0x01) == 0 ; // lecture de l'état du poussoir if (is_pressed) { // si pressé if (!was_pressed) { // et que ce n'était pas déjà le cas LED &= ~_BV(1) ; // on allume la LED témoin, was_pressed = 1 ; // on mémorise l'état AvrXSetSemaphore(&sem) ; // et on lève le sémaphore } } else { // le bouton n'est pas pressé if (was_pressed) { // et que ce n'était pas déjà le cas was_pressed = 0 ; // on remet tout à 0 LED |= _BV(1) ; } } AvrXDelay(&timer, 100); // pause de 100mx avant scrutation suivante } } //-------------------------------------------------------------------------------------------- int main(void) // Main démarre dans le contexte du kernel AvrX { AvrXSetKernelStack(0); // définition du stack du kernel MCUCR = 1<<SE; // autorise l'instruction SLEEP TCNT0 = TCNT0_INIT; // initialise le timer 0 (utilisé pour la gestion des timers TCCR0 = TMC8_CK256; // définit son prescaler à CLK/256 TIMSK = 1<<TOIE0; // active l'interruption Timer0 Overflow LEDDDR = 0xFF; // configure en sortie le port des LEDs LED = 0xFF; // initialise toutes les sortie à 1 // => éteint les LEDs si celles-ci sont reliées à Vcc SWITCHDDR = 0x00 ; // le port des switch est configuré en entrée SWITCHPUP = 0xFF ; // les pullups sont activées => appui sur le poussoir = entrée à 0 AvrXRunTask(TCB(task1)); // active les 2 tâches AvrXRunTask(TCB(task2)); Epilog(); // bascule sur le contexte de la première tâche // => active l'ensemble while(1); // il n'y a plus rien à faire ici }