Lire et écrire des bits individuels dans un registre. Ports du microcontrôleur AVR. Registre des données d'entrée du port D – PIND

L'un des aspects les plus importants de la programmation des microcontrôleurs consiste à travailler avec les registres et les ports. Les microcontrôleurs de la série AVR disposent de plusieurs registres d'E/S et de 32 registres de travail à usage général. Le programmeur ne peut pas écrire directement un numéro dans le registre d'E/S. Au lieu de cela, il doit écrire un nombre dans un registre à usage général, puis copier la valeur de ce registre dans un registre d'E/S. Les registres de travail sont désignés par R1, R2, ..., R31.

Pour faciliter l'écriture des programmes, il est très pratique de donner des noms aux registres. Il est conseillé de donner des noms qui correspondent aux informations stockées. Par exemple, si le registre R16 est utilisé pour stocker des informations temporaires, il peut alors être appelé temp. Cela se fait comme suit:

Afin de ne pas « nommer » les registres d'entrées/sorties et les registres principaux du microcontrôleur, il suffit de connecter le fichier d'en-tête correspondant au microcontrôleur utilisé au début du programme. Ceux. vous n'aurez pas à donner de noms aux registres de ports, aux minuteries/compteurs, etc. Par exemple, si le programme est destiné au microcontrôleur AT90s8515 :

Inclure "8515def.inc"

