Bonjour,
Je débute en électronique et j'essaie de comprendre le fonctionnement des microcontrôleurs PIC, mais je bloque depuis plusieurs semaines sur la conversion analogique/numérique. Pouvez-vous me mettre sur la voie?
Je travaille avec un PIC 16F676 (data sheet : http://ww1.microchip.com/downloads/en/DeviceDoc/40039F.pdf (http://ww1.microchip.com/downloads/en/DeviceDoc/40039F.pdf)) sous MPLAB (en C).
Pour tester la conversion de signaux analogique en numérique, je voudrais simplement allumer deux LED en fonction de la valeur lue par le convertisseur... mais rien ne se passe : apparemment la conversion n'a pas lieu, mais je ne comprend pas pourquoi.
Voici mon code, pouvez-vous m'aider s'il vous plaît?
#include <xc.h>
#define _XTAL_FREQ 4000000
void main(void) {
//Selection canal Analog. : AN0
ADCON0bits.CHS0=0;
ADCON0bits.CHS1=0;
ADCON0bits.CHS2=0;
// Fréq opération= OSC/16
ADCON1bits.ADCS0=1;
ADCON1bits.ADCS1=0;
ADCON1bits.ADCS2=1;
ADCON0bits.VCFG=0;//Vref = VDD
//Format Resultat Convetion
ADCON0bits.ADFM=1;//justif. droite
//Selection A/D pins
ANSELbits.ANS0=1;//PIN 0 analog.
ANSELbits.ANS1=0;//PIN 1 digital
// selction I/O pins
TRISAbits.TRISA0=1;//PIN 0 entée
TRISAbits.TRISA1=0;//PIN 1 sortie
TRISAbits.TRISA2=0;//PIN 2 sortie
PORTAbits.RA1=0;//LED pin 1 eteinte
PORTAbits.RA2=0;//LED pin 2 eteinte
unsigned int result=0;
while(1){
ADCON0bits.ADON=1;//initialiser Conv Analog-Num.
if (ADCON0bits.GO_DONE==0){
ADCON0bits.GO_DONE=1;//démarrer la conversion
}
while(ADCON0bits.GO_DONE=1){}// attendre que la conversion soit terminée
result=ADRESL; //resultat sur 8 bits
//Allumer LED 1 ou 2 en fonction du resultat
if (result>100){
PORTAbits.RA1=1;
PORTAbits.RA2=0;
}
else if (result<100){
PORTAbits.RA2=1;
PORTAbits.RA1=0;
}
}
return;
}
Bonjour olibou,
Je pratique pas MPLAB (en C), j'écris tout mes programmes an ASM, si tu veux je peux l'écrire an ASM, et t'expliquer la façon de faire
pour que tu le réécrive en C
A+
Bonjour Curiosus et merci pour ta réponse.
Allons-y pour l'assembleur!
J'ai l'impression que la plupart des bidouilleurs de PIC programment en assembleur, ce sera peut être l'occasion de m'y mettre!
Merci ;D
Bonjour Olibou,
Non, une majorité de bidouilleurs ne codent pas les PICs en ASM.
Si tu utilises un petit 8 bits genre 16F84 très utilisé autrefois , ou même un 12F683 qui possède un ADC 10 bits (sujet évoqué récemment sur le forum), vu le "peu" de mémoire programme dont tu disposes, l'ASM est une obligation. C'est aussi le cas de ton 16F676 (1K de flash...) L'ASM est aussi incontournable si tu veux réaliser un petit fréquencemètre. L'ASM te permet de maîtriser complètement tes durées d'exécution.
L'ASM t'oblige cependant à te "farcir" la quasi totalité d'au moins quelques chapitres de la datasheet mais après tu sais ce que tu fais...en particulier la manière de configurer tous les bits de tous les registres...et y'en a un paquet !
Culturellement l'ASM , même celui des PICs (cf la détestation que Cyrob a vis à vis de son jeu d'instructions), ça ne me gêne pas, vu que j'en ai pissé des lignes de code ASM en Z80 fin des 70's , début des 80's.
Par contre dès que tu veux réaliser quelques calculs avec un minimum de précision, alors la bibliothèque de calcul en float du C est indispensable et là tu auras besoin du C et donc d'une mémoire programme plus conséquente, et donc d'un PIC mieux doté en flash. idem si tu veux utiliser les outils I²C, il vaut mieux utiliser les bibliothèques du C.
Pour ma part, j'utilise le Compilateur C de MikroElektronika qui est payant mais tu peux télécharger le complilateur mikroC gratos (limité à 1K de mémoire programme) et regarder la bibliothèque ADC. Il te donnera des exemples en C de configuration des registres que tu pourras convertir en MPLAB pour tes besoins propres.
https://www.mikroe.com/mikroc-pic
Tu peux aussi télécharger les tutos en ASM de BigOnOff (le tuto 16F87X en particulier qui contient les ADC) vu que c'est en français et particulièrement bien détaillé et avec de nombreux exemples
https://www.abcelectronique.com/bigonoff/organisation.php?par=09f52
Bonne journée.
Yffig
Bonjour Yffig,
Le PIC que j'ai choisi comporte effectivement peu de mémoire flash mais je l'utilise essentiellement à des fins "pédagogiques" pour tenter de comprendre comment programmer un PIC.
Pour mes "vrai" projets, je tiendrais compte de ton conseil et choisirais un PIC mieux doté en mémoire.
je vais tester MicroC pour voir si j'y trouve une solution à mon énigme...
Merci pour ta réponse!
Bonjour olibou, et tout le forum,
J'ai fini le programme, je le teste et le mets vers les 1 heure 30 du matin, en France métropolitain, (avec un schéma) chose que tu aurais du faire.
Je vais pas te dire qu'un langage est mieux qu'un autre, c'est à toi de voir, personnellement je suis pas d'accord de payer une licence pour programmer.
Je me suis constitué une bibliothèque que j'ai écrit en ASM, ce qui me permets de la modifier à tous moment.
Revenons à ton programme, J'ai mis 3 led rouge, vert, bleu, avec un potentiomètre, si tu tournes le potentiomètres
elles s’allumeront en fonction de la position de celui-ci..
Si tu vois une autre idée ?
A+
Bonjour Curiosus,
C'est vraiment super merci!
C'est vrai que j'aurais pu poster un schéma... :-[ mais ta proposition correspond tout à fait à ce que je voudrais faire. J'espère que quand j'aurais compris comment fonctionne un convertisseur A/N, j'arriverais à utiliser différents capteurs... mais une étape à la fois.
J'ai commencé à lire les ressources de BigOnOff dont Yffig à posté le lien : c'est vraiment très bien fait. J'y ai déjà trouvé plein d'éclaircissements et je n'en suis qu'au début ;D
En tout cas merci
Bonsoir,
Je ne vais pas faire de long discourt vu l'heure tardive, voila j'ai fini, testé, sa fonctionne, après on pourras le réécrire en MPLAB (en C)
De plus pas besoin de quartz, car ce pic possède un oscillateur interne de 4 Mhz, il suffit juste de l'activer, chose que j'ai faite.
Le code pour les intéressés
list p=16f676 ; list directive to define processor
#include <p16F676.inc> ; processor specific variable definitions
errorlevel -302 ; suppress message 302 from list file
__CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;*************************************** assignations *****************************************
#DEFINE led1 PORTC,0 ; led rouge
#DEFINE led2 PORTC,1 ; led bleu
#DEFINE led3 PORTC,2 ; led vert
;**********************************************************************************************
CBLOCK H'20'
loop1 :1
loop2 :1
loop3 :1
res8 :1
res16 :1
res24 :1
ENDC
;***********************************************************************************************
ORG H'0' ; reset au démarrage
goto debut ;
ORG H'4' ; lieux des interruptions
retfie
;***********************************************************************************************
debut
call 0x3FF ;
;***********************************************************************************************
BANKSEL OSCCAL ; passer en bank 1
;***********************************************************************************************
movwf OSCCAL ;
;************************** configuration du registre ANSEL en bank 1 **************************
movlw B'00000001' ; mode numérique : 13(RA0),
movwf ANSEL ; mode analogique : 12(RA1), 11(RA2), 10(RC0),9(RC1),8(RC2), 7(RC3)
;************************ configuration du registre ADCON1 en bank 1 **************************
movlw B'00100000' ; b6 = ADCS2 choisir la fréquence de fonctionnement du convertisseur
movwf ADCON1 ; b5 = ADCS1 en fonction de la fréquence d'horloge du PIC
; b4 = ADCS0
;
;************************ configuration du registre OPTION_REG en bank 1 ***********************
movlw B'10000000' ; résistances hors service sur PORTA
movwf OPTION_REG ;
;******************** configuration des registres TRISA & TRISC en bank 1 **********************
movlw B'00000001' ; configure les pattes de TRISA
movwf TRISA ; 13(RA0),12(RA1),11(RA2),4(RA3),3(RA4),2(RA5)
movlw B'00000000' ; configure les pattes de TRISC
movwf TRISC ; 10(RC0), 9(RC1), 8(RC2), 7(RC3), 6(RC4), 5(RC5)
; alimentation sous 5 volts patte 14 mettre au moins
;***********************************************************************************************
BANKSEL ADCON0 ; passer en bank 0
;***********************************************************************************************
; b7 = ADFM détermine si le résultat de la conversion
; sera justifié à droite = 1 ou à gauche = 0
; b6 = VCFG 1 = VREF pin, 0 = VDD
movlw B'00000000' ;
movwf ADCON0 ;
;************************* configuration du registre CMCON en bank 0 **************************
movlw B'00000111'
movwf CMCON ; éteindre le comparateur
;*********************** configuration du registre INTCON en bank 0,1 **************************
clrf INTCON ; désactivé les interruptions
;***********************************************************************************************
reset
clrf PORTA
clrf PORTC
;***********************************************************************************************
; Pour avoir un état bas, milieu, haut, on divise par 3 (255 /3) = 85
; état bas de 0 à 85, état milieu de 86 à 170, état haut 171 à 255
;********************************* "sélection du canal(RA0)" ***********************************
call canal_an0 ;
;***********************************************************************************************
control_1
call numériser ; lancer la conversion
movf res8,W
sublw D'85'
btfss STATUS,C
goto control_2
bsf led1
bcf led2
bcf led3
goto control_fin
control_2
movf res8,W
sublw D'170'
btfss STATUS,C
goto control_3
bcf led1
bsf led2
bcf led3
goto control_fin
control_3
bcf led1
bcf led2
bsf led3
control_fin
call _300ms ; petite pause
goto control_1
;***********************************************************************************************
;**************************** "canaux des convertiseurs numériques" *****************************
;***********************************************************************************************
canal_an0
bcf ADCON0,CHS0 ; 000 (RA0)
bcf ADCON0,CHS1
bcf ADCON0,CHS2
return
;***********************************************************************************************
canal_an1
bsf ADCON0,CHS0 ; 001 (RA1)
bcf ADCON0,CHS1
bcf ADCON0,CHS2
return
;***********************************************************************************************
canal_an2
bcf ADCON0,CHS0 ; 010 (RA2)
bsf ADCON0,CHS1
bcf ADCON0,CHS2
return
;***********************************************************************************************
canal_an3
bsf ADCON0,CHS0 ; 011 (RA3)
bsf ADCON0,CHS1
bcf ADCON0,CHS2
return
;***********************************************************************************************
canal_an4
bcf ADCON0,CHS0 ; 100 (RC0)
bcf ADCON0,CHS1
bsf ADCON0,CHS2
return
;***********************************************************************************************
canal_an5
bsf ADCON0,CHS0 ; 101 (RC1)
bcf ADCON0,CHS1
bsf ADCON0,CHS2
return
;***********************************************************************************************
canal_an6
bcf ADCON0,CHS0 ; 110 (RC2)
bsf ADCON0,CHS1
bsf ADCON0,CHS2
return
;***********************************************************************************************
canal_an7
bsf ADCON0,CHS0 ; 111 (RC3)
bsf ADCON0,CHS1
bsf ADCON0,CHS2
return
;***********************************************************************************************
numériser
bsf ADCON0,ADON ; on lance l’acquisition (charge du condensateur)
nop
nop ; tempo pour charge du condensateur
nop
bsf ADCON0,GO ; lancer la conversion A/D
btfsc ADCON0,GO ; si le bit GO est à 1 on va à la ligne 1
goto $-D'1' ; conversion n'est pas terminer
bcf ADCON0,ADON ; fin de conversion, éteindre convertisseur
movf ADRESH,W ; sauver la valeur qui vient d'être numérisé
movwf res8 ; dans la variable "res8"
return
;***********************************************************************************************
_300ms
movlw D'51'
movwf loop1
movlw D'12'
movwf loop2
movlw D'4'
movwf loop3
decfsz loop1,F
goto $-D'1'
decfsz loop2,F
goto $-D'3'
decfsz loop3,F
goto $-D'5'
return
;***********************************************************************************************
End
Fichiers joints : fichier schéma, fichier code, fichier code compilé
A+
Bonjour,
Super, ça fonctionne parfaitement!
Par contre l'assembleur, pour moi, c'est de l'hébreu!
Il ne me reste plus qu'a apprendre l'assembleur pour essayer de trouver où est le problème dans mon code en C...
Je regarde ça à tête reposée ce soir...
Bonne journée!
Olibou
Bonjour olibou, et tout le forum,
Tu fais ce que tu veux, si l'assembleur ne te convient pas, ne prends pas, moi j'aime bien l'assembleur, mais c'est moi.
Il est conseillé d'apprendre un minimum d'assembleur, ça rends service quand une fonction n'existe pas, ou si tu veux de la vitesse pour ton code.
Monsieur Bigonoff et comme Électro-Bidouilleur ils ont fait quelle que chose de super, retransmettre leurs connaissances.
Merci mille fois à eux.
Je viens de regarder ton code en C, et je m'aperçois que tu n'as pas configuré CMCON,
1)ça veux dire que tes comparateur ne sont pas éteint
2) ADFM et à 1 alors qu'il est plus simple de le mettre à 0, et récupérer le résultat dans ADRESH
Bon à suivre ......
A+
Bonjour à tous,
Je n'ai absolument rien contre l'assembleur, et je te suis également très reconnaissant pour le temps que tu consacre à mes questions :D
c'est juste que je suis au tout début de mon apprentissage (autant en électronique qu'en programmation) et j'ai déjà passé pas mal de temps à déchiffrer la datasheet et à comprendre comment coder ces quelques lignes en C... qui ne fonctionnent pas d'ailleurs!
Mais j'ai bien compris l’intérêt de l'assembleur et je vais essayer de m'y mettre, mais au rythme ou j'apprends, ça va peut être prendre quelques semaines!
La première étape va être de creuser la question du comparateur (dont je ne connais pas la fonction :-[) pour voir si c'est l'origine de mon problème.
Peut être que si j'utilise une autre broche en entrée cela va contourner le problème?
Je vais faire quelques essais... et je vous tiens au courant! (5A maxi ;D)
A+
Olibou
Bonsoir,
CitationÉcrit par olibou : Peut être que si j'utilise une autre broche en entrée cela va contourner le problème ?
Toutes ses pattes peuvent être configuré en convertisseur analogique RA0, RA1, RA2, RC0, RC1, RC2, RC3 (voir mon code en ASM)
D'après le datasheet en page 41, le comparateur agit seulement sur les pattes : RA0, RA1, RA2.
Pour ne pas utiliser le comparateur, il faut mettre
CMCON = B'00000111' , ce qui te permet de les utiliser comme convertisseur analogique.
Voir extrait du datasheet ci-dessous
A+
Bonjour à tous,
J'ai enfin trouvé ce qui n'allait pas dans mon code : un bête erreur de débutant qui n'a pas relu attentivement son programme :-[
Ça se passe ici : while(ADCON0bits.GO_DONE=1){}// attendre que la conversion soit terminée
Il fallait écrire "==" et non "=" ( c'est une condition et non une valeur assignée)
J'en ai profité pour faire quelques test :
L'activation -ou non- du comparateur (CMCON) n'a pas d'impact (ça fonctionne dans les deux cas)
La broche 3 (RA3 - MCLR) ne fonctionne pas comme sortie, bien que le MCLR soit désactivé dans les bits de configuration... si quelqu’un à la clé du mystère, je suis preneur.
L'autre problème qu'il y a dans mon programme, c'est qu'au changement de valeur (lorsque le registre ADRESL atteint la valeur 100), j’éteins la LED allumée pour allumer l'autre à son tour :
if (result>100){
PORTAbits.RA1=1;//allume la LED1
PORTAbits.RA2=0;//éteint la LED 2
Et c'est là que ça bloque... je ne peux pas donner deux instructions en même temps. Le même problème se pose si j'essaie d'allumer les deux LED en même temps.
par contre, si je ne donne qu'une seule instruction, ça fonctionne :
if (result<100){
PORTAbits.RA1=1;}//allume la LED1
if (result>=100){
PORTAbits.RA1=2;}//allume la LED2
Ce qui est étrange, c'est que quand je change progressivement la valeur ADRESL à l'aide du potentiomètre (de 0 à 255 par exemple), la LED1 devrait s'allumer en premier, puis la LED 2, mais sans éteindre la LED 1 puisque je n'ai pas donné l'instruction de l'éteindre... hors elle s'éteint!
Notez que ce sont des questions qui n'ont pas une grande importance... ce n'est même pas un vrai projet mais un petit test pour essayer de comprendre, donc, si la réponse vous paraît évidente et simple, n'hésitez pas à partager, mais ne passez pas des nuits blanches juste pour ça!
En tous cas, merci beaucoup pour vos conseils et pour les liens!
A+,
Olibou
Bonsoir,
Y aurait pas une erreur dans ta ligne ? disons au moins dans ce que tu nous soumets, (pas forcément dans ton code... ;) )
"PORTAbits.RA1=2;}//allume la LED2"
Bonne soirée
Yffig
Bien vu :-[
C'est parceque je code en trinaire ;D