Arduino Timer Interrupts

Les interruptions de minuterie vous permettent d'effectuer une tâche à des intervalles très précis, indépendamment de ce qui se passe dans votre code. Dans cet instructable, je vais expliquer comment configurer et exécuter une interruption dans Clear Timer sur Compare Match ou en mode CTC. Passez directement à l'étape 2 si vous recherchez un exemple de code.

Normalement, lorsque vous écrivez un croquis Arduino, l'Arduino exécute toutes les commandes encapsulées dans la fonction loop () {} dans l'ordre où elles sont écrites, cependant, il est difficile de chronométrer les événements dans la boucle (). Certaines commandes prennent plus de temps que d'autres à exécuter, certaines dépendent des instructions conditionnelles (if, while ...) et certaines fonctions de la bibliothèque Arduino (comme digitalWrite ou analogRead) sont composées de nombreuses commandes. Les interruptions de la minuterie Arduino vous permettent de suspendre momentanément la séquence normale d'événements se déroulant dans la fonction loop () à des intervalles précisément synchronisés, pendant que vous exécutez un ensemble distinct de commandes. Une fois ces commandes terminées, l'Arduino reprend là où il était dans la boucle ().

Les interruptions sont utiles pour:

Mesure d'un signal entrant à des intervalles également espacés (fréquence d'échantillonnage constante)

Calcul du temps entre deux événements

Envoi d'un signal d'une fréquence spécifique

Vérification périodique des données série entrantes

beaucoup plus...

Il y a plusieurs façons de faire des interruptions, pour l'instant je vais me concentrer sur le type que je trouve le plus utile / flexible, appelé Clear Timer on Compare Match ou CTC Mode. De plus, dans cet instructable, j'écrirai spécifiquement sur les temporisateurs pour l'Arduino Uno (et tout autre Arduino avec ATMEL 328/168 ... Lilypad, Duemilanove, Diecimila, Nano ...). Les principales idées présentées ici s'appliquent également aux cartes Mega et anciennes, mais la configuration est un peu différente et le tableau ci-dessous est spécifique à l'ATMEL 328/168.

Étape 1: Prescalers et registre de comparaison de correspondance

L'Uno a trois temporisateurs appelés timer0, timer1 et timer2. Chacun des temporisateurs a un compteur qui est incrémenté à chaque tick de l'horloge du temporisateur. Les interruptions de temporisation CTC sont déclenchées lorsque le compteur atteint une valeur spécifiée, stockée dans le registre de correspondance de comparaison. Une fois qu'un compteur de minuterie atteint cette valeur, il s'effacera (remis à zéro) au prochain tick de l'horloge de la minuterie, puis il continuera à compter jusqu'à la valeur de correspondance de comparaison. En choisissant la valeur de comparaison et en définissant la vitesse à laquelle le temporisateur incrémente le compteur, vous pouvez contrôler la fréquence des interruptions du temporisateur.

Le premier paramètre dont je parlerai est la vitesse à laquelle le temporisateur incrémente le compteur. L'horloge Arduino fonctionne à 16 MHz, c'est la vitesse la plus rapide avec laquelle les minuteurs peuvent incrémenter leurs compteurs. À 16 MHz, chaque tick du compteur représente 1/16 000 000 de seconde (~ 63 ns), donc un compteur prendra 10/16 000 000 secondes pour atteindre une valeur de 9 (les compteurs sont 0 indexés) et 100/16 000 000 secondes pour atteindre une valeur de 99.

Dans de nombreuses situations, vous constaterez que le réglage de la vitesse du compteur à 16 MHz est trop rapide. Timer0 et timer2 sont des temporisateurs à 8 bits, ce qui signifie qu'ils peuvent stocker une valeur maximale de compteur de 255. Timer1 est une temporisation à 16 bits, ce qui signifie qu'il peut stocker une valeur maximale de compteur de 65535. Une fois qu'un compteur atteint son maximum, il revient à zéro. (cela s'appelle débordement). Cela signifie qu'à 16 MHz, même si nous fixons le registre de correspondance de comparaison à la valeur maximale du compteur, des interruptions se produisent toutes les 256/16 000 000 secondes (~ 16 us) pour les compteurs 8 bits et toutes les 65 536/16 000 000 (~ 4 ms) secondes pour le Compteur 16 bits. De toute évidence, ce n'est pas très utile si vous ne souhaitez interrompre qu'une fois par seconde.