Pour le microcontrôleur AT90s1200 - le tout premier microcontrôleur AVR, les registres d'entrée/sortie portent des numéros allant de 0 $ à 3F $ (selon le modèle MK). Séparément, nous pouvons mettre en évidence les registres d'entrée/sortie PortB, PinB, PortD, PinD (ils ont des désignations de lettres après avoir connecté 1200def.inc, et leurs adresses sont 18 $, 16 $, 12 $, 10 $ - vous devez admettre qu'il est très difficile de conserver constantes numériques dans votre tête, les noms de lettres sont plus faciles) . Les derniers microcontrôleurs AVR possèdent beaucoup plus de ports, ils sont appelés A, B, C, D, E...

Examinons la disposition des broches du populaire microcontrôleur ATtiny2313. Les broches 2 à 9, 11, nommées PD0 à PD7, sont le port D, similaire au port B. Notez que le port B est à huit bits et le port D à sept bits.

Les ports peuvent agir comme entrées ou sorties. Si le port fonctionne comme une entrée, alors pour lire les valeurs, vous devez accéder au registre PinB ou PinD - selon le port à partir duquel nous lisons. Si certaines broches ont des niveaux élevés, le journal correspondant. "1", alors les bits correspondants dans les valeurs lues seront mis à "1". Les broches peuvent supporter un courant allant jusqu'à 20 mA, mais n'oubliez pas le courant total de toutes les broches du port car il y a des restrictions. Si le port est une sortie, alors les valeurs sur les lignes de port sont définies en écrivant la valeur appropriée dans le registre de port PortB ou PortD. Pour établir un journal. "1" à la sortie du port, le bit correspondant doit être défini dans le registre PortB ou PortD.

Le point le plus important dans le travail avec un port est de travailler avec le registre à verrouillage, qui est responsable du fonctionnement des lignes de port en entrée ou en sortie. Le nom de ce registre est DDRx, où x est la lettre du port. Afin de faire sortir les broches, il faut écrire « 1 » sur les bits correspondants. Par exemple, nous voulons faire de la broche PB7 du port B une entrée et des broches restantes des sorties, alors pour cela nous devons écrire la valeur 0b01111111 dans le registre DDRB. Le préfixe 0b signifie que le nombre est écrit sous forme binaire. Au démarrage, les registres DDRx sont effacés, c'est-à-dire toutes les jambes sont des entrées. Il est recommandé de transformer les jambes inutilisées de l'appareil en entrées.

Considérons un programme simple qui fonctionne avec un port de microcontrôleur :

Incluez "8515def.inc" ; incluons un fichier avec les descriptions de registre.def temp =r16 rjmp RESET ; vecteur de transition lors de la réinitialisation RESET : ldi temp, 0b00000011 ; définir PC0 et PC1 comme sorties sur DDRC, temp ldi temp, 0b00000001 ; allumez la LED sur la jambe PC0 out PORTC, temp in temp, PinC ; lire les niveaux du port C ... LOOP: ; boucle du programme principal nop rjmp LOOP

Dispositif à microcontrôleur :
– objectif, conception et programmation des ports d’entrée/sortie du microcontrôleur

Bonjour, chers radioamateurs !
Bienvenue sur le site « »

Eh bien, chers radioamateurs, aujourd'hui avec cet article je finirai de charger votre (et mon) cerveau de théorie pure. De plus, ce sera plus facile et plus agréable : la théorie est compatible avec la pratique.
Eh bien, aujourd'hui, nous examinerons une question très importante et intéressante - ports E/S du microcontrôleur.

Ports E/S du microcontrôleur AVR

Ports E/S(ci-après j'écrirai en abréviation - PVV) -P conçu pour la communication entre le microcontrôleur et les appareils externes. Avec leur aide, nous transmettons des informations à d'autres appareils et recevons des informations de leur part. Selon le type, le microcontrôleur peut embarquer de un à sept PVV. Chaque port d'E/S se voit attribuer une lettre de désignation : A, B, C, D, E, F, G. Tous les ports du microcontrôleur sont équivalents, huit bits(contiennent huit lignes, ce sont aussi des conclusions, ce sont aussi des bits, ce sont aussi des bits) et bidirectionnel– peut à la fois transmettre et recevoir des informations. Les PVV du microcontrôleur desservent tous ses appareils, y compris les périphériques. Par conséquent, selon l'appareil qui fonctionnera avec le port, il peut recevoir et transmettre des informations numériques ou analogiques.

Du tout, les ports sont classés par type de signal:
ports numériques– qui fonctionnent avec des signaux numériques – des « zéros » logiques et des « uns » logiques
- ports analogiques– qui fonctionnent avec des signaux analogiques – en utilisant en douceur toute la plage de tensions d'entrée de zéro volt à la tension d'alimentation MK
- ports mixtes - ils sont utilisés dans nos microcontrôleurs, peut passer rapidement du mode « port numérique » au mode « port analogique », et inversement.

Dans la littérature technique et les schémas, les PVV sont désignés comme suit :
– “R.» – la première lettre signifiant le mot « port »
– “UN» (B, C, D, E, F, G) – la deuxième lettre indiquant un port spécifique
– “0 » (1, 2, 3, 4, 5, 6, 7) – le troisième caractère est un nombre indiquant une broche spécifique (registre, bit) du port.
Par exemple : « port A » – RA, «cinquième chiffre du port A» – PA5.
S'il y a plusieurs ports dans le MK, leurs noms ne sont pas nécessairement dans l'ordre - A, B, C. Cela peut être le cas - B, C, D. Par conséquent, il n'est pas nécessaire d'avoir peur et de chercher frénétiquement où le port A est.
De plus, bien que les ports soient à huit bits, le port n'a pas nécessairement 8 broches, il peut y en avoir moins, par exemple 3 - PA0, PA1, PA2. Dans ce cas, le port est dit incomplet, ou tronqué.
Regardons un MK spécifique - ATmega8 :

Comme vous pouvez le constater, ce MK ne possède pas de port nommé « A » (absent en classe ;). Le port PB et le port PD sont pleins et comportent chacun huit broches. Et le port C est incomplet (restreint, il n'y a pas de place dans le boîtier MK pour sa sortie), il lui manque le huitième chiffre (en réalité, à l'intérieur du boîtier MK, il est là, mais on ne peut pas travailler avec).

Pour la gestion portuaire dans leur circuit électrique, il y a deux interrupteurs que nous pouvons « actionner » par programme en utilisant registres d'E/S spéciaux. Ces commutateurs sont disponibles pour chaque broche, ce qui signifie que n'importe quelle broche du port peut être contrôlée. Par exemple, une broche d'un port peut être configurée pour l'entrée d'informations, trois chiffres du même port pour la sortie, et les autres chiffres ne peuvent pas être configurés du tout, les laissant dans « l'état Z ».
Examinons ce problème plus spécifiquement, en utilisant ce diagramme comme exemple :

Remarquez les deux commutateurs - Péché Et Sud, et la résistance Rup.
En utilisant Péché La sortie du port est commutée soit pour fonctionner comme entrée, soit pour fonctionner comme sortie. Ce commutateur est contrôlé à l'aide d'un registre d'E/S DDRx. Chaque port possède son propre registre. Chaque bit du registre contrôle le bit correspondant du port (zéro - zéro, premier - premier, etc.). Le caractère « x » dans le nom du port est remplacé par le nom du port correspondant : pour le port A – DDRA, pour le port C – DDRC. Lorsqu'un « un » est écrit sur un bit du registre DDRx, le bit correspondant du port passe à la sortie d'informations, et lorsqu'un « zéro » est écrit, à l'entrée d'informations. Regardez les images ci-dessous et vous comprendrez comment travailler avec le registre DDRx.

1. Basculez toutes les broches du port vers la sortie d'informations :


2. Commutation de toutes les broches du port pour saisir les informations :


3. Commutation d'une partie des broches du port vers l'entrée et d'une partie vers la sortie des informations :

Dans l'Assembleur « classique », la configuration des broches de port pour l'entrée et la sortie des informations ressemble à ceci (juste un exemple de la 3ème figure) :

Idi R20, 0b01100010 - avec cette commande, nous écrivons le nombre binaire 01100010 dans RON R20, avec lequel nous déterminons quelle sortie de port fonctionnera comme sortie (1) et laquelle comme information d'entrée (0). Dans ce cas, les bits du port B 1,5,6 sont configurés pour la sortie d'informations et 0,2,3,4,7 – pour l'entrée d'informations.
Sortie DDRB, R20 - avec cette commande nous transférons le contenu du RON R20 vers le registre E/S du port B.

Dans Algorithm Builder, l’entrée est légèrement différente :
#b01100010 -> DDRB
Le fait est qu'Algorithm Builder est un peu plus orienté vers les langages de haut niveau, nous écrivons donc simplement « notre désir » sur une seule ligne, mais une fois compilé (traduit en codes machine), le programme lui-même convertit cette ligne comme dans le « classique "notation.

Deuxième interrupteur - Sud. Ce commutateur a un double objectif, selon la configuration des bits du port pour la sortie ou l'entrée d'informations.
Si le bit de port est configuré pour émettre des informations, puis avec son aide, nous définissons la sortie de la décharge ou « 1 » logique ou « 0 » logique .
Si le bit de port est configuré pour saisir des informations
, puis avec son aide la soi-disant « résistance de rappel » est connectée – Rup, ou « résistance de charge interne »
. Grâce à cette résistance, il simplifie la connexion des boutons et interrupteurs externes, car Habituellement, les contacts nécessitent une résistance externe.
Comme le commutateur Sin, Sout est un registre d'E/S appelé PORTx, Où « x » – lettre de désignation du port(par exemple, pour le port D, le registre ressemblera à – PORTD).
Les familles MK Mega disposent d'un interrupteur supplémentaire - POUD, - 2ème bit du registre E/S SFIOR(c'est ce qu'on appelle le « Registre des fonctions spéciales »). Avec ce PUD le contrôle général des résistances pull-up est effectué :
- lors de l'écriture de « 1 » sur ce bit, toutes les résistances de rappel pour tous les ports sont désactivées ;
– lors de l'écriture de « 0 » sur ce bit, l'état des résistances pull-up est déterminé par le registre PORTx.
Pourquoi nous avons besoin d'une déconnexion générale des résistances, et de ce PUD en même temps, nous n'en discuterons pas aujourd'hui.
Dans le mode de fonctionnement des bits de port pour la sortie, la tâche du registre PORTx est très simple - ce que nous y écrivons sera en sortie. Si nous écrivons uniquement des « zéros », les sorties seront des zéros logiques, si nous écrivons des « uns », la sortie sera des « uns » logiques.
Par exemple:

Idi R20, 0b11111111
Sortie DDRB, R20
Nous générons un zéro logique aux bits 0 à 3 et un zéro logique aux bits 4 à 7 :
Idi R20, 0b11110000
Sortie PORTB, R20
Dans le générateur d'algorithmes :
#b11111111 -> DDRB
#b11110000 -> PORTB
J'espère que tout est clair jusqu'à présent.
Les exemples ci-dessus vous permettent de configurer l'ensemble du port à la fois et d'afficher les valeurs souhaitées sur toutes les broches du port à la fois.
Si vous souhaitez configurer un seul bit d'un port pour l'entrée ou la sortie, et également émettre un « 0 » ou un « 1 » sur un seul bit d'un port sans affecter l'état et le contenu des autres bits de ce port, les commandes suivantes exister:
SBI A,b– définir le bit de registre
RCC A,b– réinitialiser le bit du registre
Dans lequel : " UN" - Numéro d'enregistrement, " b» – chiffre de ce registre.
Ces commandes fonctionnent non seulement avec RVV DDRx et PORTx, mais également avec celles portant des numéros de 0 à 31.


Exemple:
- assembleur « classique » :
Configurez le port B pour afficher les informations :
Idi R20, 0b11111111
Sortie DDRB, R20
Nous devons basculer le 1er bit du port pour saisir les informations :
DRAS 17 $ 1(où 17 $ est le numéro RBB du port B - DDRB, 1 est le chiffre du port B)
- Générateur d'algorithmes :
#b11111111 -> DDRB
0 -> PORTB.1

Les ports d'E/S ont un autre registre : PINx , registre des broches du port (« x » est la lettre de désignation du port)
Ce registre est conçu pour lire les informations de la sortie du port, quelle que soit sa configuration - entrée ou sortie. Nous ne pouvons rien écrire dans ce registre ; il est destiné uniquement à la lecture.

L'état des broches du port en fonction de leur configuration :

* PUD n'est pas disponible dans le Tiny MK et dans le modèle ATMega161 MK

La grande majorité des broches de port ont des fonctions supplémentaires et sont utilisées par les périphériques. Dans ce cas, il peut y avoir deux situations : dans un cas, il faut régler indépendamment la configuration de la sortie, et dans l'autre cas, la sortie est configurée indépendamment lorsque le périphérique correspondant est allumé.

Lors de la réinitialisation ou de la mise sous tension du microcontrôleur, toutes les broches de tous les ports (dans des cas très, très rares) sont transférées dans un état à haute impédance - « état Z ». Ce point doit être pris en compte dans les circuits réels. Si un commutateur à transistor sert de charge de sortie, afin d'éviter que sa base (la grille du transistor à effet de champ) ne pende dans l'air, il est nécessaire d'installer des résistances externes supplémentaires d'une résistance de 10 à 100 kOhm.

Si vous n'utilisez pas les broches du port, vous ne devez pas les laisser "flotter dans les airs" - de ce fait, la consommation actuelle du MK augmente (pourquoi ce n'est pas si important, mais c'est vrai). Il est recommandé de charger toutes les sorties inutilisées du circuit avec des résistances de 10 à 100 kOhm (des résistances de rappel internes peuvent également être utilisées) ou de commuter les sorties en mode sortie numérique.

Lors de l'utilisation d'un comparateur analogique, il convient de veiller à ce que les résistances de rappel soient désactivées, sinon les lectures du niveau absolu du signal seront affectées..

Les résistances pull-up ne sont pas exactement des « résistances » - leur rôle est joué par des transistors à effet de champ, qui ont une large diffusion technologique - la valeur de la résistance pull-up peut varier entre 30 et 100 kOhm. En cas de fortes interférences et dans d'autres « cas critiques », il est recommandé (bien qu'il n'y ait pas de recommandation de ce type dans les fiches techniques) de connecter des résistances de rappel supplémentaires d'une valeur nominale de 2 à 5 kOhm. De telles résistances doivent être installées sur la broche « Reset », sur les broches d'interruption externes, si elles ne sont pas utilisées. Vous devez également installer des résistances lors du fonctionnement des broches MK sur un bus commun (I2C, ou simplement lors de la connexion de la sortie MK à la sortie d'un autre appareil avec un collecteur ouvert, lors de la connexion à des boutons à deux broches). Dans de tels cas, la résistance de la résistance intégrée est trop élevée pour filtrer les interférences électromagnétiques.

Création d'un programme clignotant

Ainsi, chers lecteurs, nous nous sommes déjà familiarisés avec la structure du microcontrôleur et avons analysé les commandes simples de l'assembleur. Vous pouvez maintenant commencer à écrire un programme simple.

Pour ce faire, nous aurons besoin de l'environnement AVRStudio (qui a été mentionné précédemment) et de l'environnement de simulation du microcontrôleur - Proteus 7. Il existe de nombreux exemples sur Internet pour installer ces programmes, nous ne nous attarderons donc pas là-dessus.

Notre premier programme sera composé de :

Connexion du fichier de directive, initialisation du MK ;

Paramètres du port d'E/S MK ;

Le cycle le plus simple de commutation de ports de l'état logique « 0 » à « 1 » ;

Routines de retard simples utilisant des registres à usage général.

Lors d'une installation standard du programme AVR Studio, les fichiers contenant les directives du microcontrôleur se trouvent à l'adresse suivante : C:\Program Files\Atmel\AVR Tools\AvrAssembler\Appnotes.

Dans notre exemple, nous utiliserons le microcontrôleur Attiny2313. Son fichier inc est nommé 2313def.

Tout d'abord, ouvrons le programme AVR Studio 4 et créons un projet.

Cliquez sur le bouton pour créer un nouveau projet.

Dans la dernière fenêtre, vous devez sélectionner le simulateur et le type de notre MK. Ensuite, cliquez sur le bouton « Terminer » et vous verrez comment une nouvelle fenêtre de notre projet s'ouvrira.

Notre projet a déjà été créé et peut être rempli avec du code de programme. Comme mentionné précédemment, la première chose à faire est de connecter le fichier de directives de ce microcontrôleur. S'il est nécessaire de simuler un projet dans l'environnement AVR Studio 4, alors il est conseillé d'indiquer également le nom de notre MK. Pour ce faire, vous devez écrire la ligne suivante « .device ATtiny2313 ».

Pour connecter le fichier inc, vous devez écrire .include « tn2313def.inc ». Ainsi, nous autoriserons le compilateur à utiliser le fichier de directives de ce MK.

Ce fichier simplifie grandement la tâche de programmation, puisque nous pouvons adhérer à certaines normes et faire référence à différentes adresses MK avec des mots plutôt qu'avec des chiffres.

Par exemple, la figure suivante montre la ligne de la valeur RAM de notre MK. Dans le programme, nous écrivons « spl », bien que nous puissions également écrire « $3d ».

Ce sera correct dans les deux cas et le compilateur ne vous donnera ni erreurs ni avertissements. Mais cela rend plus difficile la perception visuelle des commandes.

Étant donné que ces adresses ont leur propre signification dans différents microcontrôleurs, l'ouverture d'un nouveau projet ne sera pas tout à fait claire sur ce qui y est écrit. Et lorsque nous utilisons des directives, nous remplaçons toutes ces adresses par des mots que nous comprenons. Si vous le souhaitez, vous pouvez remplacer tous les noms du fichier de directives par les vôtres. Mais il y a un problème ici : vous ne pourrez pas ouvrir et compiler un projet à partir d'Internet, tout comme personne ne pourra compiler votre projet et vérifier les erreurs ou apporter des modifications. Pour ce faire, vous devrez refaire les fichiers de directives.

Ainsi, le listing 1 est un exemple de notre programme simple.

Inscription 1.

Appareil Attiny2313 ; indiquer le type d'appareil

Incluez « tn2313def.inc » ; connectez le fichier de directives ATtiny2313 MK

Temp.déf = r16 ; définir un nom pour notre registre à usage général

Organisation 0x0000 ; le programme démarre à partir de l'adresse 0

ldi temp, ramend ; charger la valeur ramend dans le registre temporaire

température de service ; configurer toutes les broches du port B pour sortir

sur DDRB, temp ;

port sbi,5; définir le « 1 » logique sur PORTB5

Alors, décomposons ligne par ligne ce que nous avons fait.

Tout d'abord, juste au cas où, nous avons indiqué le type d'appareil : appareil Attiny2313.

Nous avons inclus les directives file.include « tn2313def.inc ».

Pour faciliter l'écriture du programme, le registre R16 a reçu le nom.def temp = r16. Cette opération simplifiera grandement l’écriture du programme à l’avenir. Après tout, il est plus facile pour nous de mémoriser le nom verbal du registre que d’écrire simplement R16. Ainsi, vous pouvez attribuer un nom à n'importe quel registre commençant par R0 et se terminant par R31.

Avec la commande ser temp, nous chargeons la valeur 255 dans le registre temporaire et la déchargeons dans notre DDRB. Ainsi, nous configurons le port pour la sortie. Plus tard, lors de la simulation d'un programme dans Proteus 7, nous verrons comment ces ports prendront un état zéro logique.

Nous définissons le port de sortie PB5 sur une unité logique à l'aide de la commande sbi portb,5.

A la toute fin, il faut organiser une sorte de boucle pour que le microcontrôleur ne se fige pas.

Une fois notre programme écrit, nous pouvons compiler le projet. Pour ce faire, appuyez sur la touche F7. Si le programme est écrit sans erreurs, une boîte de dialogue apparaîtra au bas du projet avec un cercle vert et un rapport sur l'utilisation de la mémoire et les erreurs.

Ouvrez l'environnement de modélisation Proteus 7 et regardez le résultat.

Compliquons maintenant un peu la tâche et faisons passer le port de sortie du zéro logique à un. Pour ce faire, nous devons modifier légèrement notre programme, Listing 2. Tous les changements se produisent uniquement dans la boucle « principale », nous ne répéterons donc pas l'intégralité du code.

Nous regardons le résultat de la simulation dans l'environnement Proteus 7 en connectant un oscilloscope à la broche PB5.

Comme vous pouvez le constater, un signal est apparu à la sortie du port. Cependant, la fréquence de commutation est proche de la fréquence du microcontrôleur.

Pour réduire la vitesse de commutation, nous devons utiliser un simple retard. Le listing 3 montre un exemple simple d'implémentation de délai.

Inscription 3.

port sbi,5; définir le « 1 » logique sur PORTB5

rcall delay ; appelle le sous-programme de retard

port cbib,5 ; définir le « 0 » logique sur PORTB5

cl r20; effacer les registres

augmenté r20 ; ajouter 1

IPC 20 200 r ; comparer, R20 = 200 ?

brin d_1; s'il n'est pas égal, passez à l'étiquette d_1, sinon ignorez

Après avoir exécuté ce programme, la vitesse de commutation des ports a diminué à 100 ms. En définissant des valeurs de comparaison dans les registres R20 et R21, vous pouvez ajuster cet intervalle. Dans la figure suivante, nous voyons le résultat du programme.

Terminons ici. Dans la partie suivante, nous analyserons des exemples de programmes avec des boutons de connexion et écrirons une boucle ticker.

Articles précédents :

♦Unité arithmétique-logique et organisation de la mémoire – mémoire de programme, mémoire de données, mémoire non volatile

Dans cet article, nous allons écrire le premier programme et apprendre à programmer les ports E/S d'un microcontrôleur.

Notre premier programme contrôlera dans un premier temps l’une des broches du microcontrôleur. Afin de nous assurer que le programme fonctionne, nous connectons une LED à la sortie contrôlée via une résistance de limitation de courant dont l'anode est connectée à la sortie MK et la cathode au moins (fil commun).

Par défaut, la tension sur toutes les broches d'un microcontrôleur non programmé est proche de zéro, donc la LED ne s'allumera pas. Notre tâche est d'écrire un programme à l'aide duquel une tension de +5 V apparaîtra à la sortie du MK. Cette tension (plus précisément le courant) allumera la LED.

Ports E/S du microcontrôleur

Le microcontrôleur ATmega8 possède 28 broches, chacune d'elles remplit des fonctions spécifiques. La LED peut être connectée à la plupart des broches, mais pas à toutes, car au moins quelques broches sont utilisées pour l'alimentation. Pour connaître clairement le but de chaque broche du MK, vous utiliserez une fiche technique. Dans la fiche technique, nous trouvons le brochage (désignation) de toutes les broches.

Presque chaque broche peut remplir plusieurs fonctions. Les abréviations des noms de fonctions sont indiquées entre parenthèses à côté des sorties. Dans les articles suivants, nous les considérerons certainement tous. Nous nous intéressons maintenant à certains d'entre eux.

Pour faire fonctionner un microcontrôleur, comme tout autre microcircuit, une tension est nécessaire. Pour éviter les faux positifs, le MK doit être alimenté uniquement avec une tension stable de 4,5 V à 5,5 V. Cette plage de tension est strictement réglementée et est indiquée dans la fiche technique.

Le plus (« + ») de l'alimentation est connecté à la 7ème broche, désignée VCC. Moins (« - ») – à la 8ème ou 22ème étape, qui sont désignées GND (GND est l'abréviation de Ground).

