Partage
  • Partager sur Facebook
  • Partager sur Twitter

Calculer une frequence variable avec Arduino

    20 septembre 2018 à 9:44:07

    Bonjour,

    J'ai un projet ou j'aurais besoin de calculer la une frequence variable d'un signal carré qui varie entre 50 Hz et 70 kHz et je  veux utiliser Arduino pour effectuer ce calcul, sauf que mon code il ne fonctionne pas comme prevu. En fait je ne comprend pas pourqoui le programme m'envoie le temps divisé par 2 du mon signal. En réalité, si par exemple je mesure 100 us à l'oscilloscope le programme m'envoie 50 us. Je pourrais me contenter de réaliser une multiplication par 2 pour avoir le bon résulatat, mais je voulais bien savoir pour quel raison ne marche pas.

    Mon premier while sert à détecter lorsque le signal est haut et par la suite je cherche à trouver le début du rapport cyclique pour que puisse compter la suivante etat base. 

    Merci à vous.:)

    long int compteur, tHaut, tBas;
    boolean etat = 0;
    
    void setup()
    {
      Serial.begin(9600);
    
      DDRD |= 0b000000000;  // pin 2 en entree
    
      compteur =0;
      tHaut = 0;
      tBas = 0;
    }
    
    
    
    
    void loop()
    {
       
      etat = PIND & 0b000000100;   // je lis la valeur de pin 2
    
      while(etat)	// lorsque le signal est haut
         {
          compteur++;
          delayMicroseconds(1);
          etat = PIND & 0b000000100;    // je lis la valeur de pin 2
    
       	// lorsque le signal revient à 0 je commence à compter en début du cycle
       	      while(!etat)  // etat  = 0
    	      {
    	           tBas++;    // incrementation de temps
    	           delayMicroseconds(1);
                   etat = PIND & 0b000000100;   // je lis la valeur de pin 2
         // si le signal revient à 1 j'affiche la valeur du temps          
                   if (etat)
                   	{
                   		Serial.print("Temps a l'etat bas : ");
                   		Serial.println(tBas);
                   		 compteur = 0;
                         tBas = 0;
                   	}
    	      }
                break;
    	   }  
    }
    



    -
    Edité par CiprianMalaes 20 septembre 2018 à 10:01:11

    • Partager sur Facebook
    • Partager sur Twitter
    La vie, c'est comme une une bicyclette, il faut avancer pour ne pas perdre l'équilibre.
      20 septembre 2018 à 15:00:46

      Salut, 

      Je ne suis pas sûr de la réponse que je vais te donner, mais il me semble que cela pourrait être due aux instructions 

      (la lecture de l'état de la pin 2 ainsi que l'incrémentation du compteur prennent du temps)

      et comme tu veux mesurer des microsecondes, aussi petit soit le temps d’exécution des  ces deux instruction il n'est pas égale à 0.

      ajoute à cela que tu utilise une boucle While et une condition If (deux instruction qui prennent également du temps)

      Idée : Essaie de rallonger le temps du delay (à 10us par exemple) et vérifie que tu n'as plus le facteur 2 mais un facteur inférieur entre ce que tu observe à l'oscillo et ce que te renvoie l'arduino. 

      • Partager sur Facebook
      • Partager sur Twitter
        20 septembre 2018 à 15:28:16

        Je pense qu'il s'agit d'un probleme lie à la carte Arduino car j'ai teste ce code et j'obtien comme résultat une valeur entre 70 et 80 et si je supprime la fonctione delayMicoseconds, le resultat est le meme. Donc, Arduino peut compter toutes les 1 us, si je ne me trompe pas.

        long int temps = 0;
        long int tDepart = 0;
        long int tFin = 0;
        long int pos = 0;
        
        void setup()
        {
          Serial.begin(9600);
        
        }
        
        void loop()
        {
          pos =0;
          tDepart = micros();
          while(pos <=100)
           {
            delayMicroseconds(1);
            pos++;
           }
            
          tFin = micros();
          Serial.println(tFin - tDepart);
          delay(1000);
        }

        Et au final pour pouvoir compter le temps à l'état bas et à létat haute j'utilise ce code. Je ne pas mis la fonction affichage pour ne pas alourdir ici le code. En tout cas , ca marche: je peut detecter une fréquence assez precise mais en multipliant par 2 le temps.

        long int compteur, Toff, Ton;
        boolean etat = 0;
        
        
        void setup()
        {
          Serial.begin(9600);
          lcd.init();        // initialization afficheur
        
          DDRD |= 0b000000000;  // pin 2 en lecture
        
          compteur =0;	// 
          Toff = 0;
          Ton = 0;
        }
        
        
        
        
        void loop()
        {
          lcd.backlight();	// activation d'eclairage LCD
          etat = PIND & 0b000000100;   // je lis la valeur de pin 2
        
        // le 1er while va detecter l'etat haute du signal
          while(etat)  // tant que le signal est haut
             {
              compteur++;
              etat = PIND & 0b000000100;    // je lis la valeur de pin 2
        
            // lorsque le signal revient à 0 je commence à compter en début du cycle bas
                while(!etat)  // tant que etat  = 0
                {
                     Toff++;    // incrementation du temps toutes les 1 us
                     // delayMicroseconds(1);  faculatative car arduino compte toutes le 1 us
                     etat = PIND & 0b000000100;   // je lis la valeur de pin 2
        
             // Quand le signal revient à 1 je compte le temps à l'état haute              
                       if(etat)
                        {
                            while(etat)
                             {
                              Ton++;    // incrementation de temps toutes les 1 us
                               etat = PIND & 0b000000100;   // je lis la valeur de pin 2
        
                          // si le signal revient à 0 j'appelle la fc d'affichage
                               if(!etat)
                                {
                                  affichage(); // appel à la fonctione de calcul et affichage
                                  break;
                                } 
                            }
                            break;
                         }     
                }
                    break;
             }  
        }
        




        • Partager sur Facebook
        • Partager sur Twitter
        La vie, c'est comme une une bicyclette, il faut avancer pour ne pas perdre l'équilibre.
          26 septembre 2018 à 3:12:44

          Pour que ton code mesure 1µs par tour d'une boucle, le contenu de la boucle doit faire exactement 16 cycles à 16MHz (1 cycle d'horloge prend 1/16µs) et ne doit pas pouvoir être interrompu par les interruptions. Donc si tu arrives à un résultat qui semble correct, c'est juste du hasard.

          Apparemment, la façon dont est compilée la ligne "Ton++" prend déjà 20 cycles, parce que Ton est une variable globale 32 bits, que l'atmega328 est seulement 8 bits (tu peux désassembler avec la commande "avr-objdump -S tonFichier.elf") :

          // lit la variable Ton (32 bits -> 4 x 8 bits)
          lds  r24, &Ton[0]
          lds  r25, &Ton[1]
          lds  r26, &Ton[2]
          lds  r27, &Ton[3]
          // Ajoute 1 au mot 16 bits composé de R24 et R25
          adiw r24, 1
          // propage la retenue à R26 puis R27
          adc  r26
          adc  r27
          // stocke la variable Ton
          sts  &Ton[0], r24
          sts  &Ton[1], r25
          sts  &Ton[2], r26
          sts  &Ton[3], r27
          

          A chaque incrémentation, la variable est rechargée et réenregistrée en RAM, justement parce que c'est une variable globale, chacune de ces instructions prend 2 cycles d'horloges, sauf les 2 adc qui prennent chacune 1 cycle (référence ici). A cela, pour la boucle ligne 41 par exemple, il faut ajouter la lecture de l'état, 7 instructions / 8 cycles, et le saut pour le while, 2 instructions / 3 cycles, soit en tout 30 cycles.

          Ton code est également assez bizarre, dans le sens où tous tes whiles ont un if avec la condition inverse à l'intérieur, et c'est ce if qui fait sortir de la boucle grâce au break, au lieu de la condition qui se trouve dans le while. Dans le cas de la première boucle le break est exécuté de façon inconditionnelle, donc ce n'est pas vraiment une boucle mais un if...

          • Partager sur Facebook
          • Partager sur Twitter

          Calculer une frequence variable avec Arduino

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown