====== Temporisation matérielle ====== //Necessary knowledge: [HW] [[en:hardware:homelab:controller]], [AVR] [[en:avr:timers]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [LIB] [[en:software:homelab:library:timer]], [PRT] [[en:examples:timer:software_delay]]// //Connaissances nécessaires: [HW] [[fr:hardware:homelab:controller]], [AVR] [[fr:avr:timers]], [LIB] [[fr:software:homelab:library:pin]], [LIB] [[fr:software:homelab:library:delay]], [LIB] [[fr:software:homelab:library:timer]], [PRT] [[fr:examples:timer:software_delay]]// ===== Théorie ===== La temporisation matérielle n'est pas la seule façon de réaliser des pauses. La même chose peut tout à fait être réalisée par un //timer//. Le //timer// est un matériel (??) qui compte dans un sens ou dans l'autre à une certaine fréquence. La fréquence d'horloge d'un //timer// peut être générée par la fréquence du micro-contrôleur ou par n'importe quel autre rythme externe. En général, on divise la fréquence de l'horloge par un multiplicateur afin d'obtenir une fréquence plus faible - cette fonction est réalisée par le diviseur (//prescaler//). Le plus important est que la valeur de la fréquence d'horloge du //timer// soit linéaire dans le temps. Le temps peut être calculé en multipliant la période de la fréquence de l'horloge du //timer// avec la valeur du //timer//. [{{ :examples:timer:timer_counter.png?300|Les évenements qui correspondent au changement du //timer// AVR.}}] Les compteurs AVR peuvent être utilisés pour informer d'un franchissement de limite ou pour atteindre une valeur de comparaison. Le franchissement de la limite est atteint lorsque la valeur du compteur arrive à sa valeur maximale, dans ce cas le cycle redémarre à 0. Pendant l'incrémentation du compteur, chacune des valeurs du compteur sont comparées à la valeur objectif pré-configurée par l'utilisateur. Lorsque ces conditions sont remplies, le bit des indexes de statut correspondants sont automatiquement configurés en position haute. Pour réaliser une temporisation en utilisant un //timer//, il suffit d'initialiser le //timer// et d'attendre que le bit de statut passe en position haute. Cela est différent dans le cas de la temporisation logiciel, le travail du //timer// ne dépend pas du compilateur, ce qui le rend plus fiable. At the same time the diversity (or complexity) of the set-up of the AVR counter can be considered fairly troublesome. Depending on the microcontroller’s timing signal, may happen that it will not divide exactly with the desired delay period and the delay will not be accurate. ===== Pratique ===== Le code du programme ci-dessous est une fonction de temporisation basée sur un //timer// simplifié. Le principe de comptage est le même que celui d'une fonction de temporisation logicielle – on fabrique une temporisation de longueur 1ms. La temporisation est réalisée avec un compteur 0 de ATmega 128 avec 8-bits. Il à été calculé précédemment que la fréquence de l'horloge est de 14,7456 Mhz le signal de temps doit être divisé 64 fois, donc le compteur ne pourra pas dépasser la limite de 1ms. La valeur que doit prendre le compteur est présenté sous la forme d'une expression dont la variable est ''timer_start''. ''F_CPU'' qui est une constante en langage macro, renvoi la fréquence de l'horloge en Hz. La fréquence de l'horloge doit être 25,6 pour le moment mais depuis qu'on ne peut plus utiliser les valeurs décimales, la valeur initiale sera 26. Malheureusement il survient une erreur dans le temps de la temporisation, qui peut être cependant négligeable (-1,7 μs). Dans le cycle on retrouve l'initialisation du compteur et la mise à zéro de la limite (en inscrivant 1). Puis il attend que le compteur atteigne la valeur 256 en partant de la valeur initiale, i.e. par rapport à la limite. A ce moment la balise prend une valeur haute et 1 ms est passée. A la fin de la fonction le //timer// est arrêté. // // Hardware delay in milliseconds. // void hw_delay_ms(unsigned short count) { // Calculating the initial value of the timer. register unsigned char timer_start = 256 - F_CPU / 1000 / 64; // Starting the timer. timer0_init_normal(TIMER0_PRESCALE_64); // Counting the variable of the delay to the 0. while (count-- > 0) { // Initializing the timer. timer0_set_value(timer_start); // Zeroing the overflow flag. timer0_overflow_flag_clear(); // Waiting for overflow. while (!timer0_overflow_flag_is_set()) { asm volatile ("nop"); } } // Zeroing the overflow flag. timer0_overflow_flag_clear(); // Stoping the timer. timer0_stop(); } Le programme suivant est un exemple similaire de temporisation logicielle. Dans la demi-période la plus petite de 100ms la LED s'allume et dans la plus grande de 900ms elle s'éteint. Ainsi la LED clignote toutes les secondes. Malheureusement, dans cet exemple la période n'est pas précisément d'une seconde, parce que l'exécution des fonction du programme prend aussi du temps. Pour un timing tout à fait exact on doit utiliser un //timer// 16-bits avec interruptions. // // Demonstration program of harware delay of the Homelab. // The Program blinks LED for a moment after every ~1 second. // #include #include // // Determining the pin of the Test LED. // pin debug_led = PIN(B, 7); // // Main program. // int main(void) { // Setting the pin of the LED as output. pin_setup_output(debug_led); // Endless loop. while (true) { // Lighting the LED. pin_clear(debug_led); // Hardware delay for 100 milliseconds. hw_delay_ms(100); // Switch off of the LED. pin_set(debug_led); // Hardware delay for 900 milliseconds. hw_delay_ms(900); } }