Les pattes restantes permettent au microcontrôleur de communiquer avec des périphériques externes. Ils sont regroupés en groupes distincts et sont appelés ports d’entrée/sortie du microcontrôleur. En les utilisant, vous pouvez à la fois envoyer des signaux à l'entrée du MK, par exemple à partir de divers capteurs, et émettre des signaux pour contrôler d'autres appareils ou pour afficher des informations sur divers indicateurs et affichages.

Le microcontrôleur ATmega8 dispose de trois ports d'E/S : B, C et D. Les ports peuvent être pleins ou incomplets. Un port complet se compose de huit bits et possède donc le même nombre de broches du même nom. Un port partiel comporte moins de 8 bits, le nombre de broches sur un tel port est donc également inférieur à huit.

Ce MK dispose de ports complets B et D. Et le port C est incomplet et comporte sept bits. Encore une fois, notez que la numérotation des bits commence à zéro, par exemple PB0, PB1, PB2...

Ne soyez pas surpris que l'ATmega8 ne dispose pas du port A. D'autres microcontrôleurs avec plus de broches peuvent contenir à la fois le port A et le port E. Les microcontrôleurs avec moins de broches peuvent n'avoir qu'un seul port, ce qui est incomplet.

Présentation d'Atmel Studio 7

Passons maintenant à l'écriture du code du programme. Notre premier programme définira +5V sur le bit zéro du port C PC0, c'est-à-dire sur la broche 23 du microcontrôleur.

Lancez Atmel Studio.

Vous devez d’abord créer un projet. Pour cela, dans la fenêtre qui s'ouvre, cliquez sur l'onglet Nouveau projet.

Vous pouvez également créer un projet en cliquant sur l'onglet Déposer. Dans le menu déroulant, vous devez sélectionner Nouveau et en avant Projet. Ou appuyez sur la combinaison de touches Ctrl+Maj+N.

Dans la fenêtre qui apparaît, sélectionnez le langage de programmation C/C++ et cliquez sur l'onglet.


Ensuite, nous devons définir un nom et un emplacement de disque pour notre projet. Appelons notre premier projet le nom 1 dans la ligne de saisie Nom. Vous pouvez modifier l'emplacement du fichier en cliquant sur le bouton Parcourir en face de la ligne Emplacement. Si vous laissez une coche à côté Créer un répertoire pour la solution, alors un dossier avec le nom du projet sera automatiquement créé à l'emplacement sélectionné. En plus du projet, d'autres fichiers auxiliaires seront créés dans ce dossier, je recommande donc de laisser la case décochée.

Une fois le nom du projet et son emplacement sélectionnés, cliquez sur le bouton D'ACCORD. La fenêtre apparaît à nouveau. Dans celui-ci, nous devons sélectionner le type de microcontrôleur. Dans notre cas, c'est ATmega8. Cliquez sur l'onglet Famille d'appareils. Dans le menu déroulant, sélectionnez une série de microcontrôleurs ATmega.

Faites défiler pour trouver et mettre en surbrillance le microcontrôleur ATmega8 et appuyez sur le bouton D'ACCORD.

Dans la fenêtre qui s'ouvre, nous voyons qu'Atmel Studio a généré automatiquement un modèle ou un modèle de programme pour nous.

Regardons tout dans l'ordre.

Atmel Studio 7 | Premier programme

Le texte surligné en vert correspond aux commentaires. Dans ce cas, le nom du projet et l'auteur sont indiqués, ainsi que l'heure et la date de création du projet. Les commentaires ne sont pas du code de programme, ils sont donc ignorés par le compilateur. Les commentaires permettent au programmeur d'améliorer la lisibilité du code, ce qui est particulièrement utile pour rechercher des erreurs et déboguer le programme.

La couleur des commentaires et autres éléments du programme peut être modifiée dans les paramètres d'Atmel Studio.

* 1.c

* Créé : 08/07/2017 16:57:59

Les commentaires peuvent être sur une ou plusieurs lignes. Ce modèle de programme utilise des commentaires sur plusieurs lignes. Ils commencent par une ligne oblique avec un astérisque et se terminent par un astérisque et une ligne oblique.

/* - début du commentaire

*/ - fin du commentaire

Tout le texte placé entre /* et */ est complètement ignoré par le compilateur.

Un commentaire d'une ligne est indiqué par deux barres obliques et est valable sur une seule ligne. Le texte précédant les deux barres obliques est reconnu par le compilateur comme du code de programme et le texte qui le suit comme un commentaire.

// Écrivez ici un commentaire d'une ligne

En pratique, l’utilisation de commentaires est considérée comme une bonne pratique de programmation. Dans ce qui suit, nous utiliserons les deux types.

Directive du préprocesseur

L'élément suivant du programme est la ligne

#inclure

Cette ligne indique au compilateur que ce fichier doit être connecté à un autre fichier appelé io.h, situé dans le dossier avr. Le fichier inclus contient des informations sur les paramètres de base du microcontrôleur.

En fait, il serait possible de ne pas inclure le fichier io.h, mais de saisir son contenu manuellement, mais cela est très gênant.

Signe # signifie que cette commande est une directive du préprocesseur. Le fait est qu'avant de compiler un fichier, le compilateur doit effectuer un traitement préliminaire. Par conséquent, une certaine préparation du fichier pour la compilation est effectuée en ajoutant quelques instructions écrites dans le fichier io.h.

io est le nom du fichier, qui vient de l'abréviation input/output - input/output.

H – extension de fichier, son nom vient du mot en-tête – titre.

Maintenant nous sommes tous ensemble. io.h est un fichier d'en-tête qui enregistre des informations sur les paramètres d'E/S du microcontrôleur.

Fonction principale principale

Ci-dessous, nous voyons la ligne suivante :

int principal (vide)

Cette ligne déclare une fonction appelée main. L'exécution du programme commence par cela. Cette fonction est comme le point de départ de tout le programme écrit dans le fichier actuel. Le nom main est réservé dans le langage C, donc pour éviter les conflits, une autre fonction située à l'intérieur de celle-ci ne peut pas être appelée par ce nom. main est traduit main, c'est-à-dire que cette fonction est la fonction principale.

Dans la syntaxe C, l'identifiant de la fonction est entre parenthèses.

Le mot void (void) est placé entre parenthèses. Cela signifie le vide. Cela indique que la fonction principale n'accepte rien, c'est-à-dire qu'elle ne prend aucun argument. Au fur et à mesure que nous écrivons des programmes plus complexes, nous nous attarderons sur ce point plus en détail.

int est un type de données entier. Dans ce cas, la fonction fonctionne avec des entiers : à la fois positifs et négatifs. Il existe d'autres types de données, tels que la virgule flottante, les caractères, etc. Nous examinerons les types de données plus en détail si nécessaire ou dans un article séparé. Cependant, il est recommandé de toujours utiliser le type de données int pour la fonction principale, car la conception int principal (vide) défini par le standard du langage C et reconnu par tout compilateur.

La portée d'une fonction est déterminée par des accolades

. → corps de fonction

Le code du programme placé entre les parenthèses ouvrantes et fermantes fait référence au corps de la fonction.

En général, toute fonction a la structure suivante :

nom de la fonction du type de données (argument)

corps de fonction (code)

tandis que la fonction

À l’intérieur de la fonction principale se trouve la fonction while :

tandis que (1)

Alors que traduit de l’anglais par « au revoir ». Cela signifie que le programme situé dans le corps de cette fonction sera exécuté tant que la condition est vraie. Celui entre parenthèses indique que la condition est vraie, donc le code du programme écrit dans cette fonction sera répété un nombre infini de fois, c'est-à-dire le programme bouclera. Pourquoi cela est-il fait ? Le fait est que le microcontrôleur doit exécuter en permanence le programme enregistré. Le programme ne peut donc pas simplement s’arrêter. Le microcontrôleur interroge toujours les ports d'E/S ou leur envoie des signaux, même en mode veille.

Maintenant que nous avons couvert les éléments de conception de base d'un programme, examinons le modèle de base dans son intégralité. Sans commentaires, cela ressemble à ceci :

#inclure

int principal (vide)

tandis que (1)

Programmation des ports E/S du microcontrôleur ATmega8

Nous pouvons maintenant compléter le programme avec le code dont nous avons besoin. La première étape consiste à définir le bit zéro du port C PC0 sur la sortie.

Nous savons déjà que le MK peut à la fois recevoir et émettre un signal, c'est-à-dire ses broches (ports) peuvent fonctionner comme contributions Et comment sorties. Par conséquent, vous devez d'abord configurer la sortie MK sur le mode approprié. A cet effet, le microcontrôleur dispose d'un registre spécial appelé DDR-d directement dà r egiste r – registre de direction des données.

Chaque port possède son propre registre. Par exemple, le registre du port C est appelé DDRC , port B – DDRB , port D – DDRD .

