Répondre à la discussion
Affichage des résultats 1 à 12 sur 12

PIC 16f887 et MCP3208



  1. #1
    lexu

    Angry PIC 16f887 et MCP3208

    Bonjour à tous,

    Mon nom est Xavier et cette année j'ai repris mes études pour effectuer une licence pro en alternance, dans le domaine de l'informatique industrielle et des automatismes.
    J'ai commencé la programmation en C cette année et j'avoue avoir quelques difficultées, notament pour ce nouveau projet que mon entreprise m'a demandé de réaliser.
    Ce projet consiste, avec un PIC16f887, de réaliser un convertion analogique numérique, avec le MCP3208 (ADC sur 112bits), qui communique avec le PIC via le module SPI, et d'afficher le résultat sur un écran lcd utilisant le module SPI également.

    Le problème que je rencontre est dans la réception des données reçue par le PIC. En effet en recopiant l'etat de sortie de L'ADC sur les leds du PORTB et du PORTD, je me suis apercue qu'il me manquait le 12ème bit(MSB).
    J'ai tester plusieurs configuration du mode SPI mais toujours pas de 12 éme bit.

    Cela fait plusieurs jours que j'essai de récupérer ce bit manquant mais sans succé.

    Voici mon code dans son intégralité. J'espère que vous y trouverez la ou les erreurs que j'ai commis pour me les signaler.

    Je compte sur vous, je suis au fond, et merci d'avance à tous ceux qui prendront le temps de lire mon roman.

    PS : je travaille avec la carte de developpement easy pic6 de chez MikroElectronika et le compilateur MicroC pro.

    voici mon code:
    Code:
    //-------------------Port Expander module connections lcd----------------------
    sbit  SPExpanderCS  at RA2_bit;
    sbit  SPExpanderRST at RA3_bit;
    sbit  SPExpanderCS_Direction  at TRISA2_bit;
    sbit  SPExpanderRST_Direction at TRISA3_bit;
    /**********************ADC module connections**********************************/
    sbit Chip_Select at RC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
    /**********************Déclaration des variables*******************************/
    unsigned short value1,value2,value3,res,buffer = 0;
    unsigned int value;
    char *text;                     // variable pour l'affichage du texte
    bit oldstate;
    int i,b;
    unsigned long tlong,ch;
    /**********************Déclaration des prototypes de fonctions*****************/
    void init_pic(void);
    void affichage (void);
    void convertion (void);
    void invertion (void);
    void Delay_us();
    void Delay_ms();
    unsigned short SPI1_Read(unsigned short buffer);
    void SPI1_Write(unsigned short data_);
    void SPI1_Init_Advanced(unsigned short master_slav,
                            unsigned short data_sample,
                            unsigned short clock_idle,
                            unsigned short transmit_edge);
    /**********************Initialisation du PIC***********************************/
    void init_pic()
    {
    ANSEL  = 0;                 // All AN pin as digital
    ANSELH = 0;                 // All AN pin as digital
    C1ON_bit = 0;               // Disable comparators
    C2ON_bit = 0;               // Disable comparators
    
    PORTA  = 0;                 // init value on PORTA
    PORTB  = 0;                 // init value on PORTB
    PORTC  = 0;                 // init value on PORTC
    PORTD  = 0;                 // init value on PORTD
    PORTE  = 0;                 // init value on PORTE
    
    TRISA  = 0b11110011;        // PORTA.2.3 are outputs others are inputs
    TRISB  = 0;                 // PORTB is output
    TRISC  = 0b11010110;        // PORTC 5.3.0 are outputs others are inpouts
    TRISD  = 0;                 // PORTD is output
    TRISE  = 0xf;               // PORTE is input
    Chip_Select = 1;            // Deselect ADC
    }
    /************************fonction de convertion********************************/
    void convertion()
    {
    SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4,     // Initialize SPI module
                       _SPI_DATA_SAMPLE_MIDDLE,
                       _SPI_CLK_IDLE_HIGH,
                       _SPI_LOW_2_HIGH);
    while(1)
    {
    Chip_Select_Direction = 0;             // Set CS# pin as Output
    Chip_Select = 0;                       // Select ADC
                       
    SPI1_Write(0x07);       // send the first byte configuratuion(single/CH7)5zero + start bit
    SPI1_Write(0xC0);       // send the second byte configuratuion(single/CH7)
    SPI1_Write(0x00);       // send the third byte with no effect
    
    value1 = SPI1_Read(buffer);   // LSB first
    
    value2 = SPI1_Read(buffer);   // MSB then
    
    Chip_Select = 1;             // Deselect ADC
    
    b = value1;
    invertion();
    value1 = res;
    b = value2;
    invertion();
    value2 = res;
    
    PORTB =  value1;             // Send LSB to PORTB
    PORTD =  value2;             // Send MSB to PORTD
    
    affichage();                 // Go to affichage
    oldstate = 0;
    }
    }
    /*****************************fonction d'affichage*****************************/
     void affichage ()
     {
     SPI_Lcd_Config(0);                        // Initialize Lcd over SPI interface
     SPExpanderCS = 0;                         // Select port expander
    
     SPI_Lcd_Cmd(_LCD_CLEAR);                  // Clear display
     SPI_Lcd_Cmd(_LCD_CURSOR_OFF);             // Turn cursor off
     
     value = value2;
     value = (value<<8) | value1;
        
        text  = "voltage:";                    // assign text to string
        SPI_LCD_Out(1,1,text);                 // print string a on LCD, 2nd row, 1st column
    
        tlong = (long)value * 5000;            // covert adc reading to milivolts
        tlong = tlong / 4095;                  // 0..4095 -> 0-5000mV
    
        ch    = tlong / 1000;                 // extract volts digit
    
        SPI_LCD_Chr(1,9,48+ch);               // write ASCII digit at 1st row, 9th column
        SPI_LCD_Chr_CP('.');
    
        ch    = (tlong / 100) % 10;           // extract 0.1 volts digit
        SPI_LCD_Chr_CP(48+ch);                // write ASCII digit at cursor point
    
        ch    = (tlong / 10) % 10;            // extract 0.01 volts digit
        SPI_LCD_Chr_CP(48+ch);                // write ASCII digit at cursor point
    
        ch    = tlong % 10;                   // extract 0.001 volts digit
        SPI_LCD_Chr_CP(48+ch);                // write ASCII digit at cursor point
        SPI_LCD_Chr_CP('V');
    
        Delay_ms(1);
        oldstate = 0;
        SPExpanderCS = 1;                      // Deselect port expander
     }
     /****************************swap byte****************************************/
     void invertion ()
     {
      res = 0;
      for ( i = 0; i < 8; ++i)
          {
          res = (res << 1);
          res |= (b & 1);
          b = (b >> 1);
          }
     }
    /********************** Programme principal ***********************************/
    void main()
    {
     init_pic();        // mise en situation du PIC
     oldstate = 0;
     //do{
        //if (Button(&PORTE, 0, 10, 1)) oldstate = 1;
        //if (oldstate && Button(&PORTE, 0, 10, 0))
           {
           convertion();
           //oldstate = 0;
           }
     //}while(1);
    }
    Merci encore a vous tous pour votre patience et votre symphatie.

    -----


  2. Publicité
  3. #2
    vede

    Cool Re : PIC 16f887 et MCP3208

    Bonjour,

    et pourquoi pas utliser l'ADC 10bits intégré dans le PIC???

    sinon t'es sur des V qui rentrent?
    qu'il sont bien capables de mettre à 1 le douzième bit de l'ADC externe?

    vede
    ;O]
    Dernière modification par vede ; 25/03/2010 à 05h13.

  4. #3
    lexu

    Re : PIC 16f887 et MCP3208

    Pour mon projet final qui consiste à mesurer des quantitées d'ions dans un échantillon de sang j'ai vraiment besoin des 12 bits, car les niveaux des tensions à mesurer sont vraiment très faible.
    Pour l'instant je simule une électrode avec un potentiomètre de 1K ohm max, ce qui fait varier mon Vref de 0V a 5V.

  5. #4
    lexu

    Re : PIC 16f887 et MCP3208

    Petit oublie, merci Vede

  6. #5
    inoxxam

    Re : PIC 16f887 et MCP3208

    Quelle est la plage de tensions que tu veux mesurer et avec quelle précision?

  7. A voir en vidéo sur Futura
  8. #6
    lexu

    Re : PIC 16f887 et MCP3208

    Pour mon projet final la plage de tension s'etant de 0 à 100 mv avec une précision de l'odre du microvolt.
    Pour l'instant je veux valider le bon fonctionnement de mon ADC MCP3208 alors je l'attaque avec une tension variant de 0 à 5v avec un vref de 5v également.
    Dans ces conditions, je ne récupère que 11 bits au lieu de 12 bits ce qui est très génant.

  9. Publicité
  10. #7
    lexu

    Re : PIC 16f887 et MCP3208

    Voici un lien de la datasheet de l'ADC.
    http://ww1.microchip.com/downloads/e...doc/21298c.pdf
    A la page 18 il y a les chronogrammes de fonctionnement de l'ADC, et j'ai l'impression que mon pic considère mon 12 bit comme le NULL BIT!!
    Quelqu'un à déjà rencontré ce problème?
    Merci d'avance pour vos reponses.

  11. #8
    Qristoff

    Re : PIC 16f887 et MCP3208

    Salut,
    le can est en config single-ended ou en différentielle ? t'as essayé l'autre config ?
    Tout existe, il suffit de le trouver...!

  12. #9
    RISC

    Re : PIC 16f887 et MCP3208

    Salut,

    Es-tu sur que ton PB ne vient pas de la liaison SPI (mauvais échantillonnage des données conduisant au décalage d'un bit ???

    Il y a 2 notes d'application utilisables avec ce produit :
    * AN703
    * AN719

    a+

  13. #10
    vede

    Cool Re : PIC 16f887 et MCP3208

    Citation Envoyé par lexu Voir le message
    Pour mon projet final la plage de tension s'etant de 0 à 100 mv avec une précision de l'odre du microvolt.
    Pour l'instant je veux valider le bon fonctionnement de mon ADC MCP3208 alors je l'attaque avec une tension variant de 0 à 5v avec un vref de 5v également.
    Dans ces conditions, je ne récupère que 11 bits au lieu de 12 bits ce qui est très génant.
    re ;O]

    pour info, une plage de 0-100mV en 12bits,
    cela fait une précision d'environ 100mV/4096 = 24,4µV...
    c'est pas 1µV... mais bon moi, même 24µV ça me fait déjà très "peur"...
    car très très difficilement réellement gérable dans la vrai vie...
    sans un MAXIMUM de filtrages, de moyennages, ...
    et encore...

    vede
    ;O]

    ps :
    je vais peut-être dire une connerie mais t'as pas pensé
    à amplifier le signal avant échantillonage?

    et désolé, j'ai pas la soluce pour le 12ém bit...
    Dernière modification par vede ; 26/03/2010 à 00h30.

  14. #11
    lexu

    Re : PIC 16f887 et MCP3208

    Salut à tous et merci pour votre aide.

    Pour répondre à Qristoff mon CAN est un single ended mais je n'ai pas testé le mode différentiel, par contre j'ai testé les 8 channels de mon CAN mais le résultat est le même, je n'ai toujours que 11 bit en reception.

    Ensuite pour répondre à RISC, merci pour les liens des AN je viens de les explorer et je pense trouver ma réponse dedans je vous tiendrez au courant.
    Sinon mon BP ne passe pas par la liaison SPI, il est relié directement au PIC.

    Enfin pour répondre à VEDE, je ne travaille pas encore sur mon projet final, mais tu as raison, une bonne amplification est un bon filtrage du signal sera oblgatoire pour traiter un signal si faible.

    En tous cas merci à vous tous pour vos réponse, je vais tester les codes trouver dans les AN et je vous tiens au jus.
    A+

  15. #12
    lexu

    Smile Re : PIC 16f887 et MCP3208

    C'est bon j'ai mes 12 bits, ça a été long et fastidieux mais ca y est. Enfin.

    Encore un grand merci à tous et voici le code pour ceux qui auront le même souci que moi.

    Code:
    void convertion()
    {
    SSPSTAT = 0x00;                        // SPI conf(
    SSPCON = 0b00100000;                   // enable SPI mode
    do
    {
    Chip_Select_Direction = 0;             // Set CS# pin as Output
    Chip_Select = 0;                       // Select ADC
    
    SSPBUF = 0x07;                         // output start bit and ADC conf(single ended)
    while(!(SSPSTAT & BUSY));              // wait for transfer complete
    
    SSPBUF = 0xC0;                         // output 2 command(channel7) and 6 dummy bits(
    while(!(SSPSTAT & BUSY));              // wait for transfer complete
    MSB = SSPBUF;                          // receive MSB first
    
    SSPBUF = 0x00;                         // send dummy byte;
    while(!(SSPSTAT & BUSY));              // wait for transfer complete
    LSB = SSPBUF;                          // receive LSB
    
    PORTB =  LSB;             // Send LSB to PORTB
    PORTD =  MSB;             // Send MSB to PORTD
    
    Chip_Select = 1;             // Deselect ADC
    
    affichage();                 // Go to affichage
    oldstate = 0;
    }while(1);
    }
    A plus et encore merci.

  16. Publicité

Sur le même thème :

Discussions similaires

  1. pic 16F887 envoi de trames
    Par Bender4972 dans le forum Électronique
    Réponses: 2
    Dernier message: 18/12/2009, 13h26
  2. Problème avec un PIC 16F887.
    Par AdrienXx dans le forum Électronique
    Réponses: 31
    Dernier message: 02/07/2009, 20h05
  3. 16f887 a 16f636
    Par joloco dans le forum Électronique
    Réponses: 7
    Dernier message: 09/06/2009, 07h07
  4. Pic 16f887 timer0
    Par Snoopy85 dans le forum Électronique
    Réponses: 30
    Dernier message: 11/03/2009, 07h43
  5. Programmer un 16f887 en jdm ?
    Par uranie-mc dans le forum Électronique
    Réponses: 3
    Dernier message: 18/04/2008, 19h04