Conversion A/D PIC18F4520

Mkv Messages postés 8 Statut Membre -  
 Biggie -
Bonjour à vous !

Je voudrai réaliser un programme permettant une conversion analogique numerique avec un PIC 18F4520. J'utilise le logiciel et une carte de test MPLAB V8 avec MCC18.
Il faudrait donc un programme avec une initialisation de l'adc ainsi que le programme de conversion.

J'ai essayé l'initialisation ce qui donne ceci (Mon probleme est que j'ai très peu de base en langage C :'( ) :

#include <p18f4520.h>
#include <adc.h>

void main(void)

{

	TRISA=1; 					// PORTA en Entrée
	PORTA=1; 					// PORTA a 1

	ADCON0bits.ADON = 1 ;		// A/D convert ON
	ADCON0bits.CHS0 = 0	;	// Choisir la voie a convertir => AN0
	ADCON0bits.CHS1 = 0	;	// Choisir la voie a convertir => AN0
	ADCON0bits.CHS2 = 0	;	// Choisir la voie a convertir => AN0
	ADCON0bits.CHS3 = 0	;	// Choisir la voie a convertir => AN0

	ADCON1bits.PCFG0 = 1 ;		// Configuration des ports A/D = AN1 et AN0
	ADCON1bits.PCFG1 = 0 ;		// Configuration des ports A/D = AN1 et AN0
	ADCON1bits.PCFG2 = 1 ;		// Configuration des ports A/D = AN1 et AN0
	ADCON1bits.PCFG3 = 1 ;	// Configuration des ports A/D = AN1 et AN0
	ADCON1bits.VCFG0 = 0 ;	// references de tension a utiliser par le CAN => Vref+ = Vdd
	ADCON1bits.VCFG1 = 0 ;	// references de tension a utiliser par le CAN => Vref- = Vss

	ADCON2bits.ADCS0 = 0 ;		// configurer horloge selection
	ADCON2bits.ADCS1 = 0 ;		// configurer horloge selection
	ADCON2bits.ADCS2 = 1 ;		// configurer horloge selection
	ADCON2bits.ACQT0 = 0 ;		// configurer un temps d'acquisition
	ADCON2bits.ACQT1 = 0 ;		// configurer un temps d'acquisition
	ADCON2bits.ACQT2 = 0 ;		// configurer un temps d'acquisition
	ADCON2bits.ADFM =  1 ;		// justification a droite
		
	ADRESH=0x00 ;				// Mise à zero du registre ADRESH 

	ADCON0bits.GO_DONE = 1;		// A/D conversion in progress (Start Of Conversion)

while(ADCON0bits.GO_DONE); // Attente de l'EOC

	{

	ADCON0bits.GO_DONE=0; // EOC
	X=ADRESH;
	X<<=8;
	X|=ADRESL;

	}


Pourriez vous me dire ce qui ne va pas dans le bout de programme ci-dessus ? les choses à modifier ect ...

Pour la suite (conversion), je ne sais pas du tout comment faire ...

11 réponses

Nico
 
Je vais essayer d'être le plus precis possible. Je vais te donner deux codes, le premier sans fonction, le second avec fonction !

Pour commencer quand tu configures tes registres ADCON1 ; 2 et 3 tu peux configurers chaqu'un en une seule ligne, au lieu de faire du bit à bit, et donc un gain de temps ( notamment pour le temps de boucle).

1ére solution :

#include <p18f4520.h>
#define q 4.8828e-3
/* quantum (résolution) tu as un CAN 10bit, 2^10 =1024. Donc 1024 => 5V ; 1=> ???V soit 0.0048828... */

void main(void)
{
float AN0;
/CAN on. CLOCK=FOSC/2. CANAL0 (RA)

// VREF+=VDD VREF-=VSS
ADCON0=1;
/* les bits 7 et 6 du registre ADCON0 (pour le 18f4520) ne sont pas utilisés, les bits 5->2 servent a choisir quel CAN, ici on utilise le AN0 soit 000; le bit 1 est un bit d'etat, et le bit 0 est pour valider le fonctionnement. On aurait pu ecrire les codes suivants : ADCON0=0x01 ou 0b00000001 ce qui revient a ecrire 1 */

ADCON1=0x8E;
/* soit 1000 1110; le premier 1 sert a justifier a droite. Le E sert a configurer les pins. */

while(1){ // boucle infinie pour utiliser en continue, dnas le cas d'une seule conversion pas besoin, on aurait pu
// for (;;) ou encore for(;3.14;) un truc qui est vrai tout le temps !

ADCON0bits.GO_DONE=1; //lance la conversion

while(ADCON0bits.GO_DONE // attente de la fin de la conversion

AN0=(float)ADRES*q; // calcule du resultat.
}
}

A partir de la tu peux explorer comme tu veux AN0.

Solution inspirée du site de : www.aix-mrs.iufm.fr ( ils ont une page avec des tp sur la programmation du 18f4520)

La deuxieme solution, vient d'un de mes profs de l'iut de Cachan.

A mettre dans un fichier CAN.h

#include <p18f4520.h>

void adc_init(char Nb_CAN_use-1); // init du CAN

int adc_read(char CAN_choisi); // lecture de la valeur analogique d'un channel

A mettre dans un fichier CAN.c

#include "CAN.h"
// pour info : AN0 => a0 , AN1=>a1... AN5=>e03

void adc_init(char Nb_CAN_use-1)
{
switch(Nb_CAN_use-1) /*configure ADCON1 suivant le numero du dernier CAN, Par exemple tu veux utiliser cinq CAN tu ecris adc_init (4) */

{
case(0) : ADCON1 = 0xE; //configuration pour un CAN
TRISA = TRISA|0b00000001;
break;
case(1) : ADCON1 = 0xD;
TRISA = TRISA|0b00000011;
break;
case(2) : ADCON1 = 0xC;
TRISA = TRISA|0b00000111;
break;
case(3) : ADCON1 = 0xB;
TRISA = TRISA|0b00001111;
break;
case(4) : ADCON1 = 0xA;
TRISA = TRISA|0b00101111;
break;
case(5) : ADCON1 = 0x9;
TRISA = TRISA|0b00101111;
TRISE = TRISE|0b00000001;
break;
case(6) : ADCON1 = 0x8;
TRISA = TRISA|0b00101111;
TRISE = TRISE|0b00000011;
break;
case(7) : ADCON1 = 0x7;
TRISA = TRISA|0b00101111;
TRISE = TRISE|0b00000111;
break;
case(8) : ADCON1 = 0x6;
TRISA = TRISA|0b00101111;
TRISE = TRISE|0b00000111;
TRISB = TRISB|0b00000100;
case(9) : ADCON1 = 0x5; //configuration de 10 CAN
TRISA = TRISA|0b00101111;
TRISE = TRISE|0b00000111;
TRISB = TRISB|0b00001100;
default : ADCON1 = 0xF;
}

ADCON2 = 0b10100110; /*configure la Fconv (Fhorloge/64) + tps d'acqui +8periode de conv + justification a droit pour utiliser sur 10bits*/

ADCON0bits.ADON = 1; // valide l'utilisation du CAN
}

int adc_read(char CAN_choisi)
{
int resultat =0 ; //varible qui sera retournée

ADCON0 = ((numero_channel << 2) & 0b00111100) |
(ADCON0 & 0b11000011); // selection du channel (du CAN)

ADCON0bits.GO = 1; // Lancement de conversion

while(ADCON0bits.GO); // attendre la fin de la conversion

result = (int)ADRESH; // Read ADRESL into the lower byte
result = result<<8 | (int)ADRESL; // Read ADRESH into the high byte

return (result); // retourne la valeur
}

A mettre dans un main,

tu declares tes variables, puis tu les utilise par exemple:

Fichier main.c:
#include "CAN.h"

void main (void)
{
int AN0=0;
int AN1=0;

adc_init(0);
adc_init(1);
AN0=adc_read(0);
AN1=adc_read(1);

//ensuite tu fais ce que tu veux des valeurs AN0

}

je pence que tout y est, pour conclure si tu utilises un seul CAN, la premiere solution est la solution, si tu compte en utiliser plusieur ( par exemple dix comme je doit faire) les fonctions s'averent tres utilent pour allerger le code et le rendre plus compréhensible.

J'espere t'avoir aidé

Nico
4
Mkv Messages postés 8 Statut Membre 9
 
merci baucoup, j'y voie deja plus claire :)

cepandant, j'aimerais savoir, le 18f45020 dispose de 2 registres ADRESH et ADRESL , a quoi servent ils ?
Dans ta premiere solution quand tu ecris "AN0=(float)ADRES*q; // calcule du resultat. " cela veux dire quoi ? qu'il met le resultat de la conversion dans un registre ?
2
Nico
 
Hello ;)

Pour comprendre a quoi servent ces deux registres, il faut comprendre le fonctionnement d'un CAN (que je n'expliquerais pas dans un soucis de clareté) donc pour faire precis, la conversion n'est pas instantanée (quelque µs voir ns) Lors de la conversion le convertisseur ne "range" pas la donnée qu'il est en train de calculer directement dans ta variable ( ex : result_conv) Lors de la conversion le resultat est stocké dans un registre temporaire soit ADRESH et ADRESL.

Un registre est contitué de 8bits, alors que notre convertisseur est de 10bits... Et la tu te dira " les registre additioner fond 16bits comment arriver à 10), je te repond "la justification a droite ou a gauche" Pour comprendre je te conseil jde juste d'aller a cette page ( interesse toi qu'au schéma et au text, le code c'est de l'assembleur, et apres les liens je prefere pas cliquer. c'est ici => www.brodeurelectronique.com ( a gauche dans tutoriaux => ADCs)

d'ou le decalage <<8 ;)

je le reconnais j'étais tres rapide la dessus.

AN0=(float)ADRES*q;

Le premier code ne vient pas de moi, je me suis inspiré, donc je supose que ADRES corespond a un registre qui contient directement le resultat selon justification a droite ou a gauche.
Pour exploiter le resultat de ta conversion tu ne peux pas l'utiliser du registre, il faut donc le stocker dans un variable.

Je pense que tu dois savoir, quand tu fais char a=5; a prend la valeur de 5, ici AN0 prend la valeur convertie;)

Apres tu peux en faire de belles choses, par exemple via des if et else if allumer plus ou moins de leds selon le resultats de la conversion, ou encore l'afficher sur un LCD. Ou meme fixer une valeur, avec laquelle tu compares ta conversion qui pourais fermer un Mosfet ou autre... tout est possible ;)

Donc a voir tes questions je suppose que tu as preféré la premiere solution je te la recris sans les // ou /* */

#include <p18f4520.h>
#define q 4.8828e-3
/* quantum (résolution) tu as un CAN 10bit, 2^10 =1024. Donc 1024 => 5V ; 1=> ???V soit 0.0048828... */

void main(void)
{
float AN0;
ADCON0=1;
ADCON1=0x8E;

ADCON0bits.GO_DONE=1;
while(ADCON0bits.GO_DONE)
AN0=(float)ADRES*q;
}

J'ai enlevé la boucle infinie, sinon le programme, resterais toujours dans cette boucle...

Si tu as besoin d'aide pour autre choses ou d'autres precisions ;) demande je pourrais peu etre d'expliquer quelques lignes

bonne programmation

Nico
2
Mkv Messages postés 8 Statut Membre 9
 
"ADCON1=0x8E;
/* soit 1000 1110; le premier 1 sert a justifier a droite. Le E sert a configurer les pins. */ "

la justification ne se fait pas dans ADCON2 ?
2

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Nico
 
Hello,

Tu as de la chance j'ai passé une partie de ma journée dessus je t'ecris un post tout propre dans l'heure ;)

Nico
1
Biggie
 
Bonjour,

je viens de voir le programme que t'as envoyé à mvk et tu m'as bien l'air de comprendre les programmations sous PCW.Tu peux m'expliquer les differents registres du pic 18f4520.?et à quoi ils servent?Merci.
0
Mkv Messages postés 8 Statut Membre 9
 
ah super :)
J'attend avec impatience :)
1
Nico
 
J'avais pas vu ta reponse,

je te propose de t'y repondre demain ;)

As tu la datasheet du 18f4520 ? ( si non prend sur le site de microchip) il y a souvent beaucoup d'aide. mais tu aura la reponse demain promi

2:40 << tu es un fou de codage xD

Nico
1
Nico
 
Avant d'aller me coucher, je reflechissais;

quand j'utilise le premier code, je me suis apperçu qu'effectivement, il y avait un soucis entre la valeur sur le CAN et la valeur qu'il me donne.

A regarder le code, en effet il y a un soucis, on ne justifie pas ni rien. Donc oui il doit manquer il ligne ;) et donc tu le devine la definition du registre 2, j'y reviendrais dessus demain :)

Veux tu mon Mp sa sera peut etre plus simple ?

Nico
1
Mkv Messages postés 8 Statut Membre 9
 
oui en effet j'aimerai bien ton mp :) se sera plus simple ^^

merci
0
KoKo- Messages postés 8 Statut Membre 1
 
Apres multiple test, il y un bien un probleme dans le premier code, on dira qu'il prend les bits aléatoirement, mieux vaut prendre le second ;)

Résolu ?
1
mike
 
Bonjour,
je dois realiser un projet qui consiste a extraire le courant harmonique a travers une charge reliée a un reseau monophasé, puis triphasé. L extraction sera faite de 2 facon, d une a travers un filtre numerique, l otre par un filtre analogique, pour faire la comparaison des 2 resultat. Le filtre analogique comprtera de nbeux can, kon doit realiser a travers le pic16f877, mais mon pb est ke je debute avec le pic et dc je ne c pas comment pgmmer celui ci, en tt k pour la conversion.est ce ke ce st les meme ligne de code ke 18f ?? pourriez vous me donner un petit coup de main pour le code ??merci
1
Mkv Messages postés 8 Statut Membre 9
 
j'aurrai surement d'autres questions par la suite, mais la j'ai compris le principal :D

merci en tout cas ^^
0