=====Comme dans n’importe quel système à microprocesseur, il est nécessaire de préparer un programme qui permettra au PIC d’effectuer son travail. Un programme est constitué d’une liste d’instructions en séquence, chacune d’entre elles identifiant très précisément les fonctions de base que le PIC est capable d’effectuer. Chaque instruction est représentée par un code d’opération (OPCODE en anglais) de 14 bits et est mémorisée dans une des mémoires flash qui contient 1024 emplacements. Chaque OPCODE est représenté par un mnémonique plus facile à retenir par l’utilisateur.
Exemple : l’OPCODE du mnémonique RETURN est : 00 0000 0000 1000
Il est plus facile de représenter un OPCODE dans sa forme hexadécimale car celle-ci est plus adéquate à la manipulation des données.
La combinaison des mnémoniques et des nombres en hexadécimal est le langage assembleur.
Un programme en langage assembleur peut être écrit sur un PC en utilisant un éditeur de texte capable de générer des fichiers de type ASCII (American Standard Code for Information and Interchange). Ce fichier texte est appelé fichier source assembleur. Une fois l’écriture du programme source assembleur terminée, le fichier doit être sauvegardé avec l’extension (.ASM).
La syntaxe utilisée ne doit pas contenir d’accent, d’espace inutile, de cédille, de parenthèse etc.
À la suite d’une ligne d’instructions, le programmeur peut écrire un commentaire à la condition qu’il soit précédé d’un point virgule (;). Notez que tout texte après un point virgule sera ignoré par le programme compilateur. Les commentaires servent à aider un utilisateur à comprendre votre démarche, ils ne sont pas obligatoires mais un bon programmeur les fera toujours.
8.1. Organisation d’un fichier (.ASM) : on prendra comme exemple le laboratoire #1
;=========================#1============================
; Programme pour le pic 16F84-04. Ce programme fait clignoter une led placée sur RB1
; (T=1 sec.)
; Titre : Led clignotante
; Auteur : Dany Amer
;=========================ENTÊTE==============================
list p=16f84, w=2 ;Identification du microcontrôleur, niveau d’erreur
__config 0x3ff1 ;Pas de protection de lecture de la mémoire, oscillateur à cristal
;Watchdog à Off, Power up timer à "On"
;============================================================
;Étiquette==Mnémonique=Opérande==========Commentaire===================
; Équivalence des registres
; *********************
portb equ 0x06 ;Adresse du registre portb pour utilisation
trisb equ 0x86 ;Adresse du registre trisb pour utilisation
status equ 0x03 ;Adresse du registre status pour utilisation
; Réservation mémoire
; *****************
compteur0 equ 0x0d ;Identifie un registre à l'adresse 0x0d au nom de compteur0
compteur1 equ 0x0e ;Identifie un registre à l'adresse 0x0e au nom de compteur1
compteur2 equ 0x0f ;Identifie un registre à l'adresse 0x0f au nom de compteur2
;============================================================
; Initialisation du programme
; **********************
org 0x00 ;Origine de départ (adresse sélectionnée après un reset)
goto debut ;L'adresse 04 est réservée aux interruptions, il faut
;donc sauter par dessus
debut
org 0x05 ;Origine du programme
bsf status,05 ;Sélection de bank1 pour l'accès au trisb
clrf trisb ;Déclaration du portb en sortie
bcf status,05 ;Sélection de bank0 pour accès au portb
clrf portb ;Place toutes les sorties du portb au niveau logique 0
; Programme principal
; *****************
boucle
movlw 0x02 ;Charge dans l'accumulateur la valeur 02
movwf portb ;Place le contenu de w dans le registre portb pour allumer
;la led placée sur la sortie RB1 du portb
call pause ;Appelle la routine étiquette pause
movlw 0x00 ;Charge dans accumulateur la valeur 00
movwf portb ;Place le contenu de w dans le registre portb pour éteindre
;la led placée sur la sortie RB1 du portb
call pause ;Appelle la routine étiquette pause
goto boucle ;Va à l'étiquette nommée boucle
;============================================================
; Temporisation de 0.5 seconde
; ************************
pause
movlw 0xff ;Charge dans l'accumulateur la valeur ff (255)
movwf compteur2 ;Transfert w dans le registre "compteur2"
load1
movlw 0x19 ;Charge l'accumulateur à 19 (25)
movwf compteur1 ;Transfert w dans le registre "compteur1"
load0
movlw 0x1a ;Charge l'accumulateur à 1a (26)
movwf compteur0 ;Transfert w dans le registre "compteur"
dec
decfsz compteur0,1 ;Décrémente le registre "compteur0", saute l'instruction
;suivante si le résultat est zéro
goto dec ;Saute inconditionnellement à "dec"
;Un cycle d’instruction utilise quatre périodes d’horloge
;Décrémente = 1cycle, goto = 2cycles soit au total 3 cycles
;ou 3 s, t = 3 micro-secondes x contenu du registre
;"compteur0" = 3 x 26 = 0.078ms
decfsz compteur1,1 ;Décrémente le registre "compteur1", saute l'instruction
;suivante si le résultat est zéro
goto load0 ;Va à "delai1" t = 3 x 26 x 25 = 1.95 ms
decfsz compteur2,1 ;Décrémente le registre "compteur2", saute l'instruction
;suivante si le résultat est zéro
goto load1 ;Va à "delai2" t = 3 x 26 x 25 x 255 = 0.49725 seconde
return ;Retour à la ligne suivant l'appel de l'étiquette "pause"
end
;============================================================
L’identification8.2.
Si vous regardez attentivement, vous remarquerez que les trois premières lignes sont précédées du symbole (;). Tout ce qui suit est une zone de commentaires, vous pouvez y inscrire ce que vous voulez. On utilisera cette zone comme zone d’identification dans laquelle on inscrira : le titre du programme, une petite description de ce qu’il fait, la date d’édition, le nom de l’auteur.
Les doubles tirets qui encadrent ce paragraphe ne servent que pour l’esthétique, ils sont précédés du point virgule et ne sont donc pas pris en considération par le programme.
8.3.
Les directivesLes directives ne font pas partie du programme, elles ne sont pas traduites en OPCODE, elles servent à indiquer à l’assembleur de quelle manière il doit travailler. Ce sont donc des commandes destinées à l’assembleur lui-même.
Par contre, les instructions seront traduites en OPCODE et chargées dans le PIC. Il faut donc faire la distinction.
§ La directive "list"
La directive "List" en bas de l’entête est destinée au compilateur pour lui indiquer quel type de processeur est utilisé (ici : Pic16F84).
§ Les directives "__config"
La ligne "__config" est aussi destinée au compilateur pour établir les bits de configuration de la case mémoire 0x2007 qui comporte 14 bits.
Les bits 0 et 1 déterminent le type d’oscillateur utilisé ;
Il
y a quatre (4) modes d’horloge
possibles :
Ø
RC
(résistance, capacité), 26.2Khz à 4610Khz ;
Ø
LP
(faible consommation) quartz ou oscillateur externe. 32 Khz, 200Khz ;
Ø
XT
(quartz ou résonateur céramique ou oscillateur externe. 100
Khz, 455Khz, 2 Mhz, 4Mhz).
Ø HS (haute vitesse : 8Mhz, 10Mhz) quartz ou résonateur céramique ou oscillateur externe.
Le bit 2 autorise ou non le fonctionnement du watchdog timer ;
Ø
Principe
C’est
un système de protection contre un blocage de programme.
Par
exemple, si le programme attend le résultat d’un système extérieur
(conversion analogique numérique par exemple) et qu’il n’y a pas de réponse,
il peut rester bloqué. Pour en sortir, on utilise un chien de garde. Il
s’agit d’un compteur qui, lorsqu’il arrive en fin de comptage, permet
de redémarrer le programme. Il est lancé au début du programme. En
fonctionnement normal, il est remis à zéro régulièrement dans une
branche du programme qui s’exécute régulièrement. Si le programme est
bloqué, il ne passe plus dans la branche de remise à zéro et le comptage
va jusqu’au bout et déclenche le chien de garde qui relance le programme.
Ø
Mise
en service
Elle se décide
lors de la programmation physique du PIC. Elle ne peut pas être suspendue
pendant l’exécution d’un programme. Elle est définitive jusqu’à une
nouvelle programmation de la puce.
La
directive de programmation __config permet de valider (option_WDT_ON) ou non
(option_WDT_OFF) le chien de garde. La mise en service peut aussi être réalisée
directement par le programmateur. L’inconvénient de cette seconde
solution est que le code du programme ne contient pas l’information; la
mise en service du chien de garde peut être oubliée lors du téléchargement
et générer un fonctionnement incorrect du programme en cas de blocage.
Ø
Gestion
Une
fois le chien de garde mis en service, il faut remettre le comptage à zéro
régulièrement. Cette opération est réalisée par l’instruction CLRWDT.
Tant que le programme se déroule normalement, cette instruction est exécutée
régulièrement et le chien de garde ne s’active pas. Si un blocage apparaît,
la remise à zéro n’a pas lieu et le chien de garde est activé. Le PIC
redémarre alors à l’adresse 0000h et le bit TO (Time out bit) (status,
4) est mis à 0. Le test de ce bit au début du programme permet de savoir
si le système vient d’être mis sous tension (TO=1) ou si le chien de
garde vient de s’activer (TO=0)
Ø
Choix
de la durée
Le chien de garde possède sa propre horloge. Sa période de base est de 18 ms. Le pré-diviseur de fréquence utilisé par le compteur est partagé avec le chien de garde. Si le bit PSA (OPTION_REG, 3) est à 1, le pré-diviseur est assigné au chien de garde. Huit (8) valeurs de 1 à 128 sont disponibles, ce qui permet d’aller jusqu’à 128 x 18 ms = 2.3 s avant le déclenchement du chien de garde.
Le bit 3 autorise ou non le fonctionnement du power up timer (délai de 72 ms à l'allumage qui prolonge le Power On Reset) ;
Les bits 4 à 13 permettent d'interdire la lecture de la mémoire programme.
Code Protect
Power Up Timer
Watchdog
Oscillateur
bit 4
bit 3
bit 2
bit 1, bit 0
0 => Oui
0 => Oui
0 => Non
00=>LP, 01=>XT
1 => Non
1 => Non
1 => Oui
10=>HS, 11=>RC
Les 5 bits sont à 1 par défaut soit : pas de Code Protect, pas de Power UP Timer, Watchdog actif, oscillateur RC
Dans le cas du Travail #1, on utilise un oscillateur à cristal, le "watchdog" est à "Off", Le "power up timer" est à "On" et la protection en lecture est inactive. Ce qui donne pour la directive __config 3FF1
Bit13
Bit12
Bit11
Bit10
Bit9
Bit 8
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
1
1
1
1
1
1
1
1
1
1
0
0
0
1
§
La directive « #define » (définition)Une définition « #define » permet de remplacer un texte complexe par un nom particulier qu’on veut lui donner.
Dans le programme, on peut par exemple donner le nom "stat" au bit 5 du registre status (status,05 = stat). Il faut alors le définir dans le programme en utilisant la directive #define.
#define stat status,05
Pour mettre à 1 le bit 5 du registre status, on écrira alors :
bsf stat au lieu de bsf status,05
§
La directive « #include »Afin d’éviter l’écriture d’une multitude de lignes d’assignation au début de chaque programme, on peut les regrouper dans un fichier et les appeler par une seule commande :
#include "P16F84.INC" ou #include <P16F84.INC>
§
La directive « org »La directive "org" précise à quelle adresse sera placée l’instruction qui suit. Après un reset ou une mise sous tension, le PIC démarre toujours à l’adresse 0x00, c’est donc à cette adresse que doit débuter votre programme.
L’adresse 0x04 est utilisée par les interruptions. Nous devons donc sauter par-dessus vers le début de notre programme principal.
Exemple :
org 0x00
goto debut
debut org 0x05
La première ligne est une directive qui indique que la ligne suivante sera placée à l’adresse 0x00.
La deuxième ligne est une instruction qui indique au PIC que le programme doit sauter à l’adresse 0x05 représentée par l’étiquette "debut" (voir étiquette plus loin).
§
La directive « end »Cette directive indique l’endroit où doit cesser l’assemblage de votre programme. Elle est obligatoire sinon une erreur vous signalera que la fin de fichier a été atteinte sans rencontrer la directive "end" (End Of File). Les instructions après la directive "end" sont tout simplement ignorées.
8.4. Les assignations ou directive « equ »
Les lignes commençant à "portb" et finissant à "compteur2" sont des assignations. Elles signalent à l’assembleur les valeurs (adresses) de toutes les constantes que nous allons utiliser. Il est en effet plus facile de retenir port B que de manipuler la valeur 0x06.
Une assignation est une simple substitution, elle associe un nombre à une étiquette. Au moment de l’assemblage, chaque assignation rencontrée sera remplacée par sa valeur.
Si vous remplacez la valeur d’une assignation, le changement sera effectif pour tout le programme. Vous ne risquez donc pas d’oublier des valeurs en chemin.
8.5. Les macros
Une macro remplace un morceau de code que nous utilisons souvent dans le programme. Elle fonctionne comme un simple traitement de texte.
Exemple :
Repete macro
movlw 0x00
movwf portb
call pause
endm
La macro se compose d’un nom écrit en première colonne suivi de la directive "macro", de une ou plusieurs instructions et de fin de macro "endm" (end of macro).
Chaque fois que le mot "repete" sera rencontré, il sera remplacé au moment de l’assemblage par les lignes d’instructions de la macro soit :
movlw 0x00
movwf portb
Call pause
8.6. Le programme principal
Dans la mémoire programme, les instructions sont codées en suites de 0 et de 1, nous, nous préférons écrire des choses comme goto ou clrw, l'assembleur se charge de la traduction. Chaque ligne peut contenir jusqu’à 4 types d’informations appelées champs.
Les quatre champs (ou colonnes) sont : l’étiquette, le mnémonique (OPCODE), l’opérande et le commentaire.
La syntaxe doit être la suivante pour l’assembleur MPLAB, que nous utiliserons dans les laboratoires. Nous avons dans l’ordre :
- Étiquette (facultative)
- Espace(s) ou tabulation(s)
- Mnémonique (en majuscules ou minuscules)
- Tabulation ou Espace(s)
- Opérande ou la valeur
- Virgule éventuelle de séparation
- Bit de destination W ou F ou éventuellement numéro du bit de 0 à 7 si nécessaire
- Espace(s) ou tabulation(s)
- Point-virgule (facultatif si pas de commentaire)
- Commentaire. (facultatif)
Notez que le mnémonique ne peut pas se trouver en première colonne, et que tout ce qui suit le point-virgule est ignoré de l’assembleur (donc c’est la zone commentaire).
La première colonne est réservée pour les étiquettes (repères)
Vous disposez également de la possibilité d’insérer un ou plusieurs espace(s) ou tabulation(s) de chaque côté de la virgule.
L’étiquette permet de donner un nom à un nombre (adresse, variable) ou à une ligne du programme. Elle commence par un caractère alphanumérique (ou un souligné), dans ce cas, le souligné ne doit pas être suivi par un chiffre. Les caractères utilisables sont lettres, chiffres, souligné et point d’interrogation. Leur longueur maximale est de 32 caractères. Par défaut il y a une différence entre une majuscule et une minuscule.
L’étiquette en début de ligne de programme commence en colonne 1; elle est suivie par un espace, une tabulation, par deux points ( : ) ou par un retour de chariot si elle est seule sur la ligne. Derrière un call ou un goto, elle est en colonne #3.
L’étiquette, représentant un nombre, est placée conformément à la directive ou à l'instruction qui l'utilise.
C’est l'instruction elle-même qui doit commencer en colonne 2. S’il y a une étiquette en colonne 1, il doit y avoir un ou plusieurs espace, deux points ( : ) ou une tabulation avant le mnémonique.
L’opérande vient après le mnémonique, il complète l’instruction. Il doit être séparé de l'instruction par un ou plusieurs espace, par deux points ( : ) ou par une tabulation. S’il y a plusieurs opérandes, ils sont séparés par des virgules.
Tout texte commençant par un point virgule est un commentaire. Il n’est pas pris en compte par la compilation jusqu’à la fin de la ligne sauf si le point virgule fait partie d’une chaîne de caractères.
Remarque : Une ligne contient 255 caractères au maximum.
§
Principe
Lorsque
le PIC n’a rien à faire (par exemple lors de l’attente d’une mesure extérieure),
ce mode est utilisé pour limiter sa consommation : le PIC est mis en
sommeil (le programme s’arrête) jusqu’à son réveil (le programme repart).
Ce mode est principalement utilisé pour les systèmes embarqués fonctionnant
sur pile.
§
Gestion
Mise
en sommeil : La mise en sommeil est réalisée grâce à
l’instruction SLEEP. La séquence suivante est exécutée :
-
Le
chien de garde est remis à 0 (équivalent à CLRWDT)
-
Le
bit TO (Time Out bit) (status, 4) est mis à 1
-
Le
bit PD (Power Down bit) (status, 3) est mis à 0
-
L’oscillateur
est arrêté ; le PIC n’exécute plus d’instruction
Réveil :
ce mode n’est intéressant que si l’on peut en sortir pour relancer le
programme. Trois événements permettent de sortir le PIC du sommeil.
-
Application
d’un niveau 0 sur MCLR (broche 4). Le pic effectue alors un reset et relance
le programme à partir de l’adresse 0000h. Les bits NOT_TO (status, 4) et
NOT_PD (status, 3) permettent à l’utilisateur de savoir quel événement a
lancé le programme (mise sous tension, reset, chien de garde)
-
Activation
du chien de garde. Le programme reprend à l’instruction suivant le SLEEP
-
Apparition
d’une interruption (RB0/INT, RB4 à RB7 ou EEPROM). Il faut pour cela que les
bits de validation spécifique des interruptions concernées soient positionnés.
Si le bit de validation générale des interruptions (GIE) est à 0 (pas de
validation des interruptions), le programme reprend après l’instruction SLEEP
comme pour le chien de garde. Si le bit de validation générale des
interruptions (GIE) est à 1 (validation des interruptions), l’instruction
suivant le SLEEP est exécutée et la fonction d’interruption liée à l’événement
qui a réveillé le PIC est exécutée.
Il y a
plusieurs possibilités de Reset :
§
Reset
à l'allumage (POR)
§
Reset
externe par mise à la masse de l'entrée MCLR
§
Reset
après Watchdog
Le
Power-up Timer (PWT) produit un délai
de 72 ms à l'allumage.
L'oscillateur
Start-up Timer (OST) maintient le
16F84 en position reset jusqu'à ce que l'oscillateur à quartz se soit stabilisé.
10.
Registre OPTION_REG (0x81)
C’est
un registre de bits où chaque bit a un rôle particulier. Il se trouve à
l’adresse 0x81, dans la banque 1. Le contenu de ce registre est :
BIT
7:
NOT_RBPU (Pull-up Enable Bit)
Quand
ce bit est mis à 0 (actif au niveau bas), une résistance de rappel au +5 volts
est placée sur chaque broche du port B. Cette option valide les résistances
sur toutes les broches du port B en même temps. Cette fonction n’existe pas
pour le port A.
Quand
ce bit est à 1, les résistances sont désactivées.
BIT
6:
INTEDG (Interrupt Edge Select Bit)
Ce
bit donne le sens de déclenchement de l’interruption sur la broche RB0/INT
INTEDG
= 1, on a interruption si le niveau sur RB0/INT passe de 0 à 1
INTEDG
= 0, l’interruption s’effectuera lors de la transition de 1 vers 0 sur la
broche RB0/INT.
BIT
5:
T0CS (TMR0 Clock Source Select Bit)
Ce
bit détermine le fonctionnement du timer 0.
T0CS
= 1, compte les impulsions reçues sur la broche RA4
T0CS
= 0, incrémenté en fonction de l’horloge interne
BIT
4 :
T0SE (TMR0 Source Edge Select Bit)
Ce
bit donne le sens de la transition qui détermine le comptage du TMR0
T0SE
= 1, l’incrémentation du TMR0 se fait lors de la transition de + 5 volts à 0
sur la broche RA4/T0CKI.
T0SE
= 0, l’incrémentation du TMR0 se fait lors de la transition de 0 à + 5 volts
sur la broche RA4/T0CKI
Si
le BIT 5 est à 0, Le BIT 4 n’est pas utilisé et sera maintenu à 0
BIT
3 :
PSA (PreScaler
Assignment
Bit)
PSA
= 1, effectue une
prédivision
au niveau du timer
du watchdog
PSA
= 0, effectue une prédivision du timer 0 (TMR0)
BIT
2-0 :
PS2-PS1-PS0 (Prescaler Rate Select Bits)
Ces
trois bits déterminent la valeur de prédivision pour le registre déterminé
au BIT3
Bit
Value |
TMR0
Rate |
WDT
Rate |
000 |
1:2 |
1:1 |
001 |
1:4 |
1:2 |
010 |
1:8 |
1:4 |
011 |
1:16 |
1:8 |
100 |
1:32 |
1:16 |
101 |
1:64 |
1:32 |
110 |
1:128 |
1:64 |
111 |
1:256 |
1:128 |
Si
on ne désire pas utiliser de prédivision, il faut mettre le BIT 3 à 1 (Prédivision
sur watchdog) et les BITS 2-0 à 0 ce qui correspond à une prédivision (1:1)
soit pas de prédivision.
Il
y a quatre (4) sources d'interruption :
a)
Externe par la broche RB0/INT
b)
Par dépassement du registre timer (TMR0)
c)
Par changement d’état des broches 4 à 7 du portb
d)
À la fin de l’écriture des données dans l’EEPROM.
Imaginez une conversation normale :
§
Chaque interlocuteur prend la parole
quand vient son tour de parler.
§
Survient un événement extérieur dont
le traitement est urgent. Par exemple un bloc de béton tombe du deuxième étage
de l’immeuble au pied duquel vous discutez.
§
Votre interlocuteur ne va pas attendre
la fin de votre conversation pour vous signaler le danger. Il va donc vous
interrompre durant le cours normal de votre discussion afin d’écarter le
danger et traiter cet événement extérieur.
§
Les interlocuteurs reprendront la
conversation sitôt le danger écarté.
Pour le PIC, le principe est le même :
§
Le programme se déroule normalement
§
Survient un événement spécifique. Le
programme principal est interrompu, l’événement est traité avant de
retourner à l’endroit de l’interruption.
L’interruption est une rupture de séquence asynchrone.
Pour la déclencher, il faut que deux conditions principales soient remplies :
§
Elle doit figurer dans la liste des événements
du processeur
§
L’utilisateur doit l’avoir autorisée.
11.1.
Principe
Lorsqu’une
interruption est provoquée :
§
Le programme termine l’instruction en
cours
§
Il arrête la procédure qu’il était
en train d’exécuter
§
Il passe à l’adresse 0x04
§
À cette adresse doit se trouver
l’instruction qui envoie sur la routine de traitement de l’interruption
§
À la fin de cette routine de
traitement, il reprend la procédure initiale là où elle était.
11.2.
Registre
INTCON (0x0B et 0x8B) est le registre qui gère les interruptions. Son écriture
permet de les autoriser ou non et sa lecture de déterminer le type
d’interruption qui s’est produite.
Bit
7 : GIE (Global Interrupt Enable)
Autorise ou non les interruptions,
quelles qu’elles soient
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
GIE = 0 interdit toutes les
interruptions
GIE = 1 autorise toutes les
interruptions non masquées
Il passe seul à 0 pendant le traitement d’une
interruption, il est remis à 1 par l’instruction RETFIE (Return From
Interrupt)
BIT
6: EEIE (EEprom Interrupt Enable)
Fonctionne en lecture/écriture
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
EEIE = 0 interdit l’interruption en
fin de programmation EEPROM
EEIE = 1 autorise l’interruption en
fin de programmation EEPROM
BIT 5 : T0IE
(Timer 0 Interrupt Enable).
Qu’est-ce que le TIMER0 ?
Le TIMER0 est en fait un compteur avec lequel :
§
On peut compter les impulsions reçues sur la broche
RA4/T0CKI. On dira dans ce cas que nous sommes en mode “COMPTEUR”.
§
On peut compter les cycles d’horloge du PIC lui-même.
Dans ce cas, comme la fréquence de l’horloge est fixe, nous comptons le
temps. On est alors en mode “TIMER”.
La sélection de l’un ou l’autre de ces modes de fonctionnement se
fait par le bit 5 (T0CS = Timer0 Clock Source
Select bit) du registre OPTION_REG.
Le registre TMR0 qui se trouve à l’adresse 0x01 en Bank0
contient tout simplement la valeur actuelle du timer0.
On peut écrire ou lire dans le registre TMR0. Si ce
registre est configuré en lecture, sa lecture nous donnera le nombre d’événements
survenus sur sa broche RA4/T0CKI. Il faut auparavant préciser le sens de la
transition qui permet d’effectuer le comptage. C’est le bit 4 (T0SE = Timer0
Source Edge Select bit) du registre OPTION_REG qui permet cette précision
Le registre TMR0 ne possède que 8 bits, il ne peut donc
compter que jusqu’à 255 (FF). Tout débordement du timer0 (passage de 0xFF à
0x00) positionne le “flag” T0IF du registre INTCON. On peut donc consulter
ce “flag” pour savoir s’il y a débordement du timer.
Si on autorise une interruption par timer0 en positionnant
le bit 5 (T0IE = Timer0 Interrupt Enable) à 1, chaque fois qu’une
interruption est générée, le “flag” T0IF passe à 1.
Avec un quartz de 4 Mhz, sachant qu’un cycle d’instruction dure 4 périodes d’horloge, nous avons une interruption toutes les 256 ms en mode timer0.
Si on veut augmenter ce temps, on utilisera un prédiviseur
et des sous routines de temporisation. Un prédiviseur étant un circuit
diviseur d’événements situé avant l’entrée de comptage du timer0. Les
divisions de fréquence s’échelonnent de 2 à 256 (voir les bits 0 à 2 du
registre OPTION_REG).
Ce bit 5 fonctionne en lecture/écriture
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
T0IE = 0 interdit l’interruption due
au dépassement du timer
T0IE = 1 autorise l’interruption due
au dépassement du timer
BIT
4 : INTE (Interrupt Enable)
Fonctionne en lecture/écriture
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
INTE = 0 interdit l’interruption par
l’entrée RB0/INT (broche 6)
INTE = 1 autorise l’interruption par
l’entrée RB0/INT (broche 6)
BIT
3 : RBIE (Register B Interrupt
Enable)
Fonctionne en lecture/écriture
Autorise ou non les interruptions par changement d’état
sur le port B, entrées
4 à 7
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
RBIE = 0 interdit les interruptions
par changement d’état sur le port B
RBIE = 1 autorise les interruptions
par changement d’état sur le port B
BIT
2 : T0IF (Timer 0 Overflow
Interrupt Flag)
Fonctionne en lecture/écriture
Fonctionne si le bit 5 autorise les interruptions dues au
dépassement timer et signale alors un éventuel dépassement
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
T0IF = 0 le compteur timer TMR0 n’a
pas effectué de dépassement
T0IF = 1 le compteur timer TMR0 a
effectué un dépassement
BIT
1 : INTF (Interrupt Flag)
Fonctionne en lecture/écriture
Fonctionne si le bit 4 autorise les interruptions par
l’entrée RB0/INT (broche 6) et signale alors une interruption valide sur
cette broche 6
Passe à 0 après un “Power On
Reset”
Passe à 0 après tous les autres
“Reset”
INTF = 0 pas d’interruption sur
RB0/INT
INTF = 1 une interruption valide
s’est produite sur RB0/INT
BIT
0 : RBIF (Register B Interrupt
Flag)
Fonctionne en lecture/écriture
Fonctionne si le bit 3 autorise les interruptions par
changement d’état sur le port B et signale alors une interruption valide sur
le port B
État aléatoire après un “Power On
Reset”
Inchangé après tous les autres
“Reset”
RBIF = 0 aucune broche RB4, RB5, RB6
et RB7 n’ a changé d’état
RBIF = 1 l’une des broches RB4, RB5,
RB6 et RB7 a changé d’état.
Pendant
la routine d’interruption, les autres interruptions ne sont pas traitées.
Les interruptions quelles qu’elles soient ne sont autorisées
que si le bit 7 (GIE) du registre INTCON (0x0b) est à 1.
§
Après un reset, ce bit est à 0
§
Pendant l’interruption, il passe à 0
§
Après un retfie, il revient à 1
11.3.
Sauvegarde des registres
La seule chose dont le programme se souvient, après être
parti en interruption est l’instruction à laquelle il doit revenir. Il faut
donc sauvegarder, dans la routine d’interruption, successivement les registres
“W” et “STATUS” sans modifier leur contenu.
11.4.
Interruption externe (RB0/INT)
L’interruption se produit sur le front montant ou
descendant d’une impulsion appliquée sur la broche 6 (RB0/INT). Il s’agit
du front montant si le bit 6 (INTEDG) du registre OPTION_REG est à 1 et d’un
front descendant s’il est à 0.
L’interruption externe est autorisée si le bit 4 (INTE)
du registre INTCON est à 1
§
Après un reset, ce bit est 0
§
Il faut le mettre à 0 avant de le
porter à 1
Lorsqu’une interruption valide a eu lieu, le bit 1 (INTF)
du registre INTCON passe à 1, pensez donc à le remettre à 0.
Exemple d’interruption : on veut allumer une lumière
placée sur RA2 à partir d’un bouton poussoir (BP) placé sur RB0/INT. (voir
figure suivante)
§
Une pression sur BP allume la Led
§
Une autre pression éteint la Led
§ Et ainsi de suite
La séquence est la suivante :
Dans notre cas cela correspond à :
On éteint la Led
Le programme principal boucle sur Led éteinte
Une interruption survient (appui sur BP)
Traitement de l’interruption (charge de 04 dans W puis application de la fonction OU EXCLUSIF entre W et Port A è Led allumée
Le programme principal boucle sur Led allumée jusqu’à la prochaine interruption.
11.5. L’anti-rebond
Imaginez un bouton poussoir géant.
Lorsque la barre tombe sur les contacts, elle rebondit plusieurs fois. Il y a donc une série de fermetures et d’ouvertures du bouton poussoir. C’est ce que le Pic, qui est un composant rapide (1 ms par instruction) qui ne travaille pas à la même échelle de temps que nous, voit lorsque nous appuyons sur le bouton poussoir.
Pour remédier à ce problème, il faut tout simplement attendre un temps supérieur au temps de rebondissement avant d’autoriser une nouvelle interruption sur RB0.
11.6. Explications
Le programme principal effectue normalement ses initialisations puis teste si une interruption est survenue en vérifiant le "flag" TEMPO. Si le "flag" n’est pas à 1, il boucle sans fin.
Si le bouton poussoir est appuyé, une interruption est générée, RA2 est inversé, la routine d’interruption positionne le "flag" TEMPO à 1 et interdit toute nouvelle interruption de RB0 (toute autre action sur BP sera sans effet pour ne pas prendre en compte les rebonds).
La routine d’interruption prend fin. Retour au programme principal qui continue alors à tester le "flag" TEMPO qui vient d’être positionné par la routine d’interruption. Appelle de la routine de temporisation dont la durée est supérieure à celle des rebonds.
Après écoulement du temps nécessaire à la fin des rebonds, les "flags" TEMPO et INTE (RBO/INT) sont remis à 0 et les interruptions sont à nouveau autorisées afin de permettre de prendre en compte une nouvelle pression sur le BP.
11.7. Finalisation du programme
;=======================================================
; Programme pour le pic 16F84. Ce programme allume une lumière placée sur RA2 à l'aide
; d'un bouton poussoir placé sur RB0/INT
; Titre : Télérupteur version 1
; Auteur : Dany Amer
; Remarque : Anti-rebond de 390 ms (temporisation) avec un quartz de 4MHz
; Fichier requis : p16f84.inc
;=======================================================
;=====================ENTÊTE==============================
list p=16f84, w=2 ; Définition de processeur, niveau d’erreur
#include <p16f84.inc> ; Définition des constantes
__config _cp_off & _wdt_off & _pwrte_on & _xt_osc
;======================================================
; ASSIGNATIONS
; *************
optionval equ 0x00 ; Valeur du registre "option"
; Résistances pull-ups "ON"
; Interruption RB0/INT sur front descendant
intermask equ 0x90 ; Masque d'interruption. Autorisation générale
; d'interruption et permission de l'interruption RB0/INT
;=======================================================
; DÉFINITIONS
; **********
#define led porta, 2 ; LED de sortie
#define tempof flags, 0 ; Drapeau d'interruption pour temporisation contre les
; rebonds du bouton poussoir
;
=======================================================; MACRO
; *****
bank0 macro
bcf status, rp0 ; Passer en banque0
endm
bank1 macro
bsf status, rp0 ; Passer en banque1
endm
;=======================================================
; DÉCLARATION DE VARIABLES
; ***********************
cblock 0x0c ; Début de la zone variables
w_temp :1 ; Emplacement de sauvegarde du registre W
status_temp : 1 ; Emplacement de sauvegarde du registre STATUS
compteur0 : 1 ; Emplacement du compteur
compteur1 : 1 ; Emplacement du compteur1
compteur2 : 1 ; Emplacement du compteur2
flags : 1 ; Emplacement du bit b0 réservé pour le "flag" tempo
endc ; Fin de la zone de stockage
;=======================================================
; DÉMARRAGE SUR RESET
; *******************
org 0x00 ; Adresse de départ après reset
goto init ; Aller à l'étiquette "init"
;=======================================================
; ROUTINE INTERRUPTION
; ********************
; sauvegarde des registres
; ----------------------------
org 0x04 ; Adresse d'interruption
movwf w_temp ; Sauvegarder le registre W
swapf status, w ; Swap status avec résultat dans w
movwf status_temp ; Sauvegarder status "swappé"
call intrb0 ; Traiter l'interruption RB0/INT
; Restauration des registres
; -----------------------------
swapf status_temp, w ; Swap ancien status, résultat dans w
movwf status ; Restaurer status
swapf w_temp, f ; Inversion L et H de l'ancien W sans modifier Z
swapf w_temp, w ; Réinversion de L et H dans W
; W restauré sans modifier status
retfie ; Retour à la ligne suivant l'appel d'interruption
;=======================================================
; INTERRUPTION RB0/INT
; *******************
intrb0
movlw 0x04 ; Bit à inverser
bank0 ; Passer en banque0
xorwf porta , f ; Inverser LED
bcf intcon, inte ; Interdire une autre interruption sur RB0/INT
bsf tempof ; Positionner le "flag" tempo
return ; Fin d'interruption RB0/INT
;=======================================================
;=======================================================
; INITIALISATION
; *************
init
bcf tempof ; Effacer "flag" tempo
bank1 ; Passer en banque1
movlw 0x01
movwf trisb ; RB0 en entrée
movlw 0xfb
movwf trisa ; RA2 en sortie
movlw optionval ; Charger masque (pull-ups "ON" et RBO/INT sur
;niveau bas)
movwf option_reg ; Initialiser le registre "option"
bank0 ; Passer en banque0
movlw intermask ; Masque d'interruption (autorisation des interruptions
; GIE et INTE)
movwf intcon ; Charger le masque dans le registre "INTCON"
bcf led ; Éteindre la Led
goto start ; Aller au programme principal
;=======================================================
; PROGRAMME PRINCIPAL
; *******************
start
btfss tempof ; Tester si le "flag" tempo est mis. Si oui sauter la
; prochaine instruction sinon exécuter la suivante
goto start ; Boucler
call tempo ; Exécuter la temporisation
bcf tempof ; Effacer le "flag" tempo
bcf intcon, intf ; Effacer le "flag" de RB0/INT
bsf intcon, inte ; Remettre RB0/INT en service
goto start
;=======================================================
; TEMPORISATION DE 390 ms
; **********************
tempo
movlw 0x02 ; Charge la valeur 2 dans l'accumulateur
movwf compteur2 ; Transfert w dans le registre "compteur2"
load1
movlw 0xff ; Charge la valeur ff dans l'accumulateur
movwf compteur1 ; Transfert w dans le registre "compteur1"
load0
movlw 0xff ; Charge la valeur ff dans l'accumulateur
movwf compteur0 ; Transfert w dans le registre "compteur"
dec
decfsz compteur0, 1 ; Décrémente le registre "compteur0", saute
; l'instruction suivante si le résultat est zéro
goto dec ; Décrémente = 1 cycle, goto = 2 cycles soit au total
; 3 cycles d’instruction , t = 3 micro-secondes x
; contenu du registre "compteur" = 3us x 255 = 765ms
decfsz compteur1, 1 ; Décrémente le registre "compteur1"
goto load0 ; t = 3 x 255 x 255 = 195ms
decfsz compteur2, 1 ; Décrémente le registre "compteur2"
goto load1 ; t = 3us x 255 x 255 x 2 = 390 millisecondes
return ; Retour à la ligne suivant l'appel de l'étiquette
; "tempo"
end ; Directive fin de programme
;=======================================================
11.8.
Utilisation de deux interruptionsDans l’exemple suivant, on va utiliser deux interruptions différentes. Dans notre programme de télérupteur, on va remplacer la temporisation par une interruption sur le TIMER0.
La mise en œuvre du timer0 est visible dans l’application suivante :
;==========================================================
; Programme pour le pic 16F84. Ce programme allume une lumière placée sur RA2 à l'aide
; d'un bouton poussoir placé sur RB0/INT
; Titre : Télérupteur version 2
; Auteur : Dany Amer
; Remarque : Anti-rebond de 328 ms à l'aide du timer (quartz de 4MHz)
; Fichier requis : p16f84.inc
;========================ENTÊTE=============================
list p=16f84, w=2 ; Définition de processeur, niveau d’erreur
#include <p16f84.inc> ; Définition des constantes
__config _cp_off & _wdt_off & _pwrte_on & _xt_osc
;==========================================================
; ASSIGNATIONS
; ************
optionval equ 0x07 ; Valeur registre option
; Résistance pull-up "ON" (Non RBPU = bit 7 = 0)
; Interruption RB0/INT sur front descendant (INTDG=bit 6 = 0)
; Incrémenté en fonction de l’horloge interne (T0CS = bit5 = 0
; Utilisation de la prédivision du timer (PSA = bit 3 = 0)
; Prédivision du timer à 256 (PS0, PS1, PS2=bits 0,1 et 2 à
; l’état 1)
intermask0 equ 0x90 ; Masque d'interruption avant l'interruption RB0
; Interruption générale autorisée GIE = bit 7 = 1
; Interruption du timer interdite T0IE = bit 5 = 0
; Interruption sur RB0/INT autorisée INTE = bit 4 = 1
intermask1 equ 0x20 ; Masque d'interruption après l'interruption RB0
; Interruption INTE hors service (RB0/INT annulée)
; Interruption TMR0 en service (T0IE=1)
; "Flag" INTF remis à 0
intermask2 equ 0x10 ; Masque d'interruption durant l'interruption Timer0
; Interruption TMR0 interdite
; Interruption RB0/INT en service
; Flag RB0/INT effacé
; Le "flag" GIE sera remis par retfie
passages equ 0x05 ; Nombre de passages dans le registre TMR0
; Temporisation contre les rebonds du bouton poussoir
; 256 s x 256 x 5 =328 ms
;==========================================================
; DÉFINITIONS
; **********
#define led porta,2 ; LED placée sur RA2
;==========================================================
; MACRO
; *****
bank0 macro
bcf status,rp0 ; Passer en banque0
endm
bank1 macro
bsf status,rp0 ; Passer en banque1
endm
input macro
bcf status,rp0
movlw 0x01
movwf trisb ; RB0 en entrée
endm
output macro
movlw 0xfb
movwf trisa ; RA2 en sortie
bsf status,rp0
endm
;==========================================================
; DÉCLARATION DE VARIABLES
; ***********************
cblock 0x0c ; Début de la zone "variables"
w_temp :1 ; Sauvegarde du registre W
status_temp : 1 ; Sauvegarde du registre STATUS
compteur : 1 ; Compteur de passages dans le registre "TMR0"
endc ; Fin de la zone
;==========================================================
; DÉMARRAGE SUR RESET
; *******************
org 0x00 ; Adresse de départ après reset
goto init ; Aller à l'étiquette "init"
;==========================================================
; ROUTINE INTERRUPTION
; ********************
; Sauvegarde des registres
; -----------------------------
org 0x04 ; Adresse de départ de l'interruption
movwf w_temp ; Sauvegarder le registre W
swapf status,w ; Permuter status (low et high) et mettre le résultat dans w
movwf status_temp ; Sauvegarder le registre status permuté
; Test des différentes interruptions
; ---
-------------------------------------btfsc intcon,t0ie ; Tester si l'interruption timer est autorisée. Si 1, aller
; à l'instruction suivante, sinon la sauter.
btfss intcon,t0if ; Tester si l'interruption timer est en cours. Si oui sauter
; la prochaine instruction, si non l'exécuter.
goto intbp ; Aller à l'étiquette intbp
call inttimer ; Traiter l'interruption par débordement du timer
bcf intcon,t0if ; Effacer le "flag" d'interruption du timer
goto recupreg ; Aller à récupération des registres sauvegardés
intbp
call intrb0 ; Traiter l'interruption par RB0/INT
bcf intcon,intf ; Effacer le "flag" de l'interruption RB0/INT
; Restauration des registres
; ------------------------------
recupreg
swapf status_temp,w ; Permuter status_temp et mettre le résultat dans w
movwf status ; Restaurer status
swapf w_temp,f ; Permuter L et H de w_temp, mettre le résultat dans f sans
; modifier Z
swapf w_temp,w ; Réinversion de L et H, résultat dans w, w est ainsi restauré
;sans modifier status
retfie ; Retour d'interruption
;==========================================================
; INTERRUPTION TIMER 0
; *******************
inttimer
decfsz compteur,f ; Décrémenter le compteur de passages dans TMR0
return ; Pas 0, retour au point d'appel de inttimer
movlw passages ; Charger w avec le nombre de passages
movwf compteur ; Recharger le compteur de passages
movlw intermask2 ; Préparation valeur INTCON
movwf intcon ; Interruption TMR0 interdite
; Interruption RB0/INT en service
; Flag RB0/INT effacé
; Le "flag" GIE sera remis par retfie
return ; Fin d'interruption timer
;==========================================================
; INTERRUPTION RB0/INT
; *******************
intrb0
movlw 0x04 ; Préparer pour inversion bit
bank0 ; Passer en banque0
xorwf porta,f ; Inverser le niveau logique sur la LED
clrf tmr0 ; Remise à zéro du timer0
movlw intermask1 ; Préparation pour le registre INTCON
movwf intcon ; Interruption INTE hors service (RB0/INT annulée)
; Interruption TMR0 en service (T0IE=1)
; "Flag" INTF remis à 0
return ; Fin d'interruption RB0/INT
;==========================================================
; INITIALISATIONS
; **************
init
input ; RB0 en entrée
output ; RA2 en sortie
clrf porta ; Sorties portA à 0
clrf portb ; Sorties portB à 0
bank1 ; Passer en banque1
movlw optionval ; Charger masque
; Résistances pull-ups "ON"
; RB0/INT active sur niveau bas
; Signal d'horloge interne
; TMR0 sélectionné
; Prédiviseur à 256
movwf option_reg ; Initialiser registre option
movlw passages ; Charger le nombre de passages
movwf compteur ; Charger le compteur de passages
bcf led ; Éteindre la LED
bank0 ; Passer en banque 0
movlw intermask0 ; Masque interruption
; Interruption générale autorisée
; Interruption timer interdite
; Interruption RB0/INT autorisée
movwf intcon ; Charger le registre INTCON
goto start ; Aller au programme principal
;==========================================================
; PROGRAMME PRINCIPAL
; ********************
start
goto start ; Boucler
end ; Fin de programme
;==========================================================
Le fonctionnement de ce programme est explicité par l’ordinogramme suivant :