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

Capteur Ultrason HC-SR04 sur PIC16F877A



  1. #1
    Benq720

    Capteur Ultrason HC-SR04 sur PIC16F877A


    ------

    Bonjour,
    Après avoir réussi à afficher un texte sur un afficheur lcd grâce à vous, je vous sollicite une nouvel fois car je voudrais cette fois ci afficher la distance entre le capteur et un obstacle.
    J'ai commencé par rechercher sur le net comment fonctionne le capteur et je suis tombé sur ceci : http://www.micropik.com/PDF/HCSR04.pdf
    D'après ce que j'ai compris il faut envoyer une impulsion de 10 microseconde dans le Triger du capteur puis il renvoie un signal haut d'une durée proportionnelle à la distance par la broche Echo.
    La formule est : distance=((temps de l’état haut du signal reçu)*(la vitesse du son dans l'air soit 340 mètres par seconde))/2
    Vu que la vitesse est en mètre par seconde je pense que la durée du signal haut envoyé par la capteur doit être en mètres par secondes aussi.
    Donc j'ai commencé à faire mon programme sur mikroC dont voici le code :

    /*
    * Project name:
    Test du HC-SR04
    * Test configuration:
    MCU: PIC16F877A
    Oscillator: HS, 12.0000 MHz
    Ext. Modules: Character LCD 2x16
    HC-SR04
    SW: mikroC PRO for PIC
    */
    // LCD connections
    sbit LCD_RS at RB4_bit;
    sbit LCD_EN at RB5_bit;
    sbit LCD_D4 at RB6_bit;
    sbit LCD_D5 at RB1_bit;
    sbit LCD_D6 at RB2_bit;
    sbit LCD_D7 at RB3_bit;

    sbit LCD_RS_Direction at TRISB4_bit;
    sbit LCD_EN_Direction at TRISB5_bit;
    sbit LCD_D4_Direction at TRISB6_bit;
    sbit LCD_D5_Direction at TRISB1_bit;
    sbit LCD_D6_Direction at TRISB2_bit;
    sbit LCD_D7_Direction at TRISB3_bit;
    // End LCD connections


    char txt1[] = "Test du capteur";
    char txt2[] = "HC-SR04";
    char txt3[] = "Distance :";
    char txt4[5];

    float distance = 0;
    int tempo1 = 0;
    int tempo2 = 0;

    bit oldstate;

    void main(){

    TRISB0_bit = 1; // Config RB0 entree
    TRISA = 0x00; // Config RA sortie
    PORTA = 0x00;

    Lcd_Init(); // Initialisation du LCD

    Lcd_Cmd(_LCD_CLEAR); // Effacer le LCD
    Lcd_Cmd(_LCD_CURSOR_OFF); // Desactivation du curseur
    Lcd_Out(1,2,txt1); // Ecrire text 1
    Lcd_Out(2,6,txt2); // Ecrire text 2
    Delay_ms(2000);
    Lcd_Cmd(_LCD_CLEAR); // Effacer le LCD


    affichage:

    floatToStr(distance,txt4);

    Delay_ms(60);
    Lcd_Cmd(_LCD_CLEAR); // Effacer le LCD
    Lcd_Cmd(_LCD_CURSOR_OFF); // Desactivation du curseur
    Lcd_Out(1,2,txt3); // Ecrire text 1
    Lcd_Out(1,14,txt4); // Afficher distance


    PORTA = 0x01; //Broche RA0 a 1
    Delay_us(10); //Attente 10 microsecondes
    PORTA = 0x00; //Broche RA0 a 1

    do {
    if (Button(&PORTB, 0, 0, 1)) { //Si reception signal
    oldstate = 1; //Mise a jour du statut du signal
    tempo1++; //Inctrémante de 1 a chaque boucle
    Delay_us(1); //on attend 1 uS pour tempo1 soit en uS
    }
    if (oldstate && Button(&PORTB, 0, 0, 0)) { //Si signal passe de 1 a 0
    oldstate = 0; //Mise a jour du statut du signal
    tempo2 = tempo1; //tempo2 devient egal a tempo1
    tempo1 = 0; //on met tempo1 a 0
    break; //on sort de la boucle
    }
    } while(1);

    tempo2 = (tempo2/1000000); //conversion microsecondes en secondes
    distance = (tempo2*340)/2; //calcul de la distance

    goto affichage;

    }

    Le problème est que la valeur affichée sur le lcd est toujours égale à 0, j'ai aussi essayé en remplaçant :
    tempo2 = (tempo2/1000000); //conversion microsecondes en secondes
    distance = (tempo2*340)/2; //calcul de la distance
    par :
    distance = tempo2/58; //calcul de la distance
    et j’obtiens bien une valeur proportionnelle a la distance mais très imprécise : j'ai 0 pour 0~40 cm 1 pour 40~80cm 3 pour 80~120cm et après 4.
    Le pic envoi bien l'impulsion de 10 microseconde avec ce programme et j'ai visualiser le signal de sortie a l'oscilloscope et j'obtiens un signal haut de 4 ms sur la broche Echo pour une distance d'environ 65 cm
    je pense que c'est ma boucle qui n'est pas correct mais je ne vois pas comment faire pour mesurer avec le plus de précision possible de temps de l'état haut à la broche RB0
    Si quelqu'un a déjà utilisé ce genre de capteur, une idée, une suggestion ou a remarquer un bugg dans le programme n'hésitez pas a répondre.

    Merci d'avance

    -----

  2. Publicité
  3. 📣 Nouveau projet éditorial de Futura
    🔥🧠 Le Mag Futura est lancé, découvrez notre 1er magazine papier

    Une belle revue de plus de 200 pages et 4 dossiers scientifiques pour tout comprendre à la science qui fera le futur. Nous avons besoin de vous 🙏 pour nous aider à le lancer...

    👉 Je découvre le projet

    Quatre questions à explorer en 2022 :
    → Quels mystères nous cache encore la Lune 🌙 ?
    → Pourra-t-on bientôt tout guérir grâce aux gènes 👩‍⚕️?
    → Comment nourrir le monde sans le détruire 🌍 ?
    → L’intelligence artificielle peut-elle devenir vraiment intelligente 🤖 ?
  4. #2
    paulfjujo

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    bonjour,


    un int ne peutcontenir, non signé , qu'une valeur maxi de 65535
    passe plutot en flottant pour les calculs.

    Pourquoi garder 340M / seconde
    tu peux utiliser soit
    340 mm / mSec
    ou 340 µ / µ sec
    pour eviter de diviser par 1000000

    Un timer serait plus approprié pour ce comptage
    ex: Timer0 en mode 16 bits declenché sur RA4

    ou mode mesure de periode avec CCP1 et timer1.

    Mais dans un premier temps , il est vrai que tu peut degrossir la mesure dans une boucle
    n'oublie pas que ton delai de 1µS sera de : 1µS + le delai d'execution des instructions de boucle ...
    Quelques instructions asm NOP pourrait permettre d'affiner l'ensemble à 1µs precise.
    Dernière modification par paulfjujo ; 16/06/2012 à 15h51.

  5. #3
    Benq720

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    Voila donc j'ai changer les int par des float et j'ai divisé par 1000 puis par 20 pour avoir la distance en cm comme cela :

    tempo2 = (tempo2/1000); //conversion microsecondes en secondes
    distance = (tempo2*340)/20; //calcul de la distance

    Le resultat est plutôt bon a 2 cm près mais il y a un changement d'unité qui se fait tout seul comme par exemple si je suis à 45 centimètre sa affiche 4.5, à 5 cm sa affiche 5 et pour 1.5 mètre sa affiche 1.5. D'où cela pourrait venir par ce que la je vois pas du tout.
    Et comment je fais pour trouver le délai d’exécution ?
    Sinon pour le principe timer ou du CCP1 comment ça marche ? parce que j'ai vu sur des forums que pour mesurer avec une précision du microseconde la méthode du timer et ccp1 était recommandée mais je n'est pas trouver d'exemple en c.

    Merci pour ton aide.

  6. #4
    paulfjujo

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    bonsoir,

    Tempo2 est un int ou un float ?
    Il serait judicieux de sortir les valeur brutes de Tempo2 pour verifier si elles sont vraiment utilisables
    et aussi verifier la linearite en fonction de la distance.
    pour les calculs tu peux garder Tempo2 en µSec
    et calculer distance= (float) tempo2 * 17.0/1000.0;

    Attention tu ne detectes pas directement l'etat de ton entree, car il me semble que la fonction Button
    applique un traitement anti-rebond (a verifier dans le fichier Map asm) et donc fausse aussi les calculs.

    sinon, ci joint un Exemple de mesure de frequence (inverse de duree) avec CCP1
    à adapter à ton cas

    Code:
    /*
    15/12/2011
    * Outils : MikroC PRO v4.60.00
    * Project name  : 16F877_Platine_Nokia_Duree_ccp1.mcppi
    * Fichier Source: 16F877A_CCP_Periodemetre.c
    * fichier scheme: P16F877_Platine.cfgsch
    * fichier EEprom: 16F877_Platine_CCP1.ihex
    * Description:
    
    Test mesure de duree par capture des fronts montants du signal
    entrant sur RC2
    Resultat envoyé sur terminal RS232
    Hardware :
    My Board: Platine Nokia 16F877
    MCU: PIC16F877
    Quartz =10MHZ
    RS232 on  board
    CONFIG   :$2007 : 0x3B32
    */
    
    #define CLS 12
    #define CR 13
    #define LF 10
    #define BS 8
    #define TAB 9
    
    
    
    unsigned tWord,tOld, tNew;
    char th,tl;
    char error;
    char edge = 0;
    char capture = 0;
    unsigned long Cumul;
    char txt[7];
    float Freq;
    
    void Write_String(char * texte)
    {
    while (* texte)
     {
    UART1_Write(* texte++);
     }
    }
    void interrupt() {
    if(PIR1.CCP1IF){
    if(!edge){
    tOld = 256*CCPR1H+CCPR1L; // keep starting value
    edge = 1;
    }else{
    tNew =256*CCPR1H + CCPR1L; // keep ending value
    capture = 1; // complete capture, set a flag
    edge = 0;
    }
    PIR1.CCP1IF = 0; //clear CCP flag
    }
    }
    
    void CRLF()
    {
     UART1_Write(CR);
     UART1_Write(LF);
    }
    
    void main() {
    char i;
    TRISB = 0; // PORTB is output
    PORTB = 0; // Initialize PORTB
    TRISA = 0;
    TRISC = 0;
    CCP1CON = 0x05; // Capture mode every rising edge
    TRISC.F2 = 1; // RC2 must be input
    T1CON = 0x21; // timer1 ON, internal clock Fosc/4, prescaler 1:4
    INTCON.GIE = 1;
    INTCON.PEIE =1;
    PIE1.CCP1IE = 1; // enable interrupt capture
    PIR1.CCP1IF = 0; //clear CCP flag
    
    UART1_Init(19200);
     while(1)
     {
     if(capture){
      PIE1.CCP1IE = 0; // disable interrupt while processing
      capture = 0; // clear flag
      // Calculate length of pulse from rising edge to rising edge
      tWord = ~tOld + tNew+1;
      // tword contain length of pulse in micro second
      WordToStr(tWord, txt); // convert to string and send back to terminal
      //for(i=0; i<6; i++) UART1_Write(txt[i]);
       Write_String(txt); UART1_Write('µ'); UART1_Write('S'); UART1_Write(TAB);
      Freq=1000000.0/((float)tWord*1.6);
      error= FloatToStr(Freq,txt);
      Write_String(txt); UART1_Write(' '); UART1_Write('H'); UART1_Write('z');
      CRLF();
      Delay_ms(1000);
      PIR1.CCP1IF = 0; //clear CCP flag
      PIE1.CCP1IE = 1; // enable interrupt
      }
     }
    }

  7. A voir en vidéo sur Futura
  8. #5
    Benq720

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    Je suis en train d'adapter le code pour mon cas et j'obtiens ce code là pour l'instant (j'ai enlever l'envoi par usart) :
    Code:
    /*
    15/12/2011
    * Outils : MikroC PRO v4.60.00
    * Project name  : 16F877_Platine_Nokia_Duree_ccp1.mcppi
    * Fichier Source: 16F877A_CCP_Periodemetre.c
    * fichier scheme: P16F877_Platine.cfgsch
    * fichier EEprom: 16F877_Platine_CCP1.ihex
    * Description:
    
    Test mesure de duree par capture des fronts montants du signal
    entrant sur RC2
    Resultat envoyé sur terminal RS232
    Hardware :
    My Board: Platine Nokia 16F877
    MCU: PIC16F877
    Quartz =10MHZ
    RS232 on  board
    CONFIG   :$2007 : 0x3B32
    */
    
    #define CLS 12
    #define CR 13
    #define LF 10
    #define BS 8
    #define TAB 9
    
    
    
    unsigned tWord,tOld, tNew;
    char th,tl;
    char error;
    char edge = 0;
    char capture = 0;
    unsigned long Cumul;
    char txt[7];
    float Freq;
    
    
    void interrupt() {
    
    if(PIR1.CCP1IF){               //Si PIR1.CCP1IF égal à 1
    if(!edge){                     //Si edge égal à 0
    tOld = 256*CCPR1H+CCPR1L;      //garde la valeur de départ
    edge = 1;                      //edge prend la valeur 1
    }else{
    tNew =256*CCPR1H + CCPR1L;     //garde la valeur de fin
    capture = 1;                   //indicateur capture términée
    edge = 0;                      //edge prend la valeur 0
    }
    PIR1.CCP1IF = 0;               //remise à 0 du flag (PIR1.CCP1IF)
    }
    }
    
    
    
    void main() {
    char i;
    TRISB = 0;       // PORTB en sortie
    PORTB = 0;       // Initialisation du PORTB
    TRISA = 0;       // PortA en sortie
    TRISC = 0;       // PortC en sortie
    CCP1CON = 0x05;           // Mode de capture a chaque front montant
    TRISC.F2 = 1;             // RC2 en entré
    T1CON = 0x21;             // timer1 ON, internal clock Fosc/4, prescaler 1:4
    INTCON.GIE = 1;
    INTCON.PEIE =1;
    PIE1.CCP1IE = 1;           // active la capture par interruption
    PIR1.CCP1IF = 0;           //remise à 0 du flag (PIR1.CCP1IF)
    
    
     while(1)
     {
     if(capture){
      PIE1.CCP1IE = 0; //desactive  la capture par interruption
      capture = 0; // Capture prend la valeur 0
      tWord = ~tOld + tNew+1;           //Calculer la longueur de l'impulsion de front montant à front montant
    
      // tword contiennent longueur d'impulsion en micro seconde
    
      WordToStr(tWord, txt);            // convertir en chaîne de caractère
    
      Freq=1000000.0/((float)tWord*1.6);
      error= FloatToStr(Freq,txt);
      
      /*
      CRLF();
      */
      
      Delay_ms(1000);
      PIR1.CCP1IF = 0;                  //remise à 0 du flag (PIR1.CCP1IF)
      PIE1.CCP1IE = 1; // enable interrupt
      }
     }
    }
    j'ai trouvé ce site qui expliquer le ccp :
    http://www.mikroe.com/eng/chapters/v...5-ccp-modules/
    mais avec je n'ai pas trouver pour mesurer la durée d'une impulsion c'est à dire le temps entre le front motant et le front descendant et non la période de front montant à front montant comme dans ce programme.
    Comment je peux l'adapter pour faire cela ?
    Dernière modification par Benq720 ; 17/06/2012 à 10h41.

  9. #6
    Benq720

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    Sinon les :
    #define CLS 12
    #define CR 13
    #define LF 10
    #define BS 8
    #define TAB 9
    sont pour l'uart aussi, donc on peu les enlever ?
    Dernière modification par Benq720 ; 17/06/2012 à 10h56.

  10. Publicité
  11. #7
    Benq720

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    Bon c'est bon j'ai réussi, j'ai adapté tout cela et ça marche impecable.
    Pour ceux que ça intéresse voici le code :

    Code:
    /*
     * Project name:
         Test du HC-SR04
     * Test configuration:
         MCU:             PIC16F877A
         Oscillator:      HS, 12.0000 MHz
         Ext. Modules:    Character LCD 2x16
                          HC-SR04
         SW:              mikroC PRO for PIC
    */
    // LCD connections
    sbit LCD_RS at RB4_bit;
    sbit LCD_EN at RB5_bit;
    sbit LCD_D4 at RB6_bit;
    sbit LCD_D5 at RB1_bit;
    sbit LCD_D6 at RB2_bit;
    sbit LCD_D7 at RB3_bit;
    
    sbit LCD_RS_Direction at TRISB4_bit;
    sbit LCD_EN_Direction at TRISB5_bit;
    sbit LCD_D4_Direction at TRISB6_bit;
    sbit LCD_D5_Direction at TRISB1_bit;
    sbit LCD_D6_Direction at TRISB2_bit;
    sbit LCD_D7_Direction at TRISB3_bit;
    // End LCD connections
    
    
    char txt1[] = "Test du capteur";
    char txt2[] = "HC-SR04";
    char txt3[] = "Distance :";
    char txt4[7];
    unsigned long Cumul;
    unsigned tWord,tOld, tNew;
    char th,tl;
    char edge = 0;
    char capture = 0;
    float temps = 0;
    float distance = 0;
    float distance2 = 0;
    
    
    void interrupt() {
    
      if(PIR1.CCP1IF){                 //Si PIR1.CCP1IF égal à 1
        if(!edge){                     //Si edge égal à 0
          CCP1CON = 0x04;              // Mode de capture a chaque front descendant
          tOld = 256*CCPR1H + CCPR1L;      //garde la valeur de départ
          edge = 1;                        //edge prend la valeur 1
        }else{
          tNew =256*CCPR1H + CCPR1L;     //garde la valeur de fin
          capture = 1;                   //indicateur capture términée
          edge = 0;                      //edge prend la valeur 0
        }
        PIR1.CCP1IF = 0;               //remise à 0 du flag (PIR1.CCP1IF)
      }
    
    }
    
    
    void main() {
    
      char i;
      TRISB = 0;       // PORTB en sortie
      PORTB = 0;       // Initialisation du PORTB
      TRISA = 0;       // PortA en sortie
      PORTA = 0x00;    // Initialisation du PORTA
      TRISC = 0;       // PortC en sortie
      CCP1CON = 0x05;           // Mode de capture a chaque front montant
      TRISC.F2 = 1;             // RC2 en entré
      T1CON = 0x21;             // timer1 ON, internal clock Fosc/4, prescaler 1:4
      INTCON.GIE = 1;
      INTCON.PEIE =1;
      PIE1.CCP1IE = 1;           // active la capture par interruption
      PIR1.CCP1IF = 0;           //remise à 0 du flag (PIR1.CCP1IF)
    
      Lcd_Init();                        // Initialisation du LCD
    
      Lcd_Cmd(_LCD_CLEAR);               // Effacer le LCD
      Lcd_Cmd(_LCD_CURSOR_OFF);          // Desactivation du curseur
      Lcd_Out(1,2,txt1);                 // Ecrire text 1
      Lcd_Out(2,6,txt2);                 // Ecrire text 2
      Delay_ms(2000);
      Lcd_Cmd(_LCD_CLEAR);               // Effacer le LCD
    
      PORTA = 0x01;                      //    Envoi une impulsion
      Delay_us(10);                      //    de 10 microsecondes
      PORTA = 0x00;                      //    dans la broche RA1
    
      while(1)
      {
        if(capture){
        PIE1.CCP1IE = 0;                //desactive  la capture par interruption
        capture = 0;                    // Capture prend la valeur 0
        tWord = ~tOld + tNew+1;           //Calculer la longueur de l'impulsion de front montant à front montant
        CCP1CON = 0x05;                   // Mode de capture a chaque front montant
        
        // tword contiennent longueur d'impulsion en micro seconde
      
        temps =((float)tWord*4)/3;
        distance = ((float)temps*17)/1000;       //calcul de la distance en cm
        floatToStr(distance,txt4);
      
        Delay_ms(70);
        PIR1.CCP1IF = 0;                 //remise à 0 du flag (PIR1.CCP1IF)
        PIE1.CCP1IE = 1;                 // enable interrupt
        
        if(distance !=distance2){
          Lcd_Cmd(_LCD_CLEAR);               // Effacer le LCD
          Lcd_Cmd(_LCD_CURSOR_OFF);          // Desactivation du curseur
          Lcd_Out(1,1,txt3);                 // Ecrire text 3
          Lcd_Out(2,8,txt4);                 // Afficher distance
        }
        
        distance2 = distance;
        PORTA = 0x01;                      //    Envoi une impulsion
        Delay_us(10);                      //    de 10 microsecondes
        PORTA = 0x00;                      //    dans la broche RA1
        }
      }
    }
    merci beaucoup paulfjujo pour ton exemple ça ma beaucoup aidé.

  12. #8
    Hamroush7

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    pourriez-vous s'il vous plaît envoyez-moi le lien de ce circuit sur ​​Proteus ou un dessin schématique, comme j'ai essayé d'utiliser le code et ça n'a pas fonctionné

  13. #9
    newtech1

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    Salut,

    ce serait syma que tu postes ton schéma, ton projet m'interesse bien


    Merci

  14. #10
    paulfjujo

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    bonjour,

    Citation Envoyé par Benq720 Voir le message
    Sinon les :
    #define CLS 12
    #define CR 13
    #define LF 10
    #define BS 8
    #define TAB 9
    sont pour l'uart aussi, donc on peu les enlever ?
    oui, exact.


    pour mesurer entre front montant et front descendant
    il faut modifier la config de detection
    CCP1CON = 0x05; // Mode de capture a chaque front montant
    dans l'interruption,
    en gerant un bit toggle pour le changement de sens
    pour valider la duree.

  15. #11
    Doum125

    Re : Capteur Ultrason HC-SR04 sur PIC16F877A

    Bonjour a tous j'ai exécuter le code que vous venez exécuter ne s'exécute pas correctement sur mon plan v8

Discussions similaires

  1. Capteur Ultrason
    Par mizzovic dans le forum Électronique
    Réponses: 8
    Dernier message: 03/06/2012, 16h53
  2. problème capteur ultrason
    Par mr-max dans le forum Électronique
    Réponses: 6
    Dernier message: 27/10/2011, 22h51
  3. Utiliser capteur à ultrason
    Par jojo86 dans le forum Électronique
    Réponses: 1
    Dernier message: 28/03/2010, 00h58
  4. capteur a ultrason
    Par medak dans le forum Électronique
    Réponses: 1
    Dernier message: 09/03/2009, 13h11
  5. capteur a ultrason
    Par khoung dans le forum Électronique
    Réponses: 4
    Dernier message: 22/04/2008, 11h33
Découvrez nos comparatifs produits sur l'informatique et les technologies.