Pour configurer la sortie du port sur entrée doit être inscrit dans le registre DDR zéro , et sur sortie unité .

La commande pour configurer le bit zéro du port C est la suivante

DDRC = 0b0000001 ;

Cette commande écrit un nombre binaire égal à la décimale 1 dans le registre DDRC. Le préfixe 0b identifie ce nombre comme binaire.

La forme binaire d'enregistrement est combinée avec beaucoup de succès avec le nombre de bits du port, puisque le nombre de bits correspond au nombre de broches du port et le numéro de séquence de bits correspond au nombre de bits à l'intérieur du port.

Vous pouvez également écrire un nombre hexadécimal dans le registre :

DDRC = 0x1 ;

Cependant, la forme binaire de notation est plus visuelle, c'est pourquoi nous l'utiliserons dans les premières étapes de la programmation des microcontrôleurs.

Regardons un autre exemple. Disons que nous devons configurer les bits zéro, troisième et septième du port B comme sortie et les bits restants comme entrée. Dans ce cas, le code ressemble à ceci :

DDRB = 0b10001001 ;

Registre du microcontrôleur PORT

Après avoir configuré le bit zéro du port C PC0 sur la sortie, nous devons encore faire des ajustements pour qu'une tension de +5 V apparaisse sur cette broche. Pour ce faire, nous devons définir le bit zéro dans le registre. PORT . Si le bit est réglé sur unité , alors la sortie sera +5V (plus précisément, la valeur de la tension d'alimentation du microcontrôleur, qui peut être comprise entre 4,5...5,5 V pour le microcontrôleur ATmega8). Si le bit est réglé sur zéro , - alors la sortie aura une tension dont la valeur est proche de zéro .

Chaque port possède son propre registre : port A – PORTE , port B – PORTB ,port C-P ORTC .

Et donc, pour obtenir une tension de +5 V sur la broche PC0, vous devez écrire la commande suivante :

PORT = 0b0000001 ;

Notez que chaque commande se termine par un point-virgule.

Ainsi, pour allumer la LED, nous n'avons besoin que de deux commandes :

DDRC = 0b0000001 ;

PORTС = 0b0000001 ;

Avec la première commande, nous définissons la broche PC0 comme entrée, et avec la seconde, nous réglons la tension sur +5 V.

Le code complet du programme ressemble à ceci :

#inclure

int principal (vide)

DDRC = 0b0000001 ;

Tandis que (1)

PORTC = 0b0000001 ;

Les éléments suivants doivent être notés ici : commande DDRC = 0b0000001 ; ne sera exécuté qu'une seule fois, et la commande PORTC = 0b0000001; sera exécuté tout le temps dans la boucle, puisqu'il est dans le corps de la fonction while (1). Mais même si nous déplaçons la commande en dehors de la fonction et la plaçons après DDRC = 0b0000001 ; , la LED s'allumera également en permanence dans ce cas. Cependant, en plaçant la commande PORTC = 0b0000001 ; Dans le corps de while (1) , nous indiquons clairement que la LED doit être allumée tout le temps.

Compilation du fichier

Maintenant que le code est complètement prêt, il faut le compiler. Pour ce faire, appuyez sur la touche F7 ou cliquez sur le bouton Construire et sélectionnez dans le menu déroulant Créer une solution.

S'il n'y a aucune erreur dans le code, le fichier sera compilé et un message apparaîtra en bas de l'écran indiquant que le projet a été compilé avec succès : Construction réussie.

De cette manière, les ports E/S d'un microcontrôleur de presque tous les types sont programmés.Notre prochaine étape est. Vous pouvez également vérifier le bon fonctionnement du code à l'aide d'un programme de simulation de microcontrôleur -

Les opérations au niveau du bit sont basées sur les opérations logiques que nous avons abordées précédemment. Ils jouent un rôle clé dans la programmation de l'AVR et d'autres types de microcontrôleurs. Presque aucun programme ne peut se passer de l'utilisation d'opérations au niveau du bit. Avant cela, nous les évitions délibérément afin de faciliter le processus d'apprentissage de la programmation MK.

Dans tous les articles précédents, nous avons programmé uniquement les ports d'E/S et n'avons pas utilisé de composants intégrés supplémentaires, par exemple des minuteries, des convertisseurs analogique-numérique, des interruptions et d'autres dispositifs internes sans lesquels le MK perd toute sa puissance.

Avant de passer à la maîtrise des appareils intégrés du MK, vous devez apprendre à contrôler ou vérifier les bits individuels des registres de l'AVR MK. Auparavant, nous effectuions une vérification ou fixions les chiffres de l'ensemble du registre en une seule fois. Voyons quelle est la différence, puis passons à autre chose.

Opérations au niveau du bit

Le plus souvent, lors de la programmation des microcontrôleurs AVR, nous l'avons utilisé, car il est plus visuel et bien compris par les programmeurs MK novices. Par exemple, nous devons définir uniquement le 3ème bit du port D. Pour ce faire, comme nous le savons déjà, nous pouvons utiliser le code binaire suivant :

PORTD = 0b00001000 ;

Cependant, avec cette commande, nous mettons le 3ème chiffre à un, et nous remettons tous les autres (0, 1, 2, 4, 5, 6 et 7ème) à zéro. Imaginons maintenant une situation dans laquelle les 6ème et 7ème bits sont utilisés comme entrées ADC et à ce moment-là, un signal d'un appareil est reçu sur les broches MK correspondantes, et nous utilisons la commande ci-dessus pour réinitialiser ces signaux. De ce fait, le microcontrôleur ne les voit pas et estime que les signaux ne sont pas arrivés. Par conséquent, au lieu d’une telle commande, nous devrions en utiliser une autre qui mettrait uniquement le 3ème bit à un, sans affecter les bits restants. Pour ce faire, l'opération au niveau du bit suivante est généralement utilisée :

PORTD |= (1<<3);

Nous analyserons sa syntaxe en détail ci-dessous. Et maintenant un autre exemple. Disons que nous devons vérifier l'état du 3ème chiffre du registre PIND, vérifiant ainsi l'état du bouton. Si ce bit est remis à zéro, alors on sait que le bouton est enfoncé puis le code de commande est exécuté, ce qui correspond à l'état du bouton enfoncé. Auparavant, nous aurions utilisé la notation suivante :

si (PIND == 0b00000000)