Au lieu de cela, vous pouvez contrôler la vitesse d'incrémentation du compteur de temporisation en utilisant ce que l'on appelle un pré-échelle. Un prescaler dicte la vitesse de votre chronomètre selon l'équation suivante:

(vitesse du minuteur (Hz)) = (vitesse d'horloge Arduino (16 MHz)) / pré-échelle

Ainsi, un pré-détartreur incrémentera le compteur à 16 MHz, un pré-détartreur 8 l'incrémentera à 2 MHz, un pré-détareur 64 = 250 kHz, etc. Comme indiqué dans les tableaux ci-dessus, le prédimensionneur peut être égal à 1, 8, 64, 256 et 1024. (J'expliquerai la signification de CS12, CS11 et CS10 à l'étape suivante.)

Vous pouvez maintenant calculer la fréquence d'interruption avec l'équation suivante:

fréquence d'interruption (Hz) = (vitesse d'horloge Arduino 16 000 000 Hz) / (pré-échelle * (comparer le registre de correspondance + 1))
le +1 est là parce que le registre de comparaison est indexé zéro

en réarrangeant l'équation ci-dessus, vous pouvez résoudre la valeur du registre de correspondance de comparaison qui donnera la fréquence d'interruption souhaitée:

comparer le registre de correspondance = [16 000 000 Hz / (pré-échelle * fréquence d'interruption souhaitée)] - 1
rappelez-vous que lorsque vous utilisez les temporisateurs 0 et 2, ce nombre doit être inférieur à 256 et inférieur à 65536 pour timer1

donc si vous vouliez une interruption toutes les secondes (fréquence de 1Hz):
comparer le registre des correspondances = [16 000 000 / (pré-échelle * 1)] -1
avec un prescaler de 1024, vous obtenez:
comparer le registre de correspondance = [16 000 000 / (1024 * 1)] -1
= 15 624
depuis 256 <15 624 <65 536, vous devez utiliser timer1 pour cette interruption.

Étape 2: Structuration des interruptions de minuterie


Le code de configuration du minuteur se fait à l'intérieur de la fonction setup () {} dans un croquis Arduino.

Le code impliqué pour configurer les interruptions de la minuterie est un peu intimidant à regarder, mais ce n'est en fait pas si difficile. Je copie à peu près le même bloc de code principal et change le prescaler et compare le registre de correspondance pour définir la fréquence d'interruption correcte.

La structure principale de la configuration d'interruption ressemble à ceci:
 ////www.instructables.com/id/Arduino-Timer-Interrupts/ void setup () cli (); // arrêter les interruptions // régler timer0 interrompre à 2 kHz TCCR0A = 0; // régler tout le registre TCCR0A sur 0 TCCR0B = 0; // même pour TCCR0B TCNT0 = 0; // initialise la valeur du compteur à 0 // définit le registre de correspondance de comparaison pour des incréments de 2 kHz OCR0A = 124; // = (16 * 10 ^ 6) / (2000 * 64) - 1 (doit être <256) // activer le mode CTC TCCR0A // terminer la configuration 
Remarquez comment la valeur de l'OCR # A (la valeur de correspondance de comparaison) change pour chacune de ces configurations de temporisation. Comme expliqué dans la dernière étape, cela a été calculé selon l'équation suivante:

comparer le registre de correspondance = [16 000 000 Hz / (pré-échelle * fréquence d'interruption souhaitée)] - 1
rappelez-vous que lorsque vous utilisez les temporisateurs 0 et 2, ce nombre doit être inférieur à 256 et inférieur à 65536 pour timer1

Notez également comment les configurations entre les trois minuteries diffèrent légèrement dans la ligne qui active le mode CTC:
TCCR0A | = (1 << WGM01); // pour timer0
TCCR1B | = (1 << WGM12); // pour timer1
TCCR2A | = (1 << WGM21); // pour timer2
Cela découle directement de la fiche technique de l'ATMEL 328/168.

Enfin, notez comment la configuration des pré-détartreurs suit les tableaux de la dernière étape (le tableau du temporisateur 0 est répété ci-dessus),
TCCR2B | = (1 << CS22); // Définit le bit CS # 2 pour 64 pré-échelle pour le temporisateur 2
TCCR1B | = (1 << CS11); // Définit le bit CS # 1 pour 8 pré-échelle pour le temporisateur 1
TCCR0B | = (1 << CS02) | (1 << CS00); // Définit les bits CS # 2 et CS # 0 pour 1024 pré-échelle pour le temporisateur 0

Remarquez à la dernière étape qu'il existe différentes options de mise à l'échelle pour les différents temporisateurs. Par exemple, timer2 n'a pas l'option de 1024 prescaler.

Les commandes que vous souhaitez exécuter pendant ces interruptions de temporisation se trouvent dans l'esquisse Arduino encapsulée comme suit:
ISR (TIMER0_COMPA_vect) {// changer le 0 en 1 pour timer1 et 2 pour timer2
// interrompre les commandes ici
}
Ce morceau de code doit être situé en dehors des fonctions setup () et loop (). Essayez également de garder la routine d'interruption aussi courte que possible, surtout si vous interrompez à une fréquence élevée. Il peut même être utile d'adresser les ports / broches de la puce ATMEL directement au lieu d'utiliser les fonctions digitalWrite () et digitalRead (). Vous pouvez trouver plus d'informations à ce sujet ici.

Exemple - l'esquisse suivante configure et exécute 3 interruptions de temporisation:

 // interruptions de la minuterie // par Amanda Ghassaei // juin 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * Ce programme est un logiciel libre; vous pouvez le redistribuer et / ou le modifier * selon les termes de la Licence Publique Générale GNU telle que publiée par * la Free Software Foundation; soit la version 3 de la licence, soit * (à votre choix) toute version ultérieure. * * / // configuration de la minuterie pour timer0, timer1 et timer2. // Pour arduino uno ou n'importe quelle carte avec ATMEL 328/168 .. diecimila, duemilanove, lilypad, nano, mini ... // ce code activera les trois interruptions de minuterie arduino. // timer0 va interrompre à 2kHz // timer1 va interrompre à 1Hz // timer2 va interrompre à 8kHz // variables de stockage boolean toggle0 = 0; boolean toggle1 = 0; bascule booléenne2 = 0; void setup () // définir les broches comme sorties pinMode (8, OUTPUT); pinMode (9, SORTIE); pinMode (13, SORTIE); cli (); // arrête les interruptions // définit temporisateur0 interruption à 2 kHz TCCR0A = 0; // définit l'ensemble du registre TCCR2A sur 0 TCCR0B = 0; // même pour TCCR2B TCNT0 = 0; // initialise la valeur du compteur à 0 // définit comparer le registre de correspondance pour des incréments de 2 kHz OCR0A = 124; // = (16 * 10 ^ 6) / (2000 * 64) - 1 (doit être <256) // activer le mode CTC TCCR0A // terminer la configuration ISR (TIMER0_COMPA_vect) { // timer0 interruption 2kHz bascule la broche 8 // génère une onde d'impulsion de fréquence 2kHz / 2 = 1kHz (prend deux cycles pour une onde complète bascule haut puis bas bas) if (bascule0) {digitalWrite (8, HIGH); bascule0 = 0; } else {digitalWrite (8, LOW); bascule0 = 1; }} ISR (TIMER1_COMPA_vect) {// timer1 interruption 1Hz bascule la broche 13 (LED) // génère une onde d'impulsion de fréquence 1Hz / 2 = 0, 5kHz (prend deux cycles pour une onde complète bascule haut puis bas bas) si (bascule1) { digitalWrite (13, HIGH); toggle1 = 0; } else {digitalWrite (13, LOW); toggle1 = 1; }} ISR (TIMER2_COMPA_vect) {// timer1 interruption 8kHz bascule la broche 9 // génère une onde d'impulsion de fréquence 8kHz / 2 = 4kHz (prend deux cycles pour une onde complète bascule haut puis bas bas) if (bascule2) {digitalWrite (9, HAUTE); toggle2 = 0; } else {digitalWrite (9, LOW); toggle2 = 1; }} void loop () {// faites d'autres choses ici} 

Les images ci-dessus montrent les sorties de ces interruptions de temporisation. La figure 1 montre une onde carrée oscillant entre 0 et 5 V à 1 kHz (interruption timer0), la figure 2 montre la LED attachée à la broche 13 s'allumant pendant une seconde puis s'éteignant pendant une seconde (interruption timer1), la figure 3 montre une onde d'impulsion oscillant entre 0 et 5V à une fréquence de 4 kHz (interruption timer2).

Étape 3: Exemple 1: compteur de vitesse de vélo

Dans cet exemple, j'ai fabriqué un compteur de vitesse de vélo alimenté par Arduino. Il fonctionne en attachant un aimant à la roue et en mesurant le temps qu'il faut pour passer par un interrupteur magnétique monté sur le cadre - le temps pour une rotation complète de la roue.

J'ai réglé la minuterie 1 pour interrompre toutes les ms (fréquence de 1 kHz) pour mesurer l'interrupteur magnétique. Si l'aimant passe par l'interrupteur, le signal provenant de l'interrupteur est élevé et la variable "temps" est mise à zéro. Si l'aimant n'est pas près de l'interrupteur, le "temps" est incrémenté de 1. De cette façon, le "temps" n'est en fait qu'une mesure de la durée en millisecondes qui s'est écoulée depuis le dernier passage de l'aimant par l'interrupteur magnétique. Cette information est utilisée plus loin dans le code pour calculer le régime et le mph du vélo.

Voici le morceau de code qui configure timer1 pour les interruptions de 1 kHz

cli (); // arrête les interruptions
// régler l'interruption timer1 à 1 kHz
TCCR1A = 0; // définir l'ensemble du registre TCCR1A sur 0
TCCR1B = 0; // idem pour TCCR1B
TCNT1 = 0; // initialise la valeur du compteur à 0
// définir le nombre de temporisations pour les incréments de 1 kHz
OCR1A = 1999; // = (16 * 10 ^ 6) / (1000 * 8) - 1
// a dû utiliser 16 bit timer1 pour ce bc 1999> 255, mais pourrait basculer sur les timers 0 ou 2 avec un plus grand prédéfinisseur
// activer le mode CTC
TCCR1B | = (1 << WGM12);
// Régler le bit CS11 pour 8 prescaler
TCCR1B | = (1 << CS11);
// activer l'interruption de comparaison du minuteur
TIMSK1 | = (1 << OCIE1A);
sei (); // autorise les interruptions

Voici le code complet si vous voulez y jeter un œil:
 // compteur de vitesse vélo // by Amanda Ghassaei 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * This le programme est un logiciel libre; vous pouvez le redistribuer et / ou le modifier * selon les termes de la Licence Publique Générale GNU telle que publiée par * la Free Software Foundation; soit la version 3 de la licence, soit * (à votre choix) toute version ultérieure. * * / // exemples de calculs // rayon de pneu ~ 13, 5 pouces // circonférence = pi * 2 * r = ~ 85 pouces // vitesse maximale de 35 mph = ~ 616 pouces / seconde // max rps = ~ 7, 25 # définir l'anche A0 / / broche connectée au commutateur de lecture // variables de stockage float radius = 13.5; // pneu radius (in inches) - CHANGE THIS FOR YOUR OWN BIKE int reedVal; long time = 0; // temps entre une rotation complète (en ms) float mph = 0, 00; circonférence du flotteur; rétro-éclairage booléen; int maxReedCounter = 100; // temps min (en ms) d'une rotation (pour anti-rebond) int reedCounter; void setup () {reedCounter = maxReedCounter; circonférence = 2 * 3, 14 * rayon; pinMode (1, OUTPUT); // tx pinMode (2, OUTPUT); // commutateur de rétroéclairage pinMode (reed, INPUT); // commutateur redd checkBacklight (); Serial.write (12); // clear // TIMER SETUP - l'interruption de la minuterie permet des mesures chronométrées précises du commutateur Reed // pour plus d'informations sur la configuration des minuteries Arduino, voir //arduino.cc/playground/Code/Timer1 cli ( ); // arrêter les interruptions // définir l'interruption timer1 à 1 kHz TCCR1A = 0; // définir l'ensemble du registre TCCR1A sur 0 TCCR1B = 0; // même pour TCCR1B TCNT1 = 0; // initialiser la valeur du compteur à 0; // définir le nombre de temporisations pour les incréments de 1 kHz OCR1A = 1999; // = (16 * 10 ^ 6) / (1000 * 8) - 1 // activer le mode CTC TCCR1B | = (1 << WGM12); // Définit le bit CS11 pour 8 prescaler TCCR1B | = (1 << CS11); // activer la temporisation comparer l'interruption TIMSK1 | = (1 <0) {// ne pas laisser reedCounter devenir négatif reedCounter - = 1; // décrémenter reedCounter}}} else {// si le commutateur reed est ouvert si (reedCounter> 0 ) {// ne laissez pas reedCounter devenir négatif reedCounter - = 1; // décrémente reedCounter}} si (temps> 2000) {mph = 0; // si aucune nouvelle impulsion du commutateur à lames n'est encore, réglez mph sur 0} else {time + = 1; // increment timer}} void displayMPH () {Serial.write (12); // clear Serial.write ("Speed ​​="); Serial.write (13); // démarre une nouvelle ligne Serial.print (mph); Serial.write ("MPH"); //Serial.write("0.00 MPH "); } void loop () {// affiche mph une fois par seconde displayMPH (); retard (1000); checkBacklight (); } 

Étape 4: Exemple 2: communication série

Ce projet est un pavé de touches rétro-éclairé 4x4. Le projet se connecte à mon ordinateur via USB, il envoie des informations sur les boutons à l'ordinateur et reçoit des informations sur la façon d'allumer les LED. Voici une vidéo:



Pour ce projet, j'ai utilisé des interruptions timer2 pour vérifier périodiquement s'il y avait des données série entrantes, les lire et les stocker dans la matrice "ledData []". Si vous regardez le code, vous verrez que la boucle principale de l'esquisse est ce qui est réellement responsable de l'utilisation des informations dans ledData pour allumer les LED correctes et vérifier l'état des boutons (une fonction appelée "shift ( ) "). La routine d'interruption est aussi courte que possible - il suffit de vérifier les octets entrants et de les stocker de manière appropriée.

Voici la configuration de timer2:

cli (); // arrête les interruptions
// définir une interruption timer2 toutes les 128us
TCCR2A = 0; // définir l'ensemble du registre TCCR2A sur 0
TCCR2B = 0; // idem pour TCCR2B
TCNT2 = 0; // initialise la valeur du compteur à 0
// définir le registre de correspondance de comparaison pour des incréments de 7, 8 kHz
OCR2A = 255; // = (16 * 10 ^ 6) / (7812, 5 * 8) - 1 (doit être <256)
// activer le mode CTC
TCCR2A | = (1 << WGM21);
// Régler le bit CS21 pour 8 prescaler
TCCR2B | = (1 << CS21);
// activer l'interruption de comparaison du minuteur
TIMSK2 | = (1 << OCIE2A);
sei (); // autorise les interruptions

Voici le croquis complet d'Arduino:
 // BUTTON TEST w / 74HC595 et 74HC165 et communication série // par Amanda Ghassaei // juin 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * Ce programme est un logiciel gratuit; vous pouvez le redistribuer et / ou le modifier * selon les termes de la Licence Publique Générale GNU telle que publiée par * la Free Software Foundation; soit la version 2 de la licence, soit * (à votre choix) toute version ultérieure. * * / // ce firmware enverra des données dans les deux sens avec le patch maxmsp "beat slicer" // connexions pin #define ledLatchPin A1 #define ledClockPin A0 #define ledDataPin A2 #define buttonLatchPin 9 #define buttonClockPin 10 #define buttonDataPin A3 / / variables de boucle octet i; octet j; octet k; byte ledByte; // stockage pour les états led, 4 octets byte ledData [] = {0, 0, 0, 0}; // stockage pour les boutons, 4 octets octet buttonCurrent [] = {0, 0, 0, 0}; byte buttonLast [] = {0, 0, 0, 0}; byte buttonEvent [] = {0, 0, 0, 0}; byte buttonState [] = {0, 0, 0, 0}; // compteur de rebond de bouton - 16 octets octet buttonDebounceCounter [4] [4]; void setup () = (1 << WGM21); // Définit le bit CS21 pour 8 prescaler TCCR2B // buttonCheck - vérifie l'état d'un bouton donné. // cette fonction de vérification des boutons est largement copiée à partir du micrologiciel monome 40h par brian crabtree et joe lake void buttonCheck (ligne d'octets, index d'octets) {if ((((buttonCurrent [row] ^ buttonLast [row]) & (1 << index) ) && // si l'état actuel du bouton physique est différent de ((buttonCurrent [row] ^ buttonState [row]) & (1 << index))) {// le dernier état du bouton physique ET l'état actuel du rebond si (buttonCurrent [row] & (1 << index)) // si l'état actuel du bouton physique est enfoncé buttonEvent [row] = 1 << index; // met immédiatement en file d'attente un nouvel événement de bouton buttonState [row] else {buttonDebounceCounter [row] [index] = 12; } // sinon le bouton était précédemment enfoncé et maintenant // a été relâché, nous avons donc réglé notre compteur de rebonds. } else if ((((buttonCurrent [row] ^ buttonLast [row]) & (1 << index)) == 0 && // si l'état actuel du bouton physique est le même que (buttonCurrent [row] ^ buttonState [row] ) & (1 <0 && --buttonDebounceCounter [ligne] [index] == 0) {// si le compteur de rebonds a // été décrémenté à 0 (ce qui signifie que // le bouton a été activé pour // kButtonUpDefaultDebounceCount / / iterations /// buttonEvent [row] = 1 << index; // mettre en file d'attente un événement de changement d'état du bouton if (buttonCurrent [row] & (1 << index)) = (1 << index); else {buttonState [ row] & = ~ (1 << index);}}}} void shift () {for (i = 0; i <4; i ++) {buttonLast [i] = buttonCurrent [i]; byte dataToSend = (1 < > 3; // latchpin low digitalWrite (buttonLatchPin, LOW); for (k = 0; k <4; k ++) {buttonCheck (i, k); if (buttonEvent [i] <  1) & 3; byte ledx = (ledByte >> 3) & 3; if (ledstate) = 8 >> ledx; else {ledData [ledy] & = ~ (8 >> ledx); }} // end si série disponible} // end do while (Serial.available ()> 8); } void loop () {shift (); // met à jour les leds et reçoit les données des boutons} 

téléchargez le patch MaxMSP ci-dessous (il fonctionnera également dans Max Runtime).

Pièces jointes

  • beat slicer.zip Télécharger

Étape 5: Exemple 3: DAC

Dans ce projet, j'ai utilisé une interruption de minuterie pour produire une onde sinusoïdale d'une fréquence spécifique de l'Arduino. J'ai soudé un simple DAC R2R 8 bits aux broches numériques 0-7. Ce DAC a été construit à partir de résistances 10k et 20k disposées dans un diviseur de tension à plusieurs niveaux. Je posterai plus sur la construction du DAC dans un autre instructable, pour l'instant j'ai inclus les photos ci-dessus.
J'ai connecté la sortie du DAC à un oscilloscope. Si vous avez besoin d'aide pour comprendre comment utiliser / lire l'oscilloscope, consultez ce tutoriel. J'ai chargé le code suivant sur l'Arduino:
 // Onde sinusoïdale 63Hz // par Amanda Ghassaei 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * Ce programme est un logiciel libre; vous pouvez le redistribuer et / ou le modifier * selon les termes de la Licence Publique Générale GNU telle que publiée par * la Free Software Foundation; soit la version 3 de la licence, soit * (à votre choix) toute version ultérieure. * * / // envoie une onde sinusoïdale de 63 Hz à l'arduino PORTD DAC float t = 0; void setup () = (1 << CS21); // activer le temporisateur comparer interruption TIMSK2 ISR (TIMER2_COMPA_vect) {// incrément t t + = 1; si (t == 628) {// 40 kHz / 628 = ~ 63 Hz t = 0; }} boucle vide () {// onde sinusoïdale de fréquence ~ 63 Hz // envoie des valeurs sinusoïdales à PORTD entre 0 et 255 PORTD = octet (127 + 127 * sin (t / 100)); } 
J'ai mis en place une interruption temporisée qui incrémente la variable t à une fréquence de 40 kHz. Une fois que t atteint 627, il est remis à zéro (cela se produit avec une fréquence de 40 000/628 = 63 Hz). Pendant ce temps, dans la boucle principale, l'Arduino envoie une valeur entre 0 (00000000 en binaire) et 255 (11111111 en binaire) aux broches numériques 0 à 7 (PORTD). Il calcule cette valeur avec l'équation suivante:

PORTD = octet (127 + 127 * sin (t / 100));

Ainsi, lorsque t augmente de 0 à 627, la fonction sinus se déplace sur un cycle complet. La valeur envoyée à PORTD est une onde sinusoïdale de fréquence 63Hz et d'amplitude 127, oscillant autour de 127. Lorsque celle-ci est envoyée via le DAC à échelle de résistance 8 bits, elle émet un signal oscillant autour de 2, 5V avec une amplitude de 2, 5V et une fréquence de 63Hz.

La fréquence de l'onde sinusoïdale peut être doublée en multipliant le terme (t / 100) par 2, quadruplée en multipliant par 4, etc.
Notez également que si vous augmentez trop la fréquence de l'interruption de la minuterie en diminuant le prescaler ou l'OCR2A, l'onde sinusoïdale ne sortira pas correctement. En effet, la fonction sin () est coûteuse en termes de calcul et, à des fréquences d'interruption élevées, elle n'a pas assez de temps pour s'exécuter. Si vous utilisez des interruptions haute fréquence, au lieu d'effectuer un calcul pendant la routine d'interruption, envisagez de stocker des valeurs dans un tableau et d'appeler simplement ces valeurs à l'aide d'une sorte d'index. Vous pouvez trouver un exemple de cela dans mon générateur de forme d'onde Arduino - en stockant 20 000 valeurs de sin dans un tableau, j'ai pu produire des ondes sinusoïdales avec une fréquence d'échantillonnage de 100 kHz.

Étape 6: Fonctions minuterie et Arduino

Une dernière chose à noter: certaines configurations de minuterie désactiveront en fait certaines des fonctions de la bibliothèque Arduino. Timer0 est utilisé par les fonctions millis () et delay (), si vous configurez manuellement timer0, ces fonctions ne fonctionneront pas correctement.
De plus, les trois temporisateurs remplacent la fonction analogWrite (). La configuration manuelle d'une minuterie arrêtera analogWrite () de fonctionner.

S'il y a une partie de votre code que vous ne voulez pas interrompre, envisagez d'utiliser cli () et sei () pour désactiver et activer globalement les interruptions.

Vous pouvez en savoir plus à ce sujet sur le site Web Arduino.

Articles Connexes