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.
"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.
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...
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...
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.
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.
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") :
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
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.
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 :
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.
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.