(n'importe quel code)

Cependant, avec son aide, nous vérifions non seulement le 3ème bit, mais tous les bits du registre PIND à la fois. Par conséquent, même si le bouton est enfoncé et que le bit souhaité est réinitialisé, mais qu'à ce moment-là, un signal est reçu sur une autre broche du port D, la valeur correspondante sera définie sur un et la condition entre parenthèses sera fausse. Par conséquent, le code à l’intérieur des accolades ne sera pas exécuté même lorsque le bouton est enfoncé. Par conséquent, pour vérifier l’état d’un 3ème bit individuel du registre PIND, une opération au niveau du bit doit être utilisée :

si (~PIND & (1<<3))

(n'importe quel code)

Pour travailler avec des bits individuels du microcontrôleur, le langage de programmation C dispose d'outils qui peuvent être utilisés pour modifier ou vérifier l'état d'un ou plusieurs bits individuels à la fois.

Définir un seul bit

Pour définir un seul bit, tel que le port D, une opération OU au niveau du bit est utilisée. C'est ce que nous avons utilisé au début de l'article.

PORTD = 0b00011100 ; // valeur initiale

PORTD = PORTD | (1<<0); применяем побитовую ИЛИ

PORTD |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101 ; // résultat

Cette commande définit le bit zéro et laisse le reste inchangé.

Par exemple, installons un autre 6ème bit du port D.

PORTD = 0b00011100 ; // état initial du port

PORTD |= (1<<6); //

PORTD == 0b01011100 ; // résultat

Pour écrire un à plusieurs bits distincts à la fois, par exemple les ports zéro, sixième et septième B l'entrée suivante s'applique.

PORTB = 0b00011100 ; // valeur initiale

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101 ; // résultat

Réinitialisation (mise à zéro) des bits individuels

Pour réinitialiser un seul bit, trois commandes évoquées précédemment sont utilisées à la fois : .

Réinitialisons le 3ème bit du registre PORTC et laissons le reste inchangé.

PORTC = 0b00011100 ;

PORTC &= ~(1<<3);

PORTC == 0b00010100 ;

Effectuons des actions similaires pour les 2e et 4e chiffres :

PORTC = 0b00111110 ;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010 ;

Commutation de bits

En plus du réglage et de la réinitialisation, une commande utile est également utilisée pour faire passer un seul bit à l'état opposé : un à zéro et vice versa. Cette opération logique est largement utilisée dans la construction de divers effets de lumière, comme une guirlande du Nouvel An. Regardons l'exemple de PORTA

PORTE = 0b00011111 ;

PORTE ^= (1<<2);

PORTE == 0b00011011 ;

Changeons l'état des bits zéro, deuxième et sixième :

PORTE = 0b00011111 ;

PORTE ^= (1<<0) | (1<<2) | (1<<6);

PORTE == 0b01011010 ;

Vérification de l'état d'un bit individuel. Permettez-moi de vous rappeler que la vérification (et non l'écriture) d'un port d'E/S s'effectue en lisant les données du registre PIN.

Le plus souvent, les tests sont effectués par l'une des deux instructions de boucle suivantes : if et while. Nous connaissons déjà ces opérateurs plus tôt.

Vérification du bit pour la présence d'un zéro logique (reset) avec si

si (0==(PIND & (1<<3)))

Si le troisième bit du port D est effacé, alors Code1 est exécuté. Sinon, Code2 est exécuté.

Des actions similaires sont effectuées avec cette forme d'enregistrement :

si (~PIND & (1<<3))

Vérification du bit pour la présence d'une unité logique (réglage) avec si

si (0 != (PIND & (1<<3)))

si (PIND & (1<<3))

Les deux boucles ci-dessus fonctionnent de manière similaire, mais peuvent, en raison de la flexibilité du langage de programmation C, avoir une forme de notation différente. L'opérateur != signifie différent. Si le troisième bit du port d'E/S PD est défini (un), alors Code1 est exécuté sinon, Code2 est exécuté ;

En attente de réinitialisation du bit alors que

tandis que (PIND & (1<<5))

Code1 sera exécuté tant que le 5ème bit du registre PIND est activé. Lorsque vous le réinitialisez, Code2 commencera à s'exécuter.

En attente que le bit soit défini avec alors que

Ici, la syntaxe C vous permet d'écrire du code de deux manières les plus courantes. En pratique, les deux types d'enregistrement sont utilisés.

Gestion des ports dans AVR GCC. Registres DDRx et PORTx.
Représentation des nombres. Opérations au niveau du bit.
Fonction de retard. Transition inconditionnelle dans le programme.

Les ports du microcontrôleur sont des périphériques d'entrée/sortie qui permettent au microcontrôleur d'envoyer ou de recevoir des données. Le port standard du microcontrôleur AVR dispose de huit bits de données qui peuvent être envoyés ou reçus en parallèle. Chaque chiffre (ou bit) correspond à un pin (pin) du microcontrôleur. Les broches du microcontrôleur sont également appelées broches. Pour désigner les ports, les lettres latines A, B, C, etc. sont utilisées. Le nombre de ports d'E/S varie en fonction du modèle de microcontrôleur.

N'importe quel port du microcontrôleur peut être configuré comme entrée ou sortie. Pour ce faire, vous devez écrire dans le registre correspondant au port DDRx valeur requise. De plus, n'importe quelle broche du port peut être configurée séparément comme entrée ou sortie. Quoi qu'il en soit, que vous souhaitiez configurer un port entier ou une seule broche, vous devrez travailler avec des registres DDRx.

DDRx - registre de direction de transfert de données. Ce registre détermine si une broche de port particulière est une entrée ou une sortie. Si un certain bit du registre DDRx contient un bit logique, la broche du port correspondante est configurée comme sortie, sinon comme entrée. La lettre x dans ce cas doit indiquer le nom du port avec lequel vous travaillez. Ainsi, pour le port A ce sera le registre DDRA, pour le port B ce sera le registre DDRB, etc.

En utilisant AVR CCG, vous pouvez écrire telle ou telle valeur dans le registre requis de l'une des manières suivantes.

Pour tout le port à la fois.

DDRD = 0xff ;

Toutes les broches du port D seront configurées comme sorties.

0xff est la représentation hexadécimale du nombre ff, où 0x est le préfixe utilisé pour écrire les nombres hexadécimaux. En notation décimale, ce sera le nombre 255 et en binaire, il ressemblera à 11111111. Autrement dit, tous les bits du registre DDRD seront écrits dans les bits logiques.

DANS AVR CCG le préfixe 0b est utilisé pour représenter les nombres binaires. Ainsi, le numéro 11111111 doit être représenté dans le programme par 0b11111111. Nous pouvons écrire la commande précédente sous une forme plus lisible.

DDRD = 0b11111111 ;

Bien que cette notation semble plus visuelle, lors de la configuration des ports, il est d'usage d'utiliser une représentation hexadécimale des nombres.

Pour configurer toutes les broches du port D comme entrées, tous les bits du registre DDRD doivent être définis sur des zéros logiques.

DDRD = 0x00 ;

D'autres numéros peuvent être écrits dans le registre DDRD. Par exemple:

DDRD = 0xb3 ;

0xb3- représentation hexadécimale du nombre 179. Sous forme binaire, cela ressemblera à 10110011. C'est-à-dire que certaines des broches du port D seront configurées comme sorties et d'autres comme entrées.

PD0 - 1 (sortie)
PD1 - 1 (sortie)
PD2 - 0 (entrée)
PD3-0 (entrée)
PD4-1 (sortie)
PD5-1 (sortie)
PD6 - 0 (entrée)
PD7-1 (sortie)

Pour configurer séparément la broche PD2 comme entrée, nous devons écrire 0 dans le bit correspondant du registre DDRD. Pour ce faire, utilisez la construction suivante.

DDRD &= ~(1
Dans ce cas, le résultat du décalage d'une position de deux positions vers la gauche est inversé à l'aide de l'opération d'inversion au niveau du bit, notée " ~ ".

Avec l'inversion, nous obtenons des uns au lieu de zéros et des zéros au lieu de uns. Cette opération logique est autrement appelée l'opération PAS(Nom anglais PAS).

Ainsi, en inversant 00000100 au niveau du bit, nous obtenons 11111011. (Pour plus d'informations sur l'utilisation des nombres dans un microcontrôleur, voir l'encadré ci-dessous.)

Le nombre résultant est multiplié par l'opération de multiplication logique au niveau du bit et par le nombre stocké dans le registre DDRD, et le résultat est écrit dans le registre DDRD.

Pour une multiplication logique 0*0=0, 0*1=0, 1*1=1 . L'opération de multiplication logique est autrement appelée l'opération ET(Nom anglais ET).

C'est-à-dire que celui que nous avons décalé de deux positions vers la gauche se transforme en zéro lorsqu'il est inversé et est multiplié par le bit correspondant stocké dans le registre DDRD. En multipliant par zéro, nous obtenons zéro. Ainsi, le bit PD2 devient nul.

Une fois le sens des données d'un port configuré, vous pouvez attribuer une valeur au port, qui sera stockée dans le registre correspondant PORTx.
PORTx est un registre de port, où x désigne le nom du port.

Si une broche est configurée comme sortie, un un dans le bit correspondant du registre PORTx génère un signal de niveau haut au niveau de la broche et un zéro génère un signal de niveau bas.

Si la broche est configurée comme entrée, alors un un dans le bit correspondant du registre PORTx connecte une résistance de rappel interne à la broche, ce qui garantit un niveau élevé à l'entrée en l'absence de signal externe.

Vous pouvez définir "1" sur toutes les broches du port D comme suit.

PORTD = 0xff;

Et vous pouvez définir « 0 » sur toutes les broches du port D comme ceci.

PORTD = 0x00 ;

Chaque bit des registres PORTx est également accessible individuellement de la même manière qu'avec les registres DDRx.

Par exemple, la commande

PORTD |= 1
définira "1" (signal de haut niveau) sur la broche PD3.

PORTD &= ~(1
définira "0" (signal de niveau bas) sur la broche PD4.

DANS AVR CCG le décalage peut également être effectué à l'aide de la fonction _BV(), qui effectue un décalage au niveau du bit et insère le résultat dans le code compilé.

Si vous utilisez la fonction _BV(), les deux commandes précédentes ressembleront à ceci.

PORTD |= _BV(PD3); // définit "1" sur la ligne 3 du port D

PORTD &= ~_BV(PD4); // définit "0" sur la ligne 4 du port D

Selon la méthode de connexion, la LED s'allumera soit à partir d'un signal de niveau haut fourni à la broche PD1 du microcontrôleur, comme dans le premier cas, soit à partir d'un signal de niveau bas dans le cas de la connexion illustrée sur la deuxième figure.

/************************************************ * *********************** EXEMPLE D'ALLUMAGE D'UNE LED AVEC UN SIGNAL DE HAUT NIVEAU Exemple de connexion dans la figure 1 *********** *** **************************************** ******* **/#inclure $WinAVR = ($_GET["avr"]); si($WinAVR) include($WinAVR);?> int principal( vide) { // démarrage du programme principal DDRD = 0xff ; PORTD |= _BV(PD1); // définit "1" (niveau haut) sur la broche PD1 }

Essayons maintenant de faire clignoter une LED connectée comme indiqué sur la figure de gauche. Pour ce faire, nous utilisons la fonction de retard _delay_ms().

La fonction _delay_ms() génère un délai en fonction de l'argument qui lui est passé, exprimé en millisecondes (il y a 1000 millisecondes dans une seconde). Le délai maximum peut atteindre 262,14 millisecondes. Si l'utilisateur transmet une valeur supérieure à 262,14 à la fonction, la résolution sera automatiquement réduite à 1/10 de milliseconde, entraînant des retards allant jusqu'à 6,5535 secondes. (Vous pouvez en savoir plus sur la formation de délais plus longs dans l'article.)

La fonction _delay_ms() est contenue dans le fichier delay.h, nous devrons donc connecter ce fichier au programme. De plus, pour que cette fonction fonctionne correctement, vous devez préciser la fréquence à laquelle fonctionne le microcontrôleur, en hertz.

/*************************************** EXEMPLE DE CLIGNOTANT DE LED Exemple de raccordement en Figure 1 ** ** **********************************/#définir F_CPU 1000000UL #inclure #inclure int principal( vide) { // démarrage du programme principal DDRD = 0xff ; // configure toutes les broches du port D comme sorties PORTD |= _BV(PD1); _delay_ms(500); // attends 0,5 seconde. PORTD |= _BV(PD1); // définit "1" (niveau haut) sur la broche PD1, // allume la LED _delay_ms(500); // attends 0,5 seconde. PORTD &= ~_BV(PD1); // définit "0" (niveau bas) sur la broche PD1, // éteint la LED } // parenthèse fermante du programme principal

La série de flashs LED sera très courte. Pour rendre le clignotement continu, vous pouvez créer une boucle infinie en utilisant l'opérateur de saut inconditionnel "goto". L'instruction goto saute au point du programme indiqué par l'étiquette. Le nom de l'étiquette ne doit pas contenir d'espaces. Le nom de l'étiquette est suivi de deux points. Il ne doit y avoir aucun espace entre le nom de l'étiquette et les deux points.
/************************************************ * ***** EXEMPLE DE LED CLIGNOTANT SANS FIN Exemple de connexion dans la figure 1 ********************************** * *******************************/#définir F_CPU 1000000UL // indique la fréquence en hertz#inclure #inclure int principal( vide) { // démarrage du programme principal DDRD = 0xff ; // configure toutes les broches du port D comme sorties commencer: // étiquette pour la commande goto start PORTD |= _BV(PD1); // définit "1" (niveau haut) sur la broche PD1, // allume la LED _delay_ms(250); // attends 0,25 seconde. PORTD &= ~_BV(PD1); // définit "0" (niveau bas) sur la broche PD1, // éteint la LED _delay_ms(250); // attends 0,25 seconde. aller à commencer; // va à l'étiquette de démarrage } // parenthèse fermante du programme principal