Logiciels > Programmation PIC > Bases > MP > Lecture CAN (ADC)

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.

pic_tuto_base_can_001a

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.

pic_tuto_base_can_001b

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.