Registres. Ch1

L'un des avantages du microcontrôleur ATmega8 est sa large gamme d'interruptions différentes.

Interrompre est un événement à l'apparition duquel l'exécution du programme principal est suspendue et une fonction est appelée pour gérer une interruption d'un certain type.

Les interruptions sont divisées en internes et externes. Les sources d'interruptions internes incluent les modules de microcontrôleur intégrés (minuteries, émetteur-récepteur USART, etc.). Des interruptions externes se produisent lorsque des signaux externes arrivent sur les broches du microcontrôleur (par exemple, des signaux sur les broches RESET et INT). La nature des signaux conduisant à l'apparition d'une interruption est fixée dans le registre de contrôle MCUCR, notamment dans les bits - ISC00 (bit 0) et ISC01 (bit 1) pour l'entrée INT 0 ; ISC10 (bit2) et ISC11 (bit3) pour l'entrée INT1.

Dans le microcontrôleur ATmega8, chaque interruption a son propre vecteur d'interruption(adresse au début de la zone mémoire du programme dans laquelle est stockée la commande permettant de passer à la routine d'interruption spécifiée). Dans mega8, toutes les interruptions ont la même priorité. Si plusieurs interruptions se produisent simultanément, l'interruption avec le numéro de vecteur le plus bas sera traitée en premier.

Vecteurs d’interruption dans Atmega8

Adresse Source d'interruption Description
0x0000 RÉINITIALISER Signal de réinitialisation
0x0001 INT0 Demande d'interruption externe à l'entrée INT0
0x0002 INT1 Demande d'interruption externe à l'entrée INT1
0x0003 T/C1 Capture temporisée T/C1
0x0004 T/C1 Faire correspondre la minuterie T/C1 Comparer le registre A
0x0005 T/C1 Correspondance avec le registre de comparaison B du temporisateur T/C1
0x0006 T/C1 Débordement du compteur T/C1
0x0007 T/C0 Débordement compteur T/C0
0x0008 IPS Transfert de données SPI terminé
0x0009 UART L'émetteur-récepteur UART a terminé la réception des données.
0x000A UART Le registre de données UART est vide
0x000B UART La transmission des données par l'émetteur-récepteur UART est terminée
0x000C ANA_COMP Interruption du comparateur analogique

Gestion des interruptions

4 registres sont chargés de gérer les interruptions dans ATmega8 :

GIMSK(alias GICR) - interdire/activer les interruptions basées sur les signaux aux entrées INT0, INT1

GIFR- gestion de toutes les interruptions externes

TIMSK, TIFR- gestion des interruptions des timers/compteurs

Registre GIMSK(GICR)

INTFx=1 : une interruption s'est produite à l'entrée INTx. Lors de l'entrée dans la routine de gestion des interruptions, INTFx est automatiquement réinitialisé à l'état de journal. 0

Registre TIMSK

7 6 5 4 3 2 1 0
TOIE1
OCIE1A
OCIE1B
-
TICIÉ
-
TOIE0
-

TOIE1=1: interruption de débordement T/C1 activée

OCIE1A=1: interruption lorsque le registre de comparaison A correspond au contenu du compteur T/C1 activé

OCIE1B=1: interruption lorsque le registre de comparaison B correspond au contenu du compteur T/C1 activé

TICI=1: interruption activée lorsque la condition de capture est remplie

TOIE0=1: interruption de débordement T/C0 activée

Registre TIFR

7 6 5 4 3 2 1 0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-

TOV1=1: Un débordement T/C1 s'est produit

OCF1A=1: le registre de comparaison A coïncidait avec le contenu du compteur T/C1 autorisé

OCF1B=1: le registre de comparaison B correspond au contenu du compteur T/C1 autorisé

ICF=1: conditions de capture remplies

TOV0=1: Un débordement T/C0 s'est produit

Lors de l'entrée dans le sous-programme de gestion des interruptions, l'indicateur du registre TIFR correspondant à l'interruption est automatiquement réinitialisé à l'état de journal. 0

Les interruptions ne fonctionnent que lorsque les interruptions générales sont activées dans le registre d'état SREG (bit 7 = 1). Lorsqu'une interruption se produit, ce bit est automatiquement réinitialisé à 0, désactivant les interruptions suivantes.

Dans cet exemple, la broche INT0 est activée en mode d'entrée pull-up. Lorsque la broche est court-circuitée à la masse à l'aide d'un bouton, la logique 0 est définie dessus (le front du signal passe de la tension d'alimentation à 0) et le gestionnaire d'interruption est déclenché, allumant l'ampoule connectée à la broche zéro du port. B

vider la lampeON()
{
PORTB.0=1;
DDRB.0=1 ;
}

interrompre void ext_int0_isr(void)
{
lampeON();
}

DDRD.2=0 ;
PORTD.2=1;

SREG|= (1 tandis que(1) (

L'exemple ci-dessus montre également comment les vecteurs d'interruption sont définis dans Code Vision AVR (interrupt void ext_int0_isr(void)). Les vecteurs d'interruption sont définis de la même manière pour les autres cas :

EXT_INT0 2
EXT_INT1 3
TIM2_COMP4
TIM2_OVF5
TIM1_CAPT6
TIM1_COMPA7
TIM1_COMPB8
TIM1_OVF9
TIM0_OVF 10
SPI_STC11
USART_RXC12
USART_DRE 13
USART_TXC14
ADC_INT 15
EE_RDY 16
ANA_COMP17
TWI 18
SPM_PRÊT 19

Récemment, de plus en plus de débutants sont confrontés au problème de la maîtrise des minuteries/compteurs (ci-après dénommés T/C) au stade de l'étude des microcontrôleurs. Dans cet article je vais essayer de dissiper les craintes concernant ces modules et expliquer clairement comment et avec quoi ces mêmes T/S sont utilisés.

Nous prendrons comme base un livre très populaire parmi les développeurs d'appareils MK, rédigé par A.V. Evstifeev. En utilisant les liens à la fin de l'article, vous pouvez trouver le projet dans et le projet dans. Dans cet article, nous analyserons le fonctionnement du T/S T2 8 bits, qui fait partie de l'Atmega8 T/S MK.

Alors, qu’est-ce qu’un minuteur/compteur ? T/S est l'un des modules de l'AVR MK avec lequel vous pouvez mesurer certaines périodes de temps, organiser le PWM et bien d'autres tâches. Selon le modèle MK, le nombre de T/S peut être de 4 ou plus. Un exemple de ceci est les Atmega640x, 1280x/1281x, 2560x/2561x MK, qui contiennent 6 T/S à bord : deux 8 bits et quatre 16 bits. L'Atmega8 MK contient trois T/S : T0 et T2 avec 8 bits, T1 avec 16 bits.

Regardons de plus près le microcontrôleur T/C T2 Atmega8.

Ce timer peut fonctionner selon plusieurs modes : Normal, PWM correct de phase, CTC (réinitialisation sur coïncidence), PWM rapide. Vous pouvez en savoir plus sur chaque mode dans le livre.

Ce T/C se compose d'un registre de contrôle, d'un registre de comptage, d'un registre de comparaison et d'un registre d'état en mode asynchrone. Le schéma fonctionnel de T2 est présenté sur la figure 1.

Voyons comment ce module fonctionne en théorie. Pour que ce soit plus clair pour vous, nous ne considérerons pas tous les gadgets inutiles de la minuterie et considérerons son mode le plus courant - NORMAL. Déterminons par nous-mêmes que le MK est cadencé à partir d'un oscillateur RC interne avec une fréquence de 1 MHz et que la minuterie est configurée pour fonctionner en mode NORMAL.

Les impulsions d'horloge arrivent à l'entrée clk i\o et entrent dans le pré-échelonneur de minuterie. Le prescaler peut être configuré, selon vos besoins, pour transmettre directement les impulsions d'horloge ou pour diviser les impulsions entrantes, en n'en transmettant qu'une certaine partie. Les impulsions entrantes peuvent être divisées en /8, /64, /256, /1024. Étant donné que notre T\S peut fonctionner en mode asynchrone, lorsqu'il est allumé dans ce mode, le nombre de prescalers augmente considérablement, mais nous ne les considérerons pas pour l'instant. Depuis le pré-échelonneur, les impulsions d'horloge entrent dans l'unité de contrôle et de celle-ci entrent dans le registre de comptage. Le registre de comptage, à son tour, incrémente pour chaque impulsion entrante. Le registre de comptage T2 est de 8 bits, il ne peut donc compter que jusqu'à 255. Lorsque le registre de comptage déborde, il est remis à 0 et recommence à compter dans le même cycle. De plus, lorsque le registre du compteur déborde, l'indicateur TOV2 (indicateur d'interruption de débordement) du registre TIFR est activé.

Maintenant que nous avons abordé des mots tels que REGISTER, il est temps de les connaître. Pour commencer, nous n'aborderons que les registres avec lesquels nous travaillerons directement, afin de ne pas remplir le cerveau d'informations inutiles.

TCNT2 est un registre de comptage, nous avons déjà parlé de son fonctionnement.

TCCR2 - registre de contrôle de minuterie.

TIMSK - registre de masque d'interruption (dans Atmega8, ce registre est le seul pour tous les temporisateurs).

TIFR - registre des drapeaux d'interruption (dans Atmega8, ce registre est le seul pour tous les timers).

Et maintenant sur chacun en détail :

Registre de contrôle TCCR2. Vous pouvez voir le contenu de ce registre sur la figure 2.


Figure 2

Les bits 0 à 2 sont responsables de la synchronisation de la minuterie. La définition de certaines combinaisons de ces bits configure le préscaler pour une minuterie donnée. Si les trois bits sont effacés, la minuterie est désactivée.

Les bits 3.6 sont responsables du mode de fonctionnement du temporisateur.

Les bits 4.5 sont nécessaires pour configurer le comportement de la sortie OSn (en d'autres termes, ils sont utilisés lors de la configuration du PWM)

Et le dernier bit de ce registre est le bit 7. Avec son aide, nous pouvons changer de force l'état de la broche OSn.

Registre de masque d'interruption - TIMSK. On le voit sur la photo n°3

A partir de ce registre nous ne nous intéressons qu'aux deux derniers bits, les bits 6 et 7. Avec ces bits nous activons les interruptions.

Le bit 6, s'il y est écrit, permet l'interruption due à l'événement "T\C T2 overflow"

Bit 7, si vous y écrivezNitsya, permet l'interruption sur l'événement "Coïncidence du registre de comptage avec le registre de comparaison"

Registre des indicateurs d'interruption TIFR. On le voit sur la photo n°4

Figure 4

Dans ce registre on s'intéresse également aux deux derniers bits : les bits 6 et 7.

Bit 6 - indicateur, activé par l'événement "Débordement T\C T2"
Bit 7 - drapeau, est installé par l'événement "Coïncidence du registre de comptage avec le registre de comparaison"

Ces bits sont réinitialisés automatiquement lorsque le gestionnaire d'interruption se termine, mais pour plus de sécurité, vous pouvez les réinitialiser vous-même en réinitialisant ces bits à "0".

Les bits restants des registres TIMSK et TIFR sont utilisés par T\C T0 et T1. Comme vous l'avez déjà remarqué, les bits de ces registres portent même les mêmes noms, à l'exception du numéro à la fin du nom, qui indique à quel timer ce bit s'applique.

Il reste à considérer deux tableaux simples, à savoir : un tableau qui décrit le contrôle du signal d'horloge (Fig. 6), et un tableau qui décrit comment configurer généralement une minuterie (Fig. 5).

J'ai écrit ci-dessus sur le contenu de ces tableaux, mais je vous les apporte pour plus de clarté.

Nous en avons maintenant terminé avec la théorie et il est temps de commencer la partie pratique. Je vais faire une réservation tout de suite.

LES HORLOGES QUE VOUS OBTENEZ EN ÉTUDIANT CET ARTICLE NE SONT PAS TRÈS PRÉCISES. CET ARTICLE EST ORIENTÉ SUR LES PRINCIPES GÉNÉRAUX DU TRAVAIL AVEC DES MINUTERIES.

Ouvrez Studio 6, créez un projet et sélectionnez Atmega8.

Au tout début, nous indiquons la fréquence d'horloge et connectons les bibliothèques dont nous avons besoin pour travailler

< avr/io.h >#inclure< avr/interrupt.h >

Dans la première ligne, nous indiquons la fréquence. Ceci est nécessaire pour que le compilateur nous comprenne mieux si nous voulons soudainement utiliser les fonctions _delay_().

La deuxième ligne de code comprend une bibliothèque avec une description générale des registres de notre MK. Il attribue également des noms lisibles à tous les registres.

La troisième ligne comprend une bibliothèque pour travailler avec des vecteurs d'interruption.

TIMSK |= (1< < TOIE2); TCCR2 |= (1< < CS22)|(1< < CS20); SREG |= (1< < 7);

Ceci termine la configuration de notre minuterie. Examinons de plus près les trois dernières lignes de code.

Dans la première ligne, nous avons activé les interruptions pour l'événement "Dépassement du timer/compteur T2".

Et dans la troisième ligne, nous avons globalement activé les interruptions. On pourrait aussi écrire ainsi :

Asm("sei");

Il ne reste plus qu'à ajouter le gestionnaire d'interruption et le code de notre horloge temps réel.

ISR (TIMER2_OVF_vect) ( takt++; if (takt>=4)(sek++; takt=0x00;) if (sek>=60) (min++; sek=0x00;) if (min>=60) (heure++; min=0x00 ;) if (heure>=24) (heure=0x00);

Il n'y a rien de compliqué ou de nouveau pour vous dans le code contenu dans le gestionnaire d'interruption. Faisons attention uniquement à la variable takt et au nombre magique "4". D'où vient ce chiffre ? Regardons ce point de plus près.

Nous savons que notre MK fonctionne à partir d'un oscillateur interne d'une fréquence de 1 MHz, le timer est cadencé avec un prescaler de \1024, notre timer peut compter jusqu'à 255. Connaissant ces paramètres, nous pouvons calculer combien de débordements il fera en 1 seconde

1 000 000 \ 1024 \ 256 = 3,814697.....

Eh bien, puisque nous apprenons à travailler avec des minuteries et que nous ne nous sommes pas fixés pour objectif d'obtenir une horloge ultra précise, nous arrondissons notre résultat et obtenons « 4 ». Ceux. en 1 seconde, la minuterie débordera environ 4 fois.

Pourquoi avons-nous divisé par 256 si le minuteur ne compte que jusqu'à 255 ? Parce que "0" est aussi un nombre. Je pense que tout est clair ici.

N'oubliez pas que toutes les variables doivent être déclarées comme globales.

Voici la liste complète du programme que nous avons obtenu.

#définir F_CPU 1000000UL #inclure< avr/io.h >#inclure< avr/interrupt.h >takt de caractère non signé = 0 ; caractère non signé sek = 0 ; caractère non signé min=0 ; heure de caractère non signé = 0 ; ISR (TIMER2_OVF_vect) ( takt++; if (takt>=4)(sek++; takt=0x00;) if (sek>=60) (min++; sek=0x00;) if (min>=60) (heure++; min=0x00 ;) if (heure>=24) (heure=0x00); int main(void) ( TIMSK |= (1< < TOIE2); TCCR2 |= (1< < CS22)|(1< < CS20); SREG |= (1< < 7); while(1) { } }

Mais qu’en est-il de la transmission des informations à l’utilisateur ? Et puis celui qui aime ça. Vous pouvez utiliser des indicateurs à sept segments, des affichages graphiques ou générateurs de caractères, etc.

Dans l'archive, vous trouverez un projet avec des informations d'affichage de Nokia5110, un projet dans Proteus 7 et tous les fichiers et bibliothèques nécessaires au travail.

Veuillez noter que la bibliothèque LCD_5110 permettant de travailler avec l'écran a été écrite par un participant au forum et fournie avec son autorisation.

Nous avons compris le compteur d'itérations de la boucle principale et découvert qu'il est totalement inadapté à des lectures précises du temps - la vitesse d'obturation flotte et il est difficile de la compter. Ce qu'il faut faire?

Évidemment, nous avons besoin d’une sorte de compteur externe qui fonctionnerait quel que soit le fonctionnement du processeur, et le processeur pourrait à tout moment voir ce qui s’y passait. Ou pour que le compteur génère des événements de débordement ou de sous-débordement, levez le drapeau ou générez une interruption. Et le pour cent le sentira et le traitera.

Et il existe un tel compteur, pas même un seul - ce sont des minuteries périphériques. Il peut y en avoir plusieurs dans un AVR, et même avec des profondeurs de bits différentes. ATmega16 en a trois, ATmega128 en a quatre. Et dans les nouveaux MK de la série AVR il y en a peut-être encore plus, je ne l'ai pas reconnu.

De plus, une minuterie peut être plus qu'un simple compteur stupide : une minuterie est l'un des périphériques les plus sophistiqués (en termes de fonctions alternatives).

Que peuvent faire les minuteries ?

  • Tiquez à différentes vitesses, en comptant le temps
  • Compter les impulsions entrantes de l'extérieur (mode compteur)
  • Tick ​​​​du quartz externe à 32768Hz
  • Générer plusieurs types de signaux PWM
  • Émettre des interruptions (une demi-douzaine d'événements différents) et définir des indicateurs

Différentes minuteries ont des fonctionnalités différentes et des profondeurs de bits différentes. Voir la fiche technique pour plus de détails.

Source du tick du minuteur
Le minuteur/compteur (ci-après je l'appellerai T/C) compte soit les impulsions d'horloge du générateur d'horloge intégré, soit de l'entrée de comptage.

Regardez attentivement le brochage des pattes de l'ATmega16, y voyez-vous les pattes T1 et T0 ?

Il s'agit donc des entrées de comptage Timer 0 et Timer 1. Avec les réglages appropriés, le T/S comptera soit le front montant (front de 0-1), soit le front descendant (front de 1-0) du impulsions arrivant à ces entrées.

L'essentiel est que la fréquence des impulsions entrantes ne dépasse pas la fréquence d'horloge du processeur, sinon il n'aura pas le temps de traiter les impulsions.

De plus, T/C2 est capable de fonctionner en mode asynchrone. Autrement dit, le T/S ne compte pas les impulsions d'horloge du processeur, ni les impulsions entrantes dans les jambes, mais les impulsions de son propre oscillateur, alimenté par un quartz séparé. Pour ce faire, le T/C2 dispose d'entrées TOSC1 et TOSC2, sur lesquelles vous pouvez fixer un résonateur à quartz.

Pourquoi est-ce même nécessaire ? Oui, organisez au moins une horloge en temps réel. J'y ai accroché une horloge à quartz à 32768 Hz et j'ai compté le temps - 128 débordements se produiront par seconde (puisque T/C2 est à huit bits). Un débordement équivaut donc à 1/128 de seconde. De plus, le temporisateur ne s'arrête pas pendant le traitement de l'interruption de débordement ; il continue également à compter. L'horloge est donc un jeu d'enfant !

Pré-diviseur
Si le temporisateur compte les impulsions provenant d'un générateur d'horloge ou de son générateur interne, elles peuvent toujours être transmises via un préscaler.

Autrement dit, avant même d'entrer dans le registre de comptage, la fréquence d'impulsion sera divisée. Vous pouvez diviser par 8, 32, 64, 128, 256, 1024. Donc, si vous placez un quartz d'horloge sur T/C2 et que vous le passez dans un pré-échelonneur à 128, alors votre minuterie fonctionnera à une vitesse d'un tick par seconde.

Confortable! Il est également pratique d'utiliser un prescaler lorsque vous avez juste besoin d'obtenir un intervalle important, et que la seule source de ticks est le générateur d'horloge du processeur à 8 MHz, vous en aurez marre de compter ces mégahertz, mais si vous le passez par le prescaler , à 10h24, alors tout est beaucoup plus heureux.

Mais il y a une particularité ici, le fait est que si nous lançons le T/S avec une sorte de pré-échelle brutale, par exemple à 1024, alors le premier tick du registre de comptage n'interviendra pas nécessairement après 1024 impulsions.

Cela dépend de l'état dans lequel se trouve le préscaler. Et si, au moment où nous l'avons allumé, il avait déjà compté jusqu'à près de 1024 ? Cela signifie qu'il y aura une coche immédiatement. Le pré-échelonneur fonctionne tout le temps, que la minuterie soit activée ou non.

Par conséquent, les préscalers peuvent et doivent être réinitialisés. Vous devez également prendre en compte le fait que le préscaler est le même pour tous les compteurs, donc lors de sa réinitialisation, vous devez prendre en compte le fait qu'un autre minuteur perdra du temps jusqu'au prochain tick, et il peut se tromper exactement Par ici.

Par exemple, le premier timer fonctionne sur la broche 1:64 et le second sur la broche 1:1024 du prescaler. Le second a presque atteint 1024 dans le pré-échelonneur et maintenant il devrait y avoir un tick de minuterie, mais vous êtes ensuite allé réinitialiser le pré-échelonneur pour démarrer le premier temporisateur exactement à partir de zéro. Que va-t-il se passer ? C'est vrai, le deuxième diviseur sera immédiatement réinitialisé à 0 (le pré-échelonneur est le même, il a un registre) et le deuxième temporisateur devra attendre encore 1024 cycles d'horloge pour obtenir l'impulsion souhaitée !

Et si vous réinitialisez le pré-échelonneur dans la boucle, au profit du premier minuteur, plus d'une fois tous les 1024 cycles d'horloge, alors le deuxième minuteur ne fonctionnera jamais et vous vous cognerez la tête sur la table en essayant de comprendre pourquoi votre deuxième minuterie ne fonctionne pas, bien que ce soit nécessaire.

Pour réinitialiser les prescalers, écrivez simplement le bit PSR10 dans le registre SFIOR. Le bit PSR10 sera réinitialisé automatiquement au prochain cycle d'horloge.

Registre des comptes
Le résultat complet du tourment décrit ci-dessus est accumulé dans le registre de comptage TCNTx, où x est le numéro de la minuterie. il peut être de huit ou seize bits, auquel cas il se compose de deux registres TCNTxH et TCNTxL - respectivement les octets de poids fort et de poids faible.

Et il y a un piège ici, si vous devez mettre un nombre dans un registre de huit bits, alors il n'y a aucun problème OUT TCNT0, Rx et pas de clous, alors avec des registres à deux octets, vous devrez jouer.

Et le fait est que le minuteur compte indépendamment du processeur, donc on peut mettre un octet en premier, il commencera à compter, puis le second, et le recalcul commencera en tenant compte du deuxième octet.

Se sentir mal? Ici! Le timer est un appareil précis, ses registres de comptage doivent donc être chargés en même temps ! Mais comment? Et les ingénieurs d'Atmel ont résolu le problème simplement :
Le registre haut (TCNTxH) est écrit en premier dans le registre TEMP. Ce registre est purement officiel et ne nous est en aucun cas accessible.

Ce que nous obtenons : nous écrivons l'octet de poids fort dans le registre TEMP (pour nous, c'est un sacré TCNTxH), puis nous écrivons l'octet de poids faible. A ce moment, la valeur que nous avons enregistrée précédemment est entrée dans le TCNTxH réel. Autrement dit, deux octets, haut et bas, sont écrits simultanément ! Vous ne pouvez pas modifier la commande ! La seule façon

Cela ressemble à ceci :

CLI ; Nous interdisons les interruptions, à coup sûr ! SORTIE TCNT1H,R16 ; L'octet de poids fort a été écrit en premier dans TEMP OUT TCNT1L,R17 ; Et maintenant, je me suis inscrit aux cours seniors et juniors ! SEI ; Activer les interruptions

Pourquoi désactiver les interruptions ? Oui, pour qu'après avoir écrit le premier octet, le programme ne se précipite pas accidentellement sans interruption, puis quelqu'un viole notre minuterie. Alors dans ses registres ce ne sera pas ce que nous avons envoyé ici (ou dans l'interruption), mais qu'est-ce que c'est. Alors essayez d'attraper un tel bug plus tard ! Mais cela peut survenir au moment le plus inopportun, mais vous ne l’attraperez pas, car une interruption est presque une variable aléatoire. De tels moments doivent donc être abordés immédiatement.

Tout se lit de la même manière, mais dans l'ordre inverse. Tout d'abord, l'octet de poids faible (tandis que celui de poids fort est placé dans TEMP), puis celui de poids fort. Cela garantit que nous comptons exactement l'octet qui se trouvait actuellement dans le registre de comptage, et non celui qui était en cours d'exécution pendant que nous le retirions du registre de comptage.

Registres de contrôle
Je ne décrirai pas toutes les fonctions des minuteries, sinon cela s'avérera être un traité écrasant. Il vaut mieux parler du principal - celui du comptage, et toutes sortes de générateurs PWM et autres seront dans un autre article. Alors soyez patient, ou mâchez la fiche technique, c’est aussi utile.

Le registre principal est donc TCCRx
Pour T/C0 et T/C2, il s'agit respectivement de TCCR0 et TCCR2, et pour T/C1, il s'agit de TCCR1B.

Pour l’instant, nous ne nous intéressons qu’aux trois premiers bits de ce registre :
CSx2.. CSx0, remplacez x par le numéro du minuteur.
Ils sont responsables du réglage du prescaler et de la source d’horloge.

Les différents timers sont légèrement différents, je décrirai donc les bits CS02..CS00 uniquement pour le timer 0.

  • 000 - minuterie arrêtée
  • 001 — le préscaler est égal à 1, c'est-à-dire désactivé. la minuterie compte les impulsions d'horloge
  • 010 - le préscaler est de 8, la fréquence d'horloge est divisée par 8
  • 011 - le préscaler est de 64, la fréquence d'horloge est divisée par 64
  • 100 - le préscaler est de 256, la fréquence d'horloge est divisée par 256
  • 101 - le préscaler est 1024, la fréquence d'horloge est divisée par 1024
  • 110 - les impulsions d'horloge proviennent de la broche T0 lors de la transition de 1 à 0
  • 111 - les impulsions d'horloge proviennent de la broche T0 lors de la transition de 0 à 1

Interruptions
Chaque événement matériel comporte une interruption et la minuterie ne fait pas exception. Dès qu'un débordement ou un autre événement curieux se produit, une interruption apparaît immédiatement.

Les registres TIMSK et TIFR sont responsables des interruptions des minuteries. Et les AVR plus cool, comme ATMega128, ont également ETIFR et ETIMSK - une sorte de continuation, puisqu'il y aura plus de minuteries.

TIMSK est un registre de masques. Autrement dit, les bits qu'il contient activent localement les interruptions. Si le bit est activé, l'interruption spécifique est activée. Si le bit est nul, alors cette interruption est recouverte d'un bassin. Par défaut, tous les bits sont nuls.

Pour le moment, nous ne nous intéressons qu’aux interruptions de débordement. Les bits en sont responsables

  • TOIE0 - autorisation d'interrompre en cas de débordement du timer 0
  • TOIE1 - autorisation d'interrompre en cas de débordement du timer 1
  • TOIE2 - autorisation d'interrompre en cas de débordement du timer 2

Nous parlerons d'autres fonctionnalités et des interruptions de minuterie plus tard, lorsque nous examinerons PWM.

Le registre TIFR est directement un registre de drapeaux. Lorsqu'une interruption est déclenchée, un drapeau apparaît indiquant que nous avons une interruption. Cet indicateur est réinitialisé par le matériel lorsque le programme quitte le vecteur. Si les interruptions sont désactivées, l'indicateur restera là jusqu'à ce que les interruptions soient activées et que le programme passe à l'interruption.

Pour éviter que cela ne se produise, le drapeau peut être réinitialisé manuellement. Pour cela, vous devez écrire 1 dans le registre TIFR !

Maintenant, baisons
Eh bien, repensons le programme pour qu'il fonctionne avec une minuterie. Introduisons une minuterie de programme. L’orgue de Barbarie le restera, laissez-le tourner. Et nous ajouterons une deuxième variable, également quatre octets :

ORG 010$ RETI ; (TIMER1 OVF) Débordement du minuteur/compteur1 .ORG $012 RJMP Timer0_OV ; (TIMER0 OVF) Débordement minuterie/compteur0 .ORG $014 RETI ; (SPI, STC) Transfert série terminé

Ajoutons un gestionnaire d'interruption pour le dépassement du minuteur 0 à la section Interruption. Puisque notre macro de ticking fonctionne activement avec les indicateurs de registre et de corruption, nous devons d'abord enregistrer tout cela sur la pile :

Au fait, créons une autre macro qui place le registre du drapeau SREG sur la pile et une seconde qui le récupère à partir de là.

1 2 3 4 5 6 7 8 9 10 11 12 .MACRO PUSHF PUSH R16 IN R16,SREG PUSH R16 .ENDM .MACRO POPF POP R16 OUT SREG,R16 POP R16 .ENDM

MACRO PUSHF PUSH R16 IN R16,SREG PUSH R16 .ENDM .MACRO POPF POP R16 OUT SREG,R16 POP R16 .ENDM

Comme effet secondaire, il retient également le R16, n'oubliez pas que :)

1 2 3 4 5 6 7 8 9 10 11 12 13 Timer0_OV : PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI

Timer0_OV : PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI

Maintenant, initialisez la minuterie. Ajoutez-le à la section Internal Hardware Init.

; Initialisation du matériel interne ======================================= SETB DDRD,4,R16 ; DDRD.4 = 1 JEU DDRD,5,R16 ; DDRD.5 = 1 JEU DDRD,7,R16 ; DDRD.7 = 1 JEU PORTD,6,R16 ; Sortie PD6 vers entrée pull-up CLRB DDRD,6,R16 ; Lire le bouton SETB TIMSK,TOIE0,R16 ; Activer l'interruption du temporisateur OUTI TCCR0,1<

Il ne reste plus qu'à réécrire notre bloc de comparaison et recalculer le nombre. Maintenant, tout est simple, on coche une barre. Sans aucun problème avec différentes longueurs de code. Pour une seconde à 8 MHz, 8 millions de ticks doivent être effectués. En hexadécimaux, c'est 7A 12 00, en tenant compte du fait que l'octet de poids faible est TCNT0, puis 7A 12 est laissé pour notre compteur ainsi que les deux octets les plus élevés 00 00, ils n'ont pas besoin d'être vérifiés. Il n’est pas nécessaire de masquer ; nous réinitialiserons le minuteur plus tard de toute façon.

Il n'y a qu'un seul problème : l'octet de poids faible, celui du timer. Il coche chaque case et il sera presque impossible de vérifier la conformité. Parce que le moindre écart et la condition de comparaison apparaîtront dans NoMatch, mais le deviner pour que la vérification de sa valeur coïncide avec cette étape particulière... Il est plus facile de retirer une aiguille d'une botte de foin du premier coup au hasard.

La précision dans ce cas est donc limitée - vous devez avoir le temps de vérifier la valeur avant qu'elle ne quitte la plage. Dans ce cas, la plage sera, pour simplifier, 255 - la valeur de l'octet de poids faible, celui du temporisateur.

Ensuite, notre deuxième est doté d'une précision de 8 000 000 plus ou moins 256 cycles. L'erreur n'est pas grande, seulement 0,003 %.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 ; Principal ================================================== ================ ======== Principal : SBIS PIND,6 ; Si le bouton est enfoncé - transition RJMP BT_Push SETB PORTD,5 ; Allumons LED2 CLRB PORTD,4 ; Éteignez la LED1 Suivant : LDS R16,TCNT ; Charger les nombres dans les registres LDS R17,TCNT+1 CPI R16.0x12 ; Comparons octet par octet. Premier octet BRCS NoMatch ; Si c’est moins, cela signifie qu’il n’a pas touché. IPC R17.0x7A ; Deuxième octet BRCS NoMatch ; Si c’est moins, cela signifie qu’il n’a pas touché. ; Si cela correspond, alors nous effectuons l'action Match : INVB PORTD,7,R16,R17 ; LED3 inversée ; Il faut maintenant réinitialiser le compteur, sinon lors de la même itération de la boucle principale ; nous y reviendrons plus d'une fois - le minuteur n'aura pas le temps d'atteindre 255 valeurs ; de sorte que le nombre dans les deux premiers octets du compteur change et que la condition soit déclenchée. ; Bien sûr, vous pouvez contourner cela avec un indicateur supplémentaire, mais c'est plus simple de réinitialiser le compteur :) CLR R16 ; Nous n’avons besoin d’aucun CLI ; Accès à une variable multi-octets ; simultanément de l'interruption et de l'arrière-plan ; vous avez besoin d'un accès atomique. Désactiver les interruptions OUTU TCNT0,R16 ; Zéro au registre de comptage du temporisateur STS TCNT, R16 ; Zéro dans le premier octet du compteur en RAM STS TCNT+1,R16 ; Zéro dans le deuxième octet du compteur en RAM STS TCNT+2,R16 ; Zéro dans le troisième octet du compteur en RAM STS TCNT+3,R16 ; Zéro dans le premier octet du compteur en RAM SEI ; Réactivons les interruptions. ; Si cela ne correspond pas, nous ne le faisons pas :) NoMatch: NOP INCM CCNT ; Le compteur de cycles tourne ; Même s'il n'est pas utilisé. BT_Push principal JMP : SETB PORTD,4 ; Allumer la LED1 CLRB PORTD,5 ; Éteignez LED2 RJMP Suivant ; Fin principale ================================================= ================ =====

; Principal ================================================== ================ ======== Principal : SBIS PIND,6 ; Si le bouton est enfoncé - transition RJMP BT_Push SETB PORTD,5 ; Allumer la LED2 CLRB PORTD,4 ; Éteignez la LED1 Suivant : LDS R16,TCNT ; Charger les nombres dans les registres LDS R17,TCNT+1 CPI R16.0x12 ; Comparons octet par octet. Premier octet BRCS NoMatch ; Si c’est moins, cela signifie qu’il n’a pas touché. IPC R17.0x7A ; Deuxième octet BRCS NoMatch ; Si c’est moins, cela signifie qu’il n’a pas touché. ; Si cela correspond, alors nous effectuons l'action Match : INVB PORTD,7,R16,R17 ; LED3 inversée ; Il faut maintenant réinitialiser le compteur, sinon lors de la même itération de la boucle principale ; nous y reviendrons plus d'une fois - le minuteur n'aura pas le temps d'atteindre 255 valeurs ; de sorte que le nombre dans les deux premiers octets du compteur change et que la condition soit déclenchée. ; Bien sûr, vous pouvez contourner cela avec un indicateur supplémentaire, mais c'est plus simple de réinitialiser le compteur :) CLR R16 ; Nous n’avons besoin d’aucun CLI ; Accès à une variable multi-octets ; simultanément de l'interruption et de l'arrière-plan ; vous avez besoin d'un accès atomique. Désactiver les interruptions OUTU TCNT0,R16 ; Zéro au registre de comptage du temporisateur STS TCNT, R16 ; Zéro dans le premier octet du compteur en RAM STS TCNT+1,R16 ; Zéro dans le deuxième octet du compteur en RAM STS TCNT+2,R16 ; Zéro dans le troisième octet du compteur en RAM STS TCNT+3,R16 ; Zéro dans le premier octet du compteur en RAM SEI ; Réactivons les interruptions. ; Si cela ne correspond pas, nous ne le faisons pas :) NoMatch: NOP INCM CCNT ; Le compteur de cycles tourne ; Même s'il n'est pas utilisé. BT_Push principal JMP : SETB PORTD,4 ; Allumer la LED1 CLRB PORTD,5 ; Éteignez LED2 RJMP Suivant ; Fin principale ================================================= ================ =====

Voilà à quoi ça ressemble en action

Et si nous devons faire clignoter une deuxième diode avec une période différente, nous pouvons alors mettre en toute sécurité une autre variable dans le programme, et dans le gestionnaire d'interruption de minuterie, nous pouvons incrémenter deux variables à la fois. Les vérifier un par un dans la boucle du programme principal.

Vous pouvez optimiser un peu plus le processus de vérification. Fais le plus rapidement.

Il vous suffit de faire augmenter le compte, mais de le diminuer. Ceux. Nous chargeons un nombre dans une variable et commençons à le décrémenter dans l'interruption. Et là, dans le gestionnaire, nous vérifions zéro. Si zéro, alors définissez un indicateur en mémoire. Et notre programme d'arrière-plan capte ce drapeau et lance l'action, réinitialisant simultanément la vitesse d'obturation.

Mais que se passe-t-il si vous avez besoin d’être plus précis ? Eh bien, il n'y a qu'une seule option : utiliser le traitement des événements directement dans le gestionnaire d'interruption et ajuster la valeur dans TCNT:TCNT0 à chaque fois afin que l'interruption se produise exactement au bon moment.

Les minuteries sont un autre module classique présent dans presque tous les MK. Il vous permet de résoudre de nombreux problèmes, dont le plus courant est la définition d'intervalles de temps stables. La deuxième application la plus populaire est la génération PWM (nous y reviendrons plus tard) à la sortie MK. Bien que, comme déjà mentionné, l'utilisation de minuteries ne se limite en aucun cas à ces tâches, seules ces deux tâches seront considérées ici comme les plus courantes.

La minuterie elle-même est un compteur binaire connecté au système d'horloge du microcontrôleur via un diviseur supplémentaire. À leur tour, des unités de comparaison y sont connectées (il peut y en avoir plusieurs), capables d'exécuter diverses fonctions utiles et de générer des interruptions, en fonction des paramètres. Simplifié, le dispositif temporisateur peut être représenté comme suit :

La minuterie, comme tous les autres périphériques, est configurée via ses registres.

Générer des intervalles de temps à l'aide d'une minuterie.

Interruptions.

Comme son nom l'indique, l'objectif principal des blocs de comparaison est de comparer constamment la valeur actuelle de la minuterie avec la valeur spécifiée dans le registre OCRnX. Il a déjà été mentionné que les noms de registres portent souvent une profonde signification sacrée - et les registres de comparaison ne font pas exception. Ainsi, n désigne le numéro du temporisateur, X est la lettre (également une méthode de numérotation, il peut y avoir plusieurs blocs de comparaison) du registre de comparaison. Ainsi, ROC1A tu peux comprendre comment Ô sortie C comparer R. registre de 1 ère minuterie, unité UN. À propos, cela donnera à un intégrateur expérimenté la possibilité de supposer qu'il existe peut-être un temporisateur 0 et un registre de comparaison B...

Ainsi, les blocs de comparaison peuvent générer des interruptions chaque fois que la valeur du minuteur correspond (d'ailleurs, elle est dans le registre TCNTnT imer/ C ou NT euh# n) avec un numéro donné. Le lecteur devrait déjà être familier avec le concept d'interruption, mais juste au cas où, rafraîchissons-le en mémoire, et en même temps nous parlerons de la façon de le décrire en C. Ainsi, ce qui précède signifie que dès que l'événement décrit se produit, le processeur enregistrera le numéro de l'instruction en cours dans la pile et procédera à l'exécution d'un code spécialement défini, puis reviendra en arrière. Tout se passe presque de la même manière que lors de l'appel d'une fonction normale, sauf qu'elle est appelée au niveau matériel. De telles fonctions sont déclarées à l'aide d'une macro déclarée dans avr/interruption.h (ISR — « je interrompre S service R. outine", "gestionnaire d'interruption") :

ISR (< имя вектора прерывания> ) { /*code de gestion des interruptions*/ }

Chaque interruption (bien sûr, il y en a beaucoup) correspond à ce qu'on appelle. le vecteur d'interruption est une constante également déclarée dans avr/interrupt. Par exemple, un gestionnaire d'interruption permettant de faire correspondre une valeur de minuterie avec la valeur du registre OCR1A ressemblera à ceci :

ISR (TIMER1_COMPA_vect) ( /*code du gestionnaire*/ }

Sans aucun doute, le lecteur avisé a déjà deviné comment se forment les noms de vecteurs. Cependant, une liste complète de ces constantes peut être trouvée dans la documentation d'avr-libc (une bibliothèque de fonctions standard pour AVR-GCC).

La fiche technique (de la fiche technique anglaise) est un fichier de documentation technique, une description d'un appareil spécifique (microcircuit, transistor, etc.). Contient toutes les informations sur les caractéristiques et l'application du composant. Presque toujours au format PDF. Habituellement recherché sur Google comme "<название компонента>pdf".

Les trois derniers bits contrôlent le prescaler mentionné au tout début (le reste ne nous intéresse pas pour l'instant) :

Configurons la minuterie pour que les interruptions se produisent deux fois par seconde. Choisissons un préscaler 64 ; Pour ce faire, définissez les bits CS11 et CS10 :

TCCR1B = (1< < CS11) | (1 < < CS10) ;

La fréquence de comptage sera alors de 8 MHz/64 = 125 KHz, soit tous les 8 μS, un sera ajouté à la valeur de TCNT1. Nous voulons que les interruptions se produisent avec une période de 500 mS. Évidemment, pendant ce temps, le temporisateur comptera jusqu'à la valeur 500 mS/8μS=62500, soit 0xF424. La minuterie 1 est de seize bits, donc tout va bien.

OCR1A = 0xF424 ;

Il est clair que si la valeur calculée dépasse la capacité du minuteur, un préscaler plus grand doit être sélectionné. L'auteur laisse au lecteur la dérivation d'une formule simple pour calculer le nombre qui doit être chargé dans la minuterie pour obtenir la fréquence d'interruption requise à une fréquence de processeur et un pré-échelonneur donnés.

Il ne reste plus qu'à activer l'interruption de coïncidence - un bit du registre TIMSK1 en est responsable :

Ce qui suit est écrit à son sujet :

Alors, définissez la valeur souhaitée :

TIMSK1= (1< < OCIE1A) ;

De plus, rappelez-vous qu'avant d'utiliser les interruptions, elles doivent être activées globalement en appelant la fonction si(). Pour désactiver globalement les interruptions, utilisez la fonction cli(). Ces fonctions activent/effacent le bit je dans le registre SREG, contrôlant la possibilité même d'utiliser un mécanisme tel que les interruptions. Les registres comme TIMSKn ne sont rien de plus que des paramètres locaux pour un module spécifique.

Comme mentionné, une interruption peut survenir à tout moment, interrompant le programme n'importe où. Il existe cependant des cas où cela n’est pas souhaitable. Le mécanisme global de désactivation/activation des interruptions résout ce problème.

Ainsi, un programme qui fait clignoter une LED à l'aide d'interruptions peut être réécrit comme suit :

#inclure< avr/io.h >#inclure< avr/interrupt.h >ISR (TIMER1_COMPA_vect) ( TCNT1= 0 ; si (PORTB & (1< < PB0) ) PORTB& = ~ (1 < < PB0) ; else PORTB| = (1 < < PB0) ; } void main (void ) { DDRB= 0xFF ; PORTB= 0 ; OCR1A= 0xF424 ; TIMSK1= (1 < < OCIE1A) ; TCCR1B= (1 < < CS11) | (1 < < CS10) ; sei() ; while (1 ) ; }

On peut voir que maintenant, dans les intervalles entre les commutations des LED, le processeur est totalement libre d'effectuer d'autres tâches, alors que dans le premier exemple, il était occupé à compter inutilement les cycles d'horloge (les fonctions _delay_xx() fonctionnent exactement comme ça). Ainsi, les interruptions permettent d'organiser un multitâche primitif.

Génération de PWM à l'aide d'une minuterie.

Avec certains réglages, des blocs de comparaison permettent d'organiser la génération matérielle d'un signal PWM sur les pattes MK, désignées comme OCnX :

PWM (PWM) — Ch irotno- ET impulsion M. modulation ( P. ulcère W identité M. odulation). Un signal PWM est une séquence d'impulsions rectangulaires de durée variable :

Pour PWM, deux caractéristiques liées sont introduites : le rapport cyclique (D) et le rapport cyclique - l'inverse du rapport cyclique. Le rapport cyclique est le rapport entre le temps d'impulsion et la durée de la période :

Le facteur de service est souvent exprimé en pourcentage, mais son écriture en décimales est également courante.

L'importance du PWM pour l'économie nationale réside dans le fait que la valeur de tension effective d'un tel signal est directement proportionnelle au rapport cyclique :

— avec cette intégrale, le manuel paraît plus solide ; la dépendance s'exprime par la formule suivante :

U avg est la valeur moyenne de la tension (ici c'est la tension réelle) ;
D - facteur de remplissage ;
U p-p est l'amplitude de l'impulsion.

Ainsi, PWM est un moyen simple d'obtenir un signal analogique à l'aide d'un microcontrôleur - pour cela, une telle séquence d'impulsions doit être transmise à un filtre passe-bas (qui, soit dit en passant, est l'incarnation physique de l'intégrale écrite ci-dessus) .

Le mode PWM le plus couramment utilisé est ce qu'on appelle. PWM rapide (vous pouvez en savoir plus sur les autres modes directement dans la documentation), alors réfléchissons-y. Dans ce cas, les blocs de comparaison fonctionnent comme suit : lorsque le temporisateur est réinitialisé, un niveau haut est appliqué à la sortie OCnX ; Dès que le compte à rebours jusqu'au nombre écrit dans OCRnX, OCnX passe au niveau bas. Tout cela se répète avec la période de débordement du compteur. Il s'avère que la largeur de l'impulsion de sortie dépend de la valeur d'OCRnX et que la fréquence de sortie est égale à la fréquence d'horloge de la minuterie divisée par sa valeur maximale. L'image de la fiche technique explique ceci :

Un mode inverse est également possible, dans lequel l'état OCnX change dans l'ordre inverse, ce qui peut être pratique en pratique.

Configuration du bloc de comparaison pour générer du PWM.

Ici, la documentation nous aidera à nouveau. Donc, vous devez d'abord basculer le bloc de comparaison en mode de génération PWM et sélectionner la sortie qui vous intéresse parmi celles disponibles. Ces paramètres sont disponibles dans le registre TCCR0A :

Nous nous intéressons aux bits WGMxx et COMnXn. On dit d'eux ce qui suit :

Autrement dit, nous nous intéressons aux bits WGM00 et WGM01 - Mode PWM rapide,

et aussi COM0A1 - PWM non inverseur sur la broche OC0A. Mise en place :

TCCR0A= (1< < COM0A1) | (1 < < WGM01) | (1 < < WGM00) ;

Naturellement, en plus de cela, le tronçon sélectionné doit être configuré pour la sortie à l'aide du registre DDR du port correspondant.

OCR0A= 128 ;

Enfin, activez la minuterie en sélectionnant le diviseur. Tout est pareil ici :


Généralement, la fréquence la plus élevée possible est sélectionnée pour PWM (afin d'obtenir la qualité maximale du signal de sortie). C'est-à-dire qu'il est conseillé de définir la valeur minimale du diviseur :

TCCR0B= (1< < CS00) ;

À ce stade, la configuration PWM est terminée et le signal peut être vu sur la broche sélectionnée.

Comme mentionné ci-dessus, le PWM est un moyen simple de produire un signal analogique à l'aide d'un MCU. Par exemple, vous pouvez organiser un clignotement fluide de la LED (dans ce cas, le rôle de filtre passe-bas intégrateur est joué par l'œil de l'observateur, de sorte que la LED peut être connectée à la jambe MK via une résistance ordinaire ).

Certains points de l'exemple proposé nécessitent des éclaircissements.

La liste des fichiers inclus contient un mystérieux stdint.h— ce fichier déclare des types avec une profondeur de bits explicitement spécifiée, par exemple

uint8_ttoi non signé 8 -peu int eger t ouais
uint16_ttoi non signé 16 -peu int eger t ouais
uint32_ttoi non signé 32 -peu int eger t ouais
int8_t-signé 8 -peu int eger t ouais

et ainsi de suite. Ces types favorisent l’uniformité et la lisibilité du programme. De plus, il est garanti que lors du portage du code, la profondeur de bits des données restera spécifiée. Et, en passant, uint8_t est beaucoup plus rapide à écrire qu'un caractère non signé.

Modificateur volatil signifie qu'il est interdit au compilateur d'optimiser cette variable. Par exemple, si vous compilez l'exemple suivant :

void main (void) ( unsigned char i= 0 ; while (1) ( i+ + ; ) )

Après quoi vous examinez le code désassemblé, vous constaterez qu’en fait aucune variable n’a été créée et que le programme est une boucle vide. Cela s'est produit parce que l'optimiseur a considéré la variable comme inutilisée et ne l'a pas incluse dans le code résultant. Si une variable ainsi déclarée était utilisée, par exemple, dans une interruption, une telle liberté de l'optimiseur entraînerait un dysfonctionnement du programme. Application volatil exclut un tel comportement.

#inclure #inclure #inclure volatile uint8_t pwm_value= 0 , dn_count= 0 ; ISR (TIMER1_COMPA_vect) ( TCNT1= 0 ; si (dn_count) //changez en douceur la luminosité de la diode, une étape à la fois pwm_value--; sinon pwm_value++; si (pwm_value== 0 ) //vérifier les limites, allumer/éteindre dn_count= 0 ; si (pwm_value== 0xFF ) dn_count= 1 ; OCR0A= valeur_pwm ; //définit un nouveau coefficient. remplissage) void main(void) (DDRD= 0xFF; //configuration du port de sortie PORTD= 0 ; OCR1A = 0xF424 ; //constante définissant la fréquence d'interruption TIMSK1= (1<< OCIE1A) ; //active l'interruption lorsque le canal A coïncide TCCR1B = (1<< CS11) | (1 << CS10) ; //démarre le minuteur 1 TCCR0A= (1<< COM0A1) | (1 << WGM01) | (1 << WGM00) ; //la minuterie 0 générera du PWM OCR0A= 128 ; //valeur PWM initiale TCCR0B= (1<< CS00) ; //démarre le minuteur 0 si() ; //activer les interruptions tandis que(1); //c'est tout, le processus se poursuit ensuite en utilisant des interruptions et du matériel PWM } $37 ($57)
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0
TIMSK Lire écrire
  • Bit 7 - OCIE2 : Activation de l'interruption de comparaison de sortie minuterie/compteur 2 - Activer l'interruption de correspondance minuterie/compteur 2
    Lorsque le bit OCIE2 est activé et que le bit I du registre d'état est activé, une interruption est activée lorsque le contenu du registre de comparaison coïncide avec l'état du temporisateur/compteur2. L'interruption correspondante (avec le vecteur $0012) est exécutée si une correspondance se produit lors de la comparaison du contenu du registre de comparaison et de l'état du timer/counter2. Le registre d'indicateur d'interruption de minuterie/compteur (TIFR) définit l'indicateur de correspondance de minuterie/compteur2.
  • Bit 6 - TOIE2 : Activation de l'interruption de débordement du minuteur/compteur 2 - Activer l'interruption de débordement du minuteur/compteur 2
    Lorsque le bit TOIE2 est activé et que le bit I du registre d'état est activé, l'interruption de dépassement du temporisateur/compteur 2 est activée. L'interruption correspondante (avec le vecteur $0014) est exécutée si le timer/counter2 déborde. L'indicateur de dépassement de minuterie/compteur2 est défini dans le registre d'indicateurs TIFR (Timer/Counter Interrupt Flag Register).
  • Bit 5 - TICIE1 : Activation de l'interruption de capture d'entrée minuterie/compteur 1 - Activer l'interruption pour capturer la minuterie/compteur 1
    Lorsque le bit TICIE1 est activé et que le bit I du registre d'état est activé, l'interruption de capture timer/counter1 est activée. L'interruption correspondante (avec le vecteur $0016) est exécutée si la capture est déclenchée sur la broche 29, PD4(IC1). Le registre d'indicateurs TIFR (Timer/Counter Interrupt Flag Register) définit l'indicateur de capture du temporisateur/compteur1.
  • Bit 4 - OCE1A : sortie minuterie/compteur 1 CompareA Match Interrupt Enable - Activer l'interruption lorsque le registre A correspond à la minuterie/compteur 1
    Lorsque le bit OCIE1A est activé et que le bit I du registre d'état est activé, une interruption est activée lorsque le registre A correspond à l'état du temporisateur/compteur1. L'interruption correspondante (avec le vecteur $0018) est exécutée si le contenu du registre de comparaison de sortie A coïncide avec l'état du temporisateur/compteur1. Dans le registre d'indicateurs TIFR (Timer/Counter Interrupt Flag Register), l'indicateur correspondant du registre A avec le temporisateur/compteur 1 est activé.
  • Bit 3 - OCIE1B : Sortie Timer/Counter1 CompareB Match Interrupt Enable - Activer l'interruption lorsque le registre B correspond au timer/counter1
    Lorsque le bit OCIE1B est activé et que le bit I du registre d'état est activé, une interruption est activée lorsque le registre B correspond à l'état du temporisateur/compteur1. L'interruption correspondante (avec le vecteur $001A) est exécutée si le contenu du registre de comparaison de sortie B coïncide avec l'état du temporisateur/compteur1. Dans le registre d'indicateurs TIFR (Timer/Counter Interrupt Flag Register), l'indicateur correspondant du registre B avec le temporisateur/compteur 1 est activé.
  • Bit 2 - TOIE1 : Activation de l'interruption de débordement du minuteur/compteur 1 - Activer l'interruption de débordement du minuteur/compteur 1
    Lorsque le bit OCIE1B est activé et que le bit I du registre d'état est activé, l'interruption de dépassement du temporisateur/compteur 1 est activée. L'interruption correspondante (avec le vecteur $001C) est exécutée si le timer/counter1 déborde. Dans le registre d'indicateur TIFR (Timer/Counter Interrupt Flag Register), l'indicateur de débordement timer/counter1 est activé. Lorsque le timer/counter1 est en mode PWM, l'indicateur de dépassement de compteur est activé lorsque le compteur change de sens de comptage à 0000 $.
  • Bit 1 - OCIE0 : Activation de l'interruption de comparaison de sortie minuterie/compteur 0 - Activer l'interruption de correspondance minuterie/compteur0
    Lorsque le bit OCIE0 est activé et que le bit I du registre d'état est activé, une interruption est activée lorsque le contenu du registre de comparaison coïncide avec l'état du temporisateur/compteur0. L'interruption correspondante (avec le vecteur $001E) est exécutée si une correspondance se produit lors de la comparaison du contenu du registre de comparaison et de l'état du timer/counter0. Le registre d'indicateur d'interruption de minuterie/compteur (TIFR) est réglé sur l'indicateur de correspondance de minuterie/compteur 0.
  • Bit 0 - TOIE0 : Activation de l'interruption de débordement du minuteur/compteur 0 - Activer l'interruption de débordement du minuteur/compteur 0
    Lorsque le bit TOIE0 est activé et que le bit I du registre d'état est activé, l'interruption de débordement timer/counter0 est activée. L'interruption correspondante (avec le vecteur $0020) est exécutée si timer/counter0 déborde. Le registre d'indicateur d'interruption de minuterie/compteur (TIFR) définit l'indicateur de dépassement de minuterie/compteur0.