Go Down

Topic: Fonction attachInterrupt() et fréquence (Read 2159 times) previous topic - next topic

Jean-François

Feb 01, 2009, 08:14 pm Last Edit: Feb 01, 2009, 08:15 pm by jfs Reason: 1
Bonsoir,

Je suis sur un projet de capteur sur un véhicule, je mesure la pression d'huile que je compare aux t/min et si cette valeur comparée est correcte, pas de soucis, autrement une alarme se met en fonction.

Je dois récupérer une fréquence avec la fonction attachInterrupt(), je pensais trouver la fréquence maxi que je pouvais lire, mais dans les références il n'en est pas fait mention.

Quelqu'un saurait-il me donner cette valeur ?
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

"attachInterrupt" sert à gérer les 2 pattes d'interruption externe.

tout d'abord, il faut savoir qu'il faut rester le moins longtemps possible dans une interruption, au cas où de nouvelles interruptions arriveraient. donc il vaut mieux juste changer une valeur (incrémenter un compteur par exemple) pour ensuite traiter cette valeur quand il y a moins de stress (dans le "loop" par exemple).

sur une autre carte que l'Arduino mais avec un microcontrôleur identique (ATmega8) et un quartz de 8 MHz, je faisais l'acquisition de 20000 impulsions sans problème. Mais tout dépend de ce que tu mets dans ta fonction, on doit pouvoir aller beaucoup plus haut. Je vérifierai le chiffre exact.

Mais je n'ai pas compris ce que tu voulais faire et en quoi l'interruption externe allait t'aider.

Jean-François

#2
Feb 02, 2009, 08:30 pm Last Edit: Feb 02, 2009, 08:52 pm by jfs Reason: 1
J'amène quelques précisions :

Sur un véhicule à moteur thermique, l'alimentation électrique est assurée par l'alternateur, le courant en sortie de collecteur est redressé par une série de diodes et la batterie en faisant "tampon"permet de stabiliser quelques peu ce courant, mais seulement dans une certaine fourchette.
Au ralenti il peut y avoir 12,5 volts et moteur tournant à 3000-4000 tour/min on peut avoir jusqu'à 14,5 volts, ces valeurs varient lors de l'allumage ou l'extinction de consommateurs (phares, ventilation...).

Pour l'acquisition de données sur les capteurs de la voiture je passe par une isolation galvanique en utilisant des optocoupleurs, ces derniers ne faisant passer que des informations lolgiques (1/0).
le problème est que certaines de mes jauges me transmettent des données en faisant varier une tension que je n'arrive pas à faire parvenir tel quelles par le biais de mes optos. Pour pallier à cet inconvénient j'utilise un circuit VCO qui converti les tensions en fréquences que je peux ensuite lire sur les pins 2 et 3.
Jusque là ça va encore, mais voici le fond du problème qui me fait poser ces questions :

Comme je l'explique plus haut le circuit électrique dans un véhicule à moteur thermique est soumis à de fortes variations de tension. Les tensions renvoyées par les capteurs du véhicule subissent les mêmes variations et deviennent de ce fait "imprécis" (15 % de variation des mesures).
Pour pallier ce contrer ces variations, il faut que j'alimente ces capteurs avec une tension qui ne subit aucune variations (même en branchant des consommateurs), je pensait utiliser un autre circuit VCO afin de lire quel est la tension (par le biais de la fréquence générée) sur le véhicule et la corriger en commandant avec une PWM un Mosfet qui hachera le courant afin d'avoir une courant à la tension qui me convient.

Par contre d'après ce que tu me dis la fonction attachInterrupt() prend énormément de  ressource CPU ?

Est-ce possible de "daemoniser" cette fonction ?

J'espère ne pas avoir été trop long dans mon explication...  ;)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

#3
Feb 02, 2009, 08:43 pm Last Edit: Feb 02, 2009, 08:52 pm by jfs Reason: 1
Je viens de relire les références et effectivement, si l'on ne veut pas rater une impulsions il faut que le µc soit dédié uniquement à cette fonction...
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

non non pas du tout, ce n'est pas un problème de ressources CPU, ça ne prend quasiment rien d'entrer en interruption (6 cycles d'horloge, et l'Arduino fait 16 millions de cycles par seconde) et encore moins d'en sortir (4 cycles).

ce qui se passe, c'est que tant que tu es dans la fonction que tu as "attachée", le CPU ne fait rien d'autre, donc il faut vite en sortir.

une solution est d'en faire le moins possible dans l'interruption.

Code: [Select]

int count = 0;
int frequence = 0;

void setup()
{
 attachInterrupt(0, interrupt, RISING);
}

void loop()
{
 // mesurer la fréquence comme le nombre de fronts montants en 1 s.
 frequence = count;
 count = 0;
 // traiter la fréquence
 ...
delay(1000);  // attendre une seconde pour avoir la fréquence en Hz
}

void interrupt()
{
 count++;
}


mais si c'est pour mesurer une fréquence, tu devrais plutôt regarder du côté des timers en mode "compteur" sur une patte externe.

Jean-François

#5
Feb 02, 2009, 10:17 pm Last Edit: Feb 02, 2009, 10:23 pm by jfs Reason: 1
Quote

mais si c'est pour mesurer une fréquence, tu devrais plutôt regarder du côté des timers en mode "compteur" sur une patte externe.


C'est à dire ?


Pour l'instant j'ai un code comme ça :
Code: [Select]

unsigned long sendTime=0;
volatile byte ppmcount;

unsigned long ppm;

unsigned long timeold;
unsigned long timeold2;
int pwmVolt = 255;
int pinVolt = 9;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, ppm_fun, FALLING);

  ppmcount = 0;
  ppm = 0;    //Pulse per minute
  timeold = 0;
}

void loop()
{
  if (ppmcount >= 250) {
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    ppm = 30*1000/(millis() - timeold)*ppmcount;
   
    timeold = millis();
    ppmcount = 0;
   
   
  }

//********** ici c'est pour corriger la valeur de la tension*********

if (ppm >=10251){  
 pwmVolt--;
}

if (ppm <=10249){
 pwmVolt++;
}

 analogWrite(pinVolt,pwmVolt)

//************  jusque là..... mais c'est qu'une ébauche  ;) *********
 
  sendTime=millis()-timeold2;
  if (sendTime >=1000){
    Serial.print(ppm,DEC);
    Serial.print("   ");
    Serial.println(pwmVolt,DEC);
   
  timeold2 = millis();}
}

void ppm_fun()
{
  ppmcount++;
  //Each pulse, this interrupt function is run twice
}


MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

#6
Feb 03, 2009, 01:02 am Last Edit: Feb 03, 2009, 01:04 am by jfs Reason: 1
Ici une alimentation régulée par PWM avec utilisant un AVR.
Et le code utilisé....

C'est un peu tard, je regarderai ça demain  :)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

#7
Feb 04, 2009, 10:36 pm Last Edit: Feb 04, 2009, 10:40 pm by jfs Reason: 1
Avec ce code je mesure la tension en sortie PWM pin 9,
la tension est stable à environ 1-2/10ème de volt (je peux la régler en changeant la variable "freq") :

Code: [Select]


volatile byte ppmcount;
unsigned long sendTime=0;
unsigned long timeold;
unsigned long timeold2;
unsigned int diffPpm;
long ppm;
int pwmVolt = 254;
int pinVolt = 9;

void setup()
{
 TCCR1B = 0x09;

 Serial.begin(9600);
 attachInterrupt(0, ppm_fun, FALLING);
 pinMode(pinVolt,OUTPUT);
 ppmcount = 0;
 ppm = 0;    //Pulse per minute
 timeold = 0;
}

void loop()
{

 sendTime=millis()-timeold2;

 if (ppmcount >= 120) {
   //Update RPM every 20 counts, increase this for better RPM resolution,
   //decrease for faster update
   ppm = 1000/(millis() - timeold)*ppmcount;

   timeold = millis();
   ppmcount = 0;


 }


 long freq = 900000;
 freq/=35;

 if(ppm>=freq+1){

   diffPpm = ppm-freq;

   pwmVolt=0+255*(freq+1)/diffPpm;



   
   if( pwmVolt >255){
     pwmVolt= 255;
   }
   analogWrite(pinVolt,pwmVolt);


 }

 else if (ppm<=freq){

   diffPpm = freq-ppm;

   pwmVolt = 255-255*freq/diffPpm;


   if( pwmVolt >255){
     pwmVolt= 255;
   }
 
   analogWrite(pinVolt,pwmVolt);

 }
 else {
   analogWrite(pinVolt,pwmVolt);
 }




 if (sendTime >=1000){
   Serial.print(ppm,DEC);
   Serial.print("   ");
   Serial.println(pwmVolt,DEC);
   timeold2 = millis();
 }
}

void ppm_fun()
{
 ppmcount++;
 //Each pulse, this interrupt function is run twice
}



Je cherche à stabiliser ça encore plus, dans les 2-3/100ème... si quelqu'un à une piste a m'indiquer  ;)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

#8
Feb 05, 2009, 02:32 am Last Edit: Feb 05, 2009, 02:33 am by jfs Reason: 1
Petit essai pour réguler une tension 12 volt avec un tansistor commandé en PWM... ça fonctionne :D, mais la stabilité est de 2-4/10ème de volt, je cherche toujours à mieux stabiliser cette tension.  
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

#9
Feb 06, 2009, 02:26 am Last Edit: Feb 06, 2009, 02:28 am by jfs Reason: 1
Maintenant avec ce code je commande un transistor Tip127 et j'ai une "précisions" (c'est relatif... ::)) de 0,5 volts en étant programmé pour réguler une tension de 8 volts :

Code: [Select]
volatile int ppm_count;
unsigned long send_Time=0;
unsigned long send_Freq=0;
unsigned long timeold_Time;
unsigned long timeold_Freq;
                              //unsigned long diff_Ppm;
unsigned long ppm;                          //Pulse per minute
int pwm_Volt;
int pinVolt = 9;
int val;
void setup()
{
 TCCR1B = 0x09;
 Serial.begin(9600);
 attachInterrupt(0, ppm_fun, FALLING);
 pinMode(pinVolt,OUTPUT);
}
void loop()
{
 if (ppm_count >= 145) {
   ppm = 540/(millis() - timeold_Freq)*ppm_count;
   timeold_Freq = millis();
   ppm_count = 0;
   val=1;
 }
 long freq = 80000;                 //tension x 10'000
                       // freq/=35;
 if (val==1){
   if(ppm>=freq){
                      // diff_Ppm = freq-ppm;
                      //pwm_Volt=255-255*diff_Ppm/freq;
     pwm_Volt--;    
   }
   if (ppm<=freq){
                     //diff_Ppm = freq-ppm;
                     // pwm_Volt = 0+255*diff_Ppm/freq;
     pwm_Volt++;
   }
   if( pwm_Volt >255){
     pwm_Volt= 255;
   }
   if( pwm_Volt < 0){
     pwm_Volt= 0;
   }
   val=0;
 }
 analogWrite(pinVolt,pwm_Volt);
 send_Time=millis()-timeold_Time;
 if (send_Time >=1000){
   Serial.print(" ppm : ");
   Serial.print(ppm,DEC);
   Serial.print("   ");
   Serial.print("  ppm_count : ");
   Serial.print(ppm_count,DEC);
   Serial.print("   ");
   Serial.print("  pwm : ");
   Serial.println(pwm_Volt,DEC);
   timeold_Time = millis();
 }
}
void ppm_fun()
{
 ppm_count++;
 //Each pulse, this interrupt function is run twice
}



Je cherche toujours un moyen d'affiner cette régulation.
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

#10
Feb 07, 2009, 05:05 pm Last Edit: Feb 07, 2009, 06:06 pm by jfs Reason: 1

Dans le Playground j'ai trouvé ça :

Regulated Positive Voltage Booster


Pour continuer le sujet sur une alimentation dont la tension serait pilotée  :

Tension pilotée et stable
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

Pour en revenir au sujet, j'ai lu sur une page du net que quelqu'un se servait de cette fonction pour contrôler des fréquences et qu'il avait réussi à contrôler un quartz d'horloge à 32,768 kHz.
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Go Up