Dernière mise à jour :
04/01/2015
Présentation
L'exemple décrit ici montre comment
réaliser l'acquisition d'une tension analogique et montre une
façon de traiter le résultat dans son domaine
numérique. Le PIC utilisé pour l'exemple est le 12F675,
qui dispose de plusieurs entrées analogiques.
Qu'est-ce qu'un CAN ?
CAN = Convertisseur Analogique Numérique (en anglais : ADC = Analog to
Digital Convertor)
Un convertisseur analogique numérique est un système qui
fait une correspondance entre une tension analogique et une valeur
numérique. Dans le domaine analogique tout comme dans le domaine
numérique, il existe des limites, une limite basse et une limite
haute. Par exemple, on peut imaginer une plage de tension comprise
entre 0 V et +5 V pour le domaine analogique, et une plage de valeurs
comprises entre 0 et 255 pour le domaine numérique. Tout comme
on peut imaginer une plage de tension comprise entre 0 V et +2,5 V pour
le domaine
analogique, et une plage de valeurs comprises entre 0 et 1023 pour le
domaine numérique. Ces deux plages peuvent être mise en
regard, on peut par exemple décider de mettre la valeur
analogique 0 V en face de la valeur numérique 0, et mettre la
valeur analogique +5 V en face de la valeur numérique 1023.
Le nombre de valeurs possibles dans le domaine numérique (1024
valeurs différentes dans l'exemple précédent, de 0
à 1023) conditionne la précision de la conversion, car de
ce nombre dépend directement la largeur de la plage de tension
analogique qui "tombe en face" d'une même valeur
numérique. En effet, et cela est facile à comprendre, le
nombre de valeurs numériques correspond au nombre de "tranches"
de valeurs du domaine analogique. Ici, la plage de 0 V à +5 V
est "découpée" en 1023 tranches, qui valent chacune
0,004887 volts de largeur (ou de hauteur, si vous
préférez), cela correspond à la division de 5 V par
1023. Pas besoin d'être expert pour deviner ou sentir qu'un
nombre réduit de valeurs numériques rendra scabreuses les
correspondances entre les deux domaines : il existe en effet un nombre
infini de valeurs possibles du côté analogique (on peut
avoir une valeur de 1,001 V tout comme une valeur de 1,002 V), alors
que les valeurs numériques sont en nombre fini. Dans le cas
présent - et c'est toujours vrai pour un convertisseur
analogique numérique, on est absolument certain que plusieurs
tensions analogiques différentes vont tomber en face d'une
même valeur numérique, et que leur distinction, une fois
converties, sera totalement impossible. Reste à prendre la
décision de la précision désirée : est-il
important de pouvoir distinguer deux tensions analogiques distantes de
1 mV ? Si oui, il est clair que la division en tranches de 0,004887
volts va poser problème, l'écart minimal décelable
étant cinq fois supérieur à la précision
demandée. Pour répondre à cette demande, il
faudrait disposer d'un nombre de valeurs numériques bien
supérieur à 1024. Par exemple 16384 valeurs possibles, qui autoriserait
des
tranches aussi fines que 0,3 mV. Et bien le choix semble simple,
puisque qui peut le plus peut le moins : on ne va pas s'embêter
et on va choisir le système doté du plus grand nombre
possible de valeurs numériques, qui correspond à un
convertisseur doté d'une résolution maximale. En fait, la
pratique va vite nous limiter dans notre choix : un bon convertisseur
doté d'une grande résolution coûte plus cher qu'un
convertisseur de résolution "moyenne", et pour
bénéficier de la haute résolution, tous les
circuits et composants qui tournent autour, ainsi que le circuit
imprimé et l'alimentation, doivent être assemblés
selon des règles très strictes et critiques. Mais nous
n'allons pas développer plus que ça ces histoires de
"qualité" ou de résolution des CAN, car là n'est
pas l'objet principal du sujet. Contentons-nous de considérer
que les CAN dont la résolution est de 10 bits qui
équipent nos petits PICs, constituent déjà une
bonne entrée en matière. 10 bits permettent le
découpage en 1023 valeurs, tout comme 8 bits permettent un
découpage en 255 valeurs, et 14 bits permettent un
découpage en 16384 valeurs. Et 1023 valeur pour une plage de
tension de 5 V, cela donne une résolution voisine de 5 mV, ce
qui est déjà bien suffisant dans nombre de cas !
Lecture d'une valeur analogique
Avant de pouvoir effectuer la conversion d'une valeur analogique en son
équivalent numérique avec un convertisseur "nu" (un
composant "basique" qui ne fait que ça), il faut apprendre
comment faire. La conversion s'effectue en plusieurs étapes et
non en une seule, et doit suivre un timing précis. Si on va trop
lentement ou trop vite, la valeur obtenue après conversion
risque de manquer de précision ou même d'être
totalement erronée. Je sais que cela va vous déplaire,
mais ici, nous n'allons pas entrer dans le détail de
l'échantillonage de la tension à mesurer ni de la
conversion en sa valeur numérique. Non, on va simplement
exploiter une routine toute faite qui est incluse dans MikroPascal, et
qui simplifie bigrement la tâche ! Nul doute que le lecteur curieux
saura trouver des renseignements plus fouillés sur la conversion, en
cherchant un peu. Le schéma qui suit
et qui concerne notre affaire dévoile un PIC 12F675, dont seule
l'entrée analogique AN0 est utilisée parmi les quatre disponibles. Les
autres broches
du circuit sont configurées en tant que sortie
logique pour piloter des leds.
Nous avons vu à la page
PIC -
Bases - Configuration minimale,
qu'une même broche d'un PIC pouvait jouer plusieurs rôles, selon la
configuration adoptée pour celle-ci. Le PIC 12F675 dispose de six
pattes "utiles" dont quatre peuvent être configurées en tant que port
logique (entrée ou sortie), ou en tant qu'entrée analogique.
Dans
le
cas qui nous concerne, nous utilisons la ligne GP0/AN0 comme entrée
analogique qui accueillera une tension comprise entre 0 V et +5 V, et
les autres lignes en tant que
sorties logiques - à l'exclusion de GP3 qui ne peut par construction
que servir d'entrée. Une fois encore, le registre TRIS va être mis à
contribution pour définir le sens de ces diverses lignes. Mais
contrairement au PIC 16F628A, le PIC 12F675 ne possède pas de
port
appelé PORTA ou PORTB. Au lieu de cela, il possède un port appelé GPIO,
que l'on peut tout autant considérer comme un "port universel d'entrées
/ sorties". Pas de ligne de code de type TRISA ou TRISB pour la
configuration, mais
plutôt une ligne de type TRISIO. Et tant qu'à faire, adoptons la
méthode de configuration individuelle de chaque ligne du port GPIO, via
"indexation" du mot TRISIO avec le numéro d'ordre des lignes
qui
nous interessent. Le code ci-après correspond au programme complet, de
nouvelles choses au menu ;-)
program electronique_pic_tuto_base_can_001a;
var
wIn: word; // variable contenant la valeur numérisée de la tension analogique
procedure Init;
begin
OPTION_REG := %10000000; // pullup désactivé (bit 7 à 1)
TRISIO.0 := 1; // GP0 configuré en entrée (analogique ou numérique)
TRISIO.1 := 0; // GP1 configuré en sortie, commande led D4
TRISIO.2 := 0; // GP2 configuré en sortie, commande led D3
TRISIO.3 := 1; // GP3 non utilisé, configuré en entrée
TRISIO.4 := 0; // GP4 configuré en sortie, commande led D2
TRISIO.5 := 0; // GP5 configuré en sortie, commande led D1
CMCON := %00000111; // désactivation comparateurs, on peut aussi écrire CMCON := 7;
ANSEL.ANS0 := 1; // utilisation de l'entrée GPIO.0 comme entrée analogique (AN0)
ANSEL.ANS1 := 0; // utilisation de l'entrée GPIO.1 comme sortie numérique (GP1)
ANSEL.ANS2 := 0; // utilisation de l'entrée GPIO.2 comme sortie numérique (GP2)
ANSEL.ANS3 := 0; // utilisation de l'entrée GPIO.4 comme sortie numérique (GP4)
ADCON0.ADFM := 1; // 0 = left justified, 1 = right justified
ADCON0.VCFG := 0; // tension de référence = VDD
ADCON0.ADON := 1; // activation du module convertisseur A/D
ANSEL.ADCS0 := 1; // |
ANSEL.ADCS1 := 0; // | ADCS = 001 = Fosc/8
ANSEL.ADCS2 := 0; // |
GPIO.1 := 0;
GPIO.2 := 0;
GPIO.4 := 0;
GPIO.5 := 0;
//ADC_Init;
end;
// main program
begin
Init;
while true do
begin
wIn := ADC_Read(0); // lecture entrée analogique AN0
GPIO.1 := ((wIn >= 767) and (wIn < 1024)); // led D4 : +3.75V < Vin < +5V
GPIO.2 := ((wIn >= 512) and (wIn < 767)); // led D2 : +1.25V < Vin < +2.5V
GPIO.4 := ((wIn >= 255) and (wIn < 512)); // led D3 : +2.5V < Vin < +3.75V
GPIO.5 := ((wIn >= 0) and (wIn < 255)); // led D1 : 0V < Vin < +1.25V
delay_ms(300);
end;
end.
Configuration générale
Des choses déjà vues et d'autres nouvelles.
OPTION_REG
Registre
des options, qui permet de définir un certain nombre de "comportements"
que le PIC doit avoir. Ce registre comporte 8 bits, et chaque bit
correspond à une fonction particulière. Ici, seule la fonction PULLUP,
dont l'état est défini par la valeur du septième bit, nous interesse,
elle doit être désactivée (bit 7 à 1). Pour les autres bits, on verra
les explications plus tard ;-)
TRISIO
Configuration
permettant de définir l'orientation des broches du PIC, en entrée ou en
sortie. Ce mot ne décrit pas si l'entrée doit être de type analogique
ou numérique, il ne fait que renseigner sur le sens des données
(sortant du PIC ou y entrant).
CMCON
Ce
registre permet de spécifier si l'on veut oui ou non utiliser le
comparateur interne du PIC. Ici, ce n'est pas le cas, et les bits 0 à 2
qui décrivent comment l'utiliser doivent être positionnés à 1
(désactivation totale).
ANSEL.ANSx
Permet
de spécifier si les entrées doivent être de type numérique (valeur 0)
ou si elles doivent être de type analogique (valeur 1).
ADCON0
Registre
de controle du CAN, qui permet d'indiquer comment il doit fonctionner,
et sur quelle entrée analogique il doit se "brancher". Le paramètre
ADON (premier bit de ce registre) doit être positionné explicitement
par code pour indiquer si le module de conversion doit être oui ou non
activé. Il peut l'être même si on ne l'utilise pas, mais ajoute un peu
à la consommation du circuit, ce qui n'est guère utile.
Conversion analogique numérique
ADC_Read(num_entrée)
C'est
la
fameuse procédure qui permet de lire en une seule ligne de code, la
valeur d'une tension analogique sur une entrée, et de la convertire en
une valeur
numérique. Cette procédure n'attend qu'une seule information de notre
part : le numéro de l'entrée analogique sur laquelle on veut effectuer
l'échantillonnage, que l'on place entre les parenthèses. Ici il s'agit
de l'entrée AN0 - la première entrée analogique du PIC, le numéro
d'entrée analogique à spécifier est donc le numéro 0. Si on avait voulu
lire la tension présente sur l'entrée AN2, il aurait fallut écrire
ADC_Read(2). Une fois la
conversion achevée, la procédure retourne la valeur numérisée, sur un
format de 16 bit (word). C'est cette valeur qui est stockée dans la
variable wIn, également de type Word (16 bits).
Allumage des LED
Une seule LED peut être allumée à la fois, selon les conditions
suivantes :
-
si tension d'entrée sur AN0 comprise entre 0 V et +1,25 V
(valeur numérisée wIn comprise entre 0 et 255), allumage LED D1.
-
si tension d'entrée sur AN0 comprise entre +1,25 V et +2,5 V (valeur
numérisée wIn comprise entre 256 et 511), allumage LED D2.
- si
tension d'entrée sur AN0 comprise entre +2,5 V et +3,75 V
(valeur
numérisée wIn comprise entre 512 et 767), allumage LED D3.
-
si tension d'entrée sur AN0 comprise entre +3,75 V et +5 V
(valeur numérisée wIn comprise entre 767 et 1023),
allumage LED D4.
Pour rappel
: le CAN est de type 10 bits et le codage numérique peut s'effectuer
sur une valeur comprise entre 0 et 1023. L'entrée analogique travaille
sur une pleine échelle de 5 V (0 V à +5 V), la valeur max de +5 V
correspond à la valeur numérique 1023.
Remarques concernant la plage de tension du CAN-
on travaille ici sur une plage de 5 V qui correspond à la tension
d'alimentation du PIC. Si ce dernier était alimenté sous une tension de
3,3 V, la valeur la plus élevée du CAN correspondrait à +3,3 V.
- la
plage de travail peut être réduite à une valeur inférieure à celle de
l'alimentation du PIC. On peut par exemple exploiter tous les niveaux
d'échelle du CAN sur une plage de tension de 0,5 V, dès l'instant où
les références haute et/ou basse (Vref+ et Vref-) du CAN sont accessibles
via des broches du PIC, que l'on doit dans ce cas correctement
configurer.
Code plus "lisible" ?
On aurait pû aussi déclancher l'allumage des LED avec des lignes
de codes plus "parlantes" mais aussi plus encombrantes :
// main program
begin
Init;
while true do
begin
wIn := ADC_Read(0); // lecture entrée analogique AN0
// led D1 : 0V < Vin < +1.25V
if ((wIn >= 0) and (wIn < 255)) then
begin
GPIO.1 := 0;
GPIO.2 := 0;
GPIO.4 := 0;
GPIO.5 := 1;
end
// led D2 : +1.25V < Vin < +2.5V
else if ((wIn >= 255) and (wIn < 512)) then
begin
GPIO.1 := 0;
GPIO.2 := 0;
GPIO.4 := 1;
GPIO.5 := 0;
end
// led D3 : +2.5V < Vin < +3.75V
else if ((wIn >= 512) and (wIn < 767)) then
begin
GPIO.1 := 0;
GPIO.2 := 1;
GPIO.4 := 0;
GPIO.5 := 0;
end
// led D4 : +3.75V < Vin < +5V
else if ((wIn >= 767) and (wIn < 1024)) then
begin
GPIO.1 := 1;
GPIO.2 := 0;
GPIO.4 := 0;
GPIO.5 := 0;
end;
delay_ms(300);
end;
end.
Historique
04/01/2015
- Ajout infos concernant la
plage de tension du CAN quand le PIC est alimenté sous 3,3 V, merci à
Pierre-Marie pour ses remarques.
02/11/2014
- Correction erreur dans le code
principal : j'avais attribué les trois bits ADCS2:0 au registre ADCON0 au
lieu de ANSEL. Cette erreur n'empêchait pas l'ensemble de
fonctionner, le CAN tournait à Fosc/2 au lieu de Fosc/8 (bits
ADCSx du registre ANSEL par défaut à 0). Côté registre ADCON0, les
bits 4 et 5 ne sont pas implémentés et le bit 6 était forcé à 0,
qui était la valeur qu'on voulait. En somme, coup de bol (si ça n'avait
pas fonctionné, je m'en serais sans doute rendu compte). Merci à Gilles
N. qui m'a signalé la coquille.
29/07/2009
- Première mise à disposition.