[Programmation] PIC18F4431 et ADC
Répondre à la discussion
Affichage des résultats 1 à 21 sur 21

PIC18F4431 et ADC



  1. #1
    invite6374ce44

    PIC18F4431 et ADC


    ------

    Bonjour à tous !

    J'ai besoin de vous une fois de plus ! :/

    En effet, j'aimerais bien faire un test tout basique à l'aide de mon PIC18F4431 et d'un simple potentiomètre.

    Ce que je veux faire, c'est utiliser le Port AN0 pour lire la valeur du potentiomètre, de stocker cette valeur dans une variable, et d'ensuite, afficher cette variable sur un LCD.
    Et bien sûr, on verrais la valeur changer en temps réel lorsque l'on tourne le potentiomètre.

    J'ai déjà épluché quelque doc par rapport à ça, j'ai même essayé de regarder des programmes d'exemples, voir comment setup le bordel.

    J'ai essayé un petit bout de code, mais il ne se passe rien niveau Affi, par contre pas d'erreurs à la compilation.

    Je vais vous mettre le bout de code ci-dessous, et peut être que à partir de ça vous pourrez m'aiguiller !

    Code:
    void main(){
        LCD lcd = { &PORTC, 2, 3, 4, 5, 6, 7 }; // PORT, RS, EN, D4, D5, D6, D7 | Attribution des pins LCD
        LCD_Init(lcd);
    
        
            
            unsigned short result;
            TRISA0 = 1; // Set RA0 as input
     
            /*  PCFG3:PCFG0 (ADCON1 bit 3-0) = 1110 -> AN0 only will analog and other 12 channels will digital 
                VCFG0=0,VCFG1=0 -> Vref+ = VDD and Vref- = VSS    
            */
            ADCON1 = 0b00001110;
            
            /* CHS3:CHS0 (ADCON0 bit 5-2) = 0000  -> Channel 0 */
            ADCON0 = 0b00000000;
            
            /* 16Tosc conversion clock, 6Tad acquisition time, ADC Result Right Justified */
            ADCON2 = 0b10011101;
            
            ADCON0 = ADCON0 | 1;    // ADCON0.ADON = 1
            
            __delay_us(5);           // acquisition delay of 4.6 us
            
            ADCON0 = ADCON0 | 10;   // ADCON0.GODONE = 1
            
            while (ADCON0||10);0     // wait till GODONE bit is zero
            
            result = ADRES;         // Read converted result, ADRESH:ADRESL -> 16 bit register
           
            sprintf(s, "POT= %u", result);    
            LCD_Set_Cursor(1,1);
            LCD_putrs(s);
    
            //  process the result
        
    }
    Je vous remercie encore grandement à l'avance de votre considération.

    Bien à vous, Tom.

    (P.S : N'oubliez pas que je ne suis encore qu'un débutant )

    -----

  2. #2
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    while (ADCON0||10);0 // wait till GODONE bit is zero
    Que fait ce 0 après le ; ?
    Je ne connais pas trop les registres de ton PIC, mais tu ne devrais pas plutôt utiliser un et bit à bit (&) plutôt qu'un OU logique (||)

    De plus ta boucle while devrait être suivie d’accolades si tu veux que plusieurs instructions soient exécutées dans la boucle.

  3. #3
    invite6374ce44

    Re : PIC18F4431 et ADC

    Je ne sais pas du tout à vrai dire ...
    Je sais que ce n'est pas "professionnel" de ma part, mais j'ai trouvé ce bout de code tout fait, je l'ai donc copié collé sans trop comprendre.. , j'ai simplement rajouté du code pour gérer l'afficheur LCD..

    Et ce code la a été programmé pour un PIC18F4550, je ne sais pas si cela influe également.

    Pourquoi le & bit à bit serait plus judicieux ? (désolé je ne m'y connait pas trop )

    Je pense que le programme bloque justement à partir de ce fameux while, car si par exemple je met une instruction pour afficher un message lambda sur l'Affi juste avant cette ligne, ca fonctionne, par contre si je la met après il ne se passe rien..

    Merci d'essayer de m'aider en tout cas !!

  4. #4
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    Je répète que je ne connais pas ces PICs, mais ce devrait être quelque chose de ressemblant davantage à:
    Code:
    int i;
    for (i =  0; i < 10; i++)   // pour afficher 10  fois la valeur mesurée
    {
        ADCON0 = ADCON0 | 0b10;   // ADCON0.GODONE = 1    Début de conversion    
        while (ADCON0 & 0b10);     // wait till GODONE bit is zero    Attente de fin de conversion
            
        result = ADRES;         // Read converted result, ADRESH:ADRESL -> 16 bit register
           
        sprintf(s, "POT= %u", result);    
        LCD_Set_Cursor(1,1);
        LCD_putrs(s);
        delay(10);  // ou autre instruction qui fait une tempo de 1 seconde
    }
    ça devrait afficher 10 fois la valeur analogique, avec un intervalle de 10 secondes.

  5. A voir en vidéo sur Futura
  6. #5
    invite6374ce44

    Re : PIC18F4431 et ADC

    J'ai donc essayé ce que tu m'as proposé ce qui donne :
    Code:
    int main(void) {
        LCD lcd = { &PORTC, 2, 3, 4, 5, 6, 7 }; // PORT, RS, EN, D4, D5, D6, D7 | Attribution des pins LCD
        LCD_Init(lcd);
        
        unsigned short result;
            TRISA0 = 1; // Set RA0 as input
     
            /*  PCFG3:PCFG0 (ADCON1 bit 3-0) = 1110 -> AN0 only will analog and other 12 channels will digital 
                VCFG0=0,VCFG1=0 -> Vref+ = VDD and Vref- = VSS    
            */
            ADCON1 = 0b00001110;
            
            /* CHS3:CHS0 (ADCON0 bit 5-2) = 0000  -> Channel 0 */
            ADCON0 = 0b00000000;
            
            /* 16Tosc conversion clock, 6Tad acquisition time, ADC Result Right Justified */
            ADCON2 = 0b10011101;
            
    int i;
    for (i =  0; i < 10; i++)   // pour afficher 10  fois la valeur mesurée
    {
        ADCON0 = ADCON0 | 0b10;   // ADCON0.GODONE = 1    Début de conversion    
        while (ADCON0 & 0b10);     // wait till GODONE bit is zero    Attente de fin de conversion
            
        result = ADRES;         // Read converted result, ADRESH:ADRESL -> 16 bit register
           
        sprintf(s, "POT= %u", result);    
        LCD_Set_Cursor(1,1);
        LCD_putrs(s);
        __delay_ms(1000);  // ou autre instruction qui fait une tempo de 1 seconde
    }
    }
    Mais lorsque je lance le programme sous simulation, il n'y a toujours rien qui s'affiche sur l'Afficheur LCD ...

    Je suis perplexe car je ne suis pas encore très familier avec tout cela .. ^^'

  7. #6
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    Il n'y a pas un debogueur qui permet d'exécuter le programme pas à pas?

    Sinon, à l'ancienne, on met des print vers la console pour vérifier à quel endroit on est passé dans le programme.

  8. #7
    micka_ch

    Re : PIC18F4431 et ADC

    Bonsoir,

    Je crois qu'il manque l'enable du périph ADC :

    Genre dans l'init :
    Code:
    ADCON0 |= 0x01;
    bit 0:
    ADON:
    A/D On bit
    1 = A/D converter module is operating
    0 = A/D converter module is shut off and consumes no operating current

  9. #8
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    Oui, je n'avais pas vérifié car cette ligne était présente dans le programme original.
    Du coup, pourquoi l'avoir retirée? Il ne fallait pas modifier la 1ère partié.

  10. #9
    invite6374ce44

    Re : PIC18F4431 et ADC

    Bonjour à vous, pour cette ligne, je ne sais pas où la mettre...

    Et c'est pas celle qui est dans le for (en rouge) ? Si c'est le cas je ne l'ai pas enlevée :
    Code:
    for (i =  0; i < 10; i++)   // pour afficher 10  fois la valeur mesurée
    {
        ADCON0 = ADCON0 | 0b10;// ADCON0.GODONE = 1    Début de conversion    
        while (ADCON0 & 0b10);     // wait till GODONE bit is zero    Attente de fin de conversion
            
        result = ADRES;         // Read converted result, ADRESH:ADRESL -> 16 bit register
           
        sprintf(s, "POT= %u", result);    
        LCD_Set_Cursor(1,1);
        LCD_putrs(s);
        __delay_ms(1000);  // ou autre instruction qui fait une tempo de 1 seconde
    }

  11. #10
    micka_ch

    Re : PIC18F4431 et ADC

    Bonjour,

    Non ce n'est pas la même ligne de code, le bit 0 c'est pour enable le périphérique, et le bit 1 c'est pour démarrer une nouvelle conversion.

    Code:
        ADCON0 = ADCON0 | 0x01; // ADCON0.ADON = 1 : à exécuter une seul foi à l'initialisation
        .
        .
        .
        .
        ADCON0 = ADCON0 | 0x02; // ADCON0.GODONE = 1 : à exécuter a chaque foi qu'on veut faire une conversion
    Salutations

  12. #11
    invite6374ce44

    Re : PIC18F4431 et ADC

    Bonjour micka_ch !

    C'est bon !! J'ai simplement rajouté cette ligne la dans mon init, et j'arrive à lire la valeur qui s'affiche sur mon LCD !!

    Merci beaucoup de ton aide ainsi que a tous les autres!

    Je me posais juste une dernière question, c'est que sur l'Affi LCD, quand je fais varier mon potar de 0% a 100%, la valeur va de 0 a 93
    Et je me demandais, pourquoi 93 ? Je ne sais pas a quoi cela correspond.. :/

  13. #12
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    je ne vois pas dans ton programme à quel endroit tu fais le calcul pour avoir le résultat en %. Du coup, je ne comprends pas comment ça peut t'afficher 93.

    Il faudrait également le schéma de câblage de ton installation. Dans la doc, il est spécifié que l'impédance maxi de la source qui attaque l'ADC doit être de 2,5 kohms. En clair il ne faut pas que la valeur de ton potentiomètre dépasse cette limite pour avoir une mesure correcte.
    Dernière modification par Jack ; 27/04/2018 à 11h25.

  14. #13
    invite6374ce44

    Re : PIC18F4431 et ADC

    Ah oui je ne l'avais pas fait au temps pour moi.

    J'ai mis la valeur de la résistance comme il faut, et j'ai maintenant une valeur qui va de 0 à 1023.

    Par contre lorsque je veux mettre ça sous la forme d'un pourcentage, j'effectue ce calcul : (result/1023)*100
    Mais sur l'afficheur je n'ai que "1" affiché quand le potar est a fond, sion c'est que des "0".

    Code:
    result = ADRES;         // Read converted result 
        float conv = (result/1023)*100;
        sprintf(s, "POT= %1.1f", conv);    
        LCD_Set_Cursor(1,1);
        LCD_putrs(s);

  15. #14
    antek

    Re : PIC18F4431 et ADC

    Peut-être (result*100)/1023 ?
    Dernière modification par antek ; 27/04/2018 à 12h06.

  16. #15
    invite5a48ffd1

    Re : PIC18F4431 et ADC

    Bonjour,

    Code:
    float conv = (result/1023)*100;
    Quel drôle de manière d'écrire du C...

    Il faudrait écrire:
    Code:
    float conv;
    ...
    conv=(result/1023.0)*100.0; // sous réserve que result soit lui même un float...

  17. #16
    invite5a48ffd1

    Re : PIC18F4431 et ADC

    ou faire un typecasting explicite:
    Code:
    float conv;
    ...
    conv=(float)((result/1024)*100);
    Voir selon votre compilateur.

  18. #17
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    Citation Envoyé par Chtulhu Voir le message
    ou faire un typecasting explicite:
    Code:
    float conv;
    ...
    conv=(float)((result/1024)*100);
    Voir selon votre compilateur.
    Je pense que cette version ne donnera pas le bon résultat contrairement à ton message précédent. La division entière sera effectuée avant le cast en float.
    En revanche, je préfère la division par 1024 de cette dernière version à celle par 1023. C'est bizarre, je ne trouve aucune référence à la formule de conversion dans la doc du PIC.
    Dernière modification par Jack ; 27/04/2018 à 13h27.

  19. #18
    invite5a48ffd1

    Re : PIC18F4431 et ADC

    Vous avez raison Jack.
    Il faut impérativement mettre 1024.0 et 100.0 sinon ça ne fonctionnera pas, pour la raison que vous donnez.

  20. #19
    invite6374ce44

    Re : PIC18F4431 et ADC

    Bonjour à tous, après quelques tests effectués ce matin, j'ai bien mis les bonnes valeurs en float, et je n'ai pas oublié de mettre 100.0 et 1023.0.

    Merci à tous pour votre aide, tout marche niquel, je pense que ce topic peut être considéré comme résolu.

  21. #20
    micka_ch

    Re : PIC18F4431 et ADC

    Bonjour,

    Encore 2 petits conseils au passage.

    Attention, la manipulation des floats avec des "petits" microcontrôleur 8bit consomme plus de mémoire (RAM et FLASH) que les nombres représentés en virgule fixe. Le temps d'exécution est également plus important. En plus de toutes les problématiques d'arrondi, de conversion, précision, exceptions et j'en passe.

    La fonction sprintf() est assez monstrueuse au niveau taille de code. Sur un STM32L0, elle occupait pas moins de 16k de mémoire... De plus, elle est "bannie" par guideline MISRA :

    Rule 16.1 (required): Functions shall not be defined with a variable number of arguments.
    Rule 20.9 (required): The input/output library <stdio.h> shall not be used in production code.

    Salutations

  22. #21
    Jack
    Modérateur

    Re : PIC18F4431 et ADC

    Tout à fait d'accord, il vaut mieux travailler en entier. Ca n'est pas compliqué: comme évoqué plus haut, il suffit de commencer par multiplier d'abord par 100, puis de diviser par 1024 (ou plutôt de décaler 10 fois à droite). S'il y a un point décimal, il peut être géré uniquement au niveau de l'affichage.
    La conversion d'entier en ascii est moins gourmande avec la fonction itoa si elle existe sur ce compilateur.

Discussions similaires

  1. Oscillateur interne PIC18F4431
    Par invitead51e543 dans le forum Électronique
    Réponses: 22
    Dernier message: 17/09/2015, 12h06
  2. PWM pour servomoteur PIC18F4431
    Par invite3df4a7fe dans le forum Électronique
    Réponses: 8
    Dernier message: 27/02/2015, 19h35
  3. PIC18F4431 : Power Control PWM
    Par LTHOMAS dans le forum Électronique
    Réponses: 0
    Dernier message: 22/07/2009, 12h34
  4. Interruptions sur PIC18F4431
    Par invitef8253c81 dans le forum Électronique
    Réponses: 3
    Dernier message: 17/07/2008, 00h25
  5. Interruption et PIC18F4431
    Par invitec7ced588 dans le forum Électronique
    Réponses: 1
    Dernier message: 09/03/2006, 15h01
Dans la rubrique Tech de Futura, découvrez nos comparatifs produits sur l'informatique et les technologies : imprimantes laser couleur, casques audio, chaises gamer...