En regardant les croquis que d'autres personnes ont écrits, je tombe parfois sur du code qui ressemble un peu à ceci:
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 34286;
TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << TOIE1);
Tout ce que je sais, c'est que ça a quelque chose à voir avec le timing / les minuteries (je pense). Comment puis-je déchiffrer et créer un code comme celui-ci? Quels sont TCCR1A
, TCCR1B
, TCNT1
, CS12
, TIMSK1
et TOIE1
?
timers
programming
Le gars avec le chapeau
la source
la source
Réponses:
Ce n'est pas bizarre. C'est à quoi ressemble le code MCU normal.
Ce que vous avez ici est un exemple du concept de périphériques mappés en mémoire . Fondamentalement, le matériel MCU a des emplacements spéciaux dans l'espace d'adressage SRAM du MCU qui lui est affecté. Si vous écrivez à ces adresses, les bits de l'octet écrit à l'adresse n contrôlent le comportement du périphérique m .
Fondamentalement, certaines banques de mémoire ont littéralement de petits câbles allant de la cellule SRAM au matériel. Si vous écrivez un "1" à ce bit dans cet octet, il définit cette cellule SRAM à un niveau logique élevé, qui allume ensuite une partie du matériel.
Si vous regardez dans les en-têtes du MCU, il existe de grands grands tableaux de mappages d'adresses de mots clés <->. C'est ainsi que des choses comme
TCCR1B
etc ... sont résolues au moment de la compilation.Ce mécanisme de mappage de la mémoire est extrêmement largement utilisé dans les MCU. Le MCU ATmega de l'arduino l'utilise, tout comme les séries MCU PIC, ARM, MSP430, STM32 et STM8, ainsi que de nombreux MCU que je ne connais pas immédiatement.
Le code Arduino est le truc bizarre, avec des fonctions qui accèdent indirectement aux registres de contrôle MCU. Bien que ce soit un peu plus "joli", il est également beaucoup plus lent et utilise beaucoup plus d'espace programme.
Les mystérieuses constantes sont toutes décrites en détail dans la fiche technique ATmega328P , que vous devriez vraiment lire si vous êtes intéressé à faire autre chose que de basculer occasionnellement des broches sur un arduino.
Sélectionnez des extraits de la fiche technique liée ci-dessus:
Ainsi, par exemple,
TIMSK1 |= (1 << TOIE1);
définit le bitTOIE1
dansTIMSK1
. Ceci est réalisé en déplaçant le binaire 1 (0b00000001
) vers la gauche par desTOIE1
bits, enTOIE1
étant défini dans un fichier d'en-tête comme 0. Ceci est ensuite OR au niveau du bit dans la valeur actuelle deTIMSK1
, ce qui place effectivement ce bit à un niveau élevé.En regardant la documentation pour le bit 0 de
TIMSK1
, nous pouvons voir qu'il est décrit commeToutes les autres lignes doivent être interprétées de la même manière.
Quelques notes:
Vous pouvez également voir des choses comme
TIMSK1 |= _BV(TOIE1);
._BV()
est une macro couramment utilisée à l' origine de l' implémentation AVC libc ._BV(TOIE1)
est fonctionnellement identique à(1 << TOIE1)
, avec l'avantage d'une meilleure lisibilité.Vous pouvez également voir des lignes telles que:
TIMSK1 &= ~(1 << TOIE1);
ouTIMSK1 &= ~_BV(TOIE1);
. Cela a la fonction inverse deTIMSK1 |= _BV(TOIE1);
, en ce qu'elle met à l' arrêt le bitTOIE1
dansTIMSK1
. Ceci est obtenu en prenant le masque de bits produit par_BV(TOIE1)
, en effectuant une opération NON au niveau du bit sur celui-ci (~
), puis en effectuant un ANDTIMSK1
par cette valeur NOTée (qui est 0b11111110).Notez que dans tous ces cas, la valeur de choses comme
(1 << TOIE1)
ou_BV(TOIE1)
sont entièrement résolues au moment de la compilation , de sorte qu'elles se réduisent fonctionnellement à une simple constante et ne prennent donc aucun temps d'exécution pour calculer au moment de l'exécution.Un code correctement écrit comportera généralement des commentaires en ligne avec le code qui détaillent les tâches assignées aux registres. Voici une routine soft-SPI assez simple que j'ai écrite récemment:
PORTC
est le registre qui contrôle la valeur des broches de sortie dansPORTC
l'ATmega328P.PINC
est le registre où les valeurs d' entrée dePORTC
sont disponibles. Fondamentalement, des choses comme celles-ci se produisent en interne lorsque vous utilisez les fonctionsdigitalWrite
oudigitalRead
. Cependant, il existe une opération de recherche qui convertit les "numéros de broche" arduino en numéros de broche matériels réels, ce qui prend quelque part dans le domaine de 50 cycles d'horloge. Comme vous pouvez probablement le deviner, si vous essayez d'aller vite, gaspiller 50 cycles d'horloge sur une opération qui ne devrait nécessiter qu'un seul est un peu ridicule.La fonction ci-dessus prend probablement quelque part dans le domaine de 100-200 cycles d'horloge pour transférer 8 bits. Cela implique 24 écritures et 8 lectures. C'est beaucoup, beaucoup plus rapide que d'utiliser les
digital{stuff}
fonctions.la source
TCCR1A
est le registre de contrôle du temporisateur / compteur 1 ATCCR1B
est le registre de commande du temporisateur / compteur 1 BTCNT1
est la valeur du compteur du temporisateur / compteur 1CS12
est le 3e bit de sélection d'horloge pour le temporisateur / compteur 1TIMSK1
est le registre de masque d'interruption du temporisateur / compteur 1TOIE1
est l'activation de l'interruption de dépassement du temporisateur / compteur 1Ainsi, le code active le temporisateur / compteur 1 à 62,5 kHz et définit la valeur à 34286. Ensuite, il active l'interruption de débordement, donc lorsqu'il atteindra 65535, il déclenchera la fonction d'interruption, très probablement étiquetée comme
ISR(timer0_overflow_vect)
la source
CS12 a une valeur de 2 car il représente le bit 2 du registre TCCR1B.
(1 << CS12) prend la valeur 1 (0b00000001) et la décale 2 fois vers la gauche pour obtenir (0b00000100). L'ordre des opérations dicte que les choses dans () se produisent en premier, donc cela se fait avant que le "| =" ne soit évalué.
(1 << CS10) prend la valeur 1 (0b00000001) et la décale vers la gauche 0 fois pour obtenir (0b00000001). L'ordre des opérations dicte que les choses dans () se produisent en premier, donc cela se fait avant que le "| =" ne soit évalué.
Alors maintenant, nous obtenons TCCR1B | = 0b00000101, qui est le même que TCCR1B = TCCR1B | 0b00000101.
Depuis "|" est "OU", tous les bits autres que CS12 dans TCCR1B ne sont pas affectés.
la source