Projet Mesure de consommation carburant moto ou auto

Bonjour à tous,

Comme exposé un peu dans ma présentation, j'aimerais réaliser un mini calculateur de consommation de carburant sur un véhicule à injection.
J'avais déjà réalisé il y a quelques années ce montage qui fonctionnait avec des circuits : deux CD4060 (compteur, diviseur, oscillateur), un CD4011 (4 portes NAND), et un NE555 (générateur de créneau) et un transistor en sortie.
(Le premier CD4060 est en oscillateur à 4Mhz et divise par /16, ensuite avec les impulsions d'injection sur 3 NAND pour envoyer au dernier cd4060 qui divise par /4036 et envoie au NE555 qui génère une impulsion assez longue pour le compteur)

Pour la partie affichage, totalisation partielle et totale, sauvegarde, j'utilisais un compteur de vélo !
Il m'affichait non pas des KM/H mais des L/H, ce qui me permettait de savoir précisément ma consommation et surtout ce qui me restait. Il faut dire que sur une moto ce n'est pas si souvent indiqué (option éventuelle) et que les témoins de réserve ne sont pas toujours fiables ou s'allume trop tôt ce qui n'est pas mieux.

Donc mon circuit électronique comptait les temps d'injection cumulés (injection : durée variable et fréquence variable) et envoyait une impulsion tous les X ms d'injection au compteur (de vélo) qui traitait le reste.
Avantage du compteur de vélo, il est autonome (pile); étanche, bouton de remise à 0 du partiel étanche aussi, pas bien grand et facilement installable au guidon ou autre endroit, son affichage est bien visible, on peut affiner le réglage en modifiant facilement la constante "tour de roue en mm" qui ici correspond à des ml consommés, il donne l'heure et il est peu cher.

Donc avec Arduino (Attiny ensuite) j'ai cru que j'avais trouvé la solution simple avec

duree = pulseIn(impulsion, HIGH);

Mais j'ai vite vu qu'il ne mesurait qu'une impulsion pas plusieurs cumulées... Enfin c'est ce que j'ai compris en visualisant avec un oscilloscope.

Depuis je cherche comment faire et je ne trouve pas la bonne manière, si possible simple.

J'ai pensé mettre une sorte de compteur (comment ?) qui ne se mette en route que lorsque l'entrée impulsion injection est à 1, et lorsque la variable temps d'injection serait égale à une valeur définie (si = X ms), envoyer une autre impulsion calibrée (pas trop brève) au compteur totalisateur (de vélo) et remettre le compteur interne à 0 pour refaire une mesure...
La même chose en fait que mon premier circuit mais c'est peut-être une mauvaise manière de voir la solution.

Je ne sais pas si c'est bien clair, je pensais y arriver seul mais je ne trouve pas d'autant que je ne maitrise pas la structure de la programmation et ses possibilités.

Merci

Michel

bonsoir
pour faire simple , tu dispose/recuperedes impulsions correspondant à une qte de carburant injecté ?
si oui je suppose que c'est une impulsion 12V ?

Bonsoir Artouste,

Oui des impulsions d'injection qui correspondent à une quantité de carburant (la pression est constante et le temps d'ouverture d'un injecteur est normalement proportionnel au volume).
C'est du 12 V mais il faut protéger l'entrée du circuit, et ici limiter à 5 V, surtout qu'il y a une surtension à la coupure de l'injecteur qui est une sorte de self.

michelm:
Bonsoir Artouste,

Oui des impulsions d'injection qui correspondent à une quantité de carburant (la pression est constante et le temps d'ouverture d'un injecteur est normalement proportionnel au volume).
C'est du 12 V mais il faut protéger l'entrée du circuit, et ici limiter à 5 V, surtout qu'il y a une surtension à la coupure de l'injecteur qui est une sorte de self.

ok
C'est donc finalement plus une estimation du volume injecté, qu'une reelle mesure volumique consommé :grin:
mais si l'erreur dérivée est acceptable/assumée , un relevé par arduino est simple à faire en assumant durée creneau haut= qte "injectée/consommée"

Pour ramener le 12V creneau sur de l'acceptable MCU , il existe plusieurs solutions, ce n'est pas en soit un probleme :grin:

comme tu dispose d'un oscillo, quelle est la durée mini d'un creneau d'injection ?

La durée d'injection de mémoire c'est de l'ordre de 1 à 15 ms.
C'est une injection séquentielle phasée, pour 2 cylindres, je ne prends qu'un injecteur sur 2, car ils donnent la même quantité à chaque cylindre.

En cherchant j'ai trouvé quelqu'un qui voulait mesurer un temps d'injection :
http://forum.arduino.cc/index.php?topic=45926.0

Par contre je ne comprends pas vraiment le code pour le moment :

J'ai oublié qu'effectivement l'injecteur est polarisé au +12V permanent, et donc que le fil utilisé (ground wire) pour la commande et pour le circuit de mesure est à 0 quand l'injecteur est ouvert (injection de carburant), et +12V quand il est fermé (injecteur au repos).

int injPin = 3; //Pin connected to injector's ground wire
volatile unsigned long injTime1;  //Time of front raising
volatile unsigned long injTime2;  //Time of front falling
unsigned long injTime;

void setup()
{
 pinMode(injPin, INPUT);
 digitalWrite (injPin, HIGH);  //Pull-up pin - as our injector is driven by connecting it to ground, i suppose i need to pull-up pin to get it's value as 1 when injector is turned off
 attachInterrupt(1, pik, CHANGE);  //interrupt on front changing
}

void loop()
{
//some code
}

void pik()
{
if (injPin == LOW) //Or i need to digitalRead it first?
{
 injTime1 = micros(); //get time of pulse going down
}
else
{ 
 injTime2 = micros();  //get time of pulse going up
 injTime = injTime2 - injTime1;  //measure time between down and up 
}
}

michelm:
La durée d'injection de mémoire c'est de l'ordre de 1 à 15 ms.
C'est une injection séquentielle phasée, pour 2 cylindres, je ne prends qu'un injecteur sur 2, car ils donnent la même quantité à chaque cylindre.
...
J'ai oublié qu'effectivement l'injecteur est polarisé au +12V permanent, et donc que le fil utilisé (ground wire) pour la commande et pour le circuit de mesure est à 0 quand l'injecteur est ouvert (injection de carburant), et +12V quand il est fermé (injecteur au repos).

ok pour les durées
0 ou 12v c'est une simple convention logique
je regarde demain , pour un code simple de test avec un interfaçage hard simple.

Oui 0 ou 12v ce n'est pas ça qui est compliqué, avec les circuits logiques j'avais inversé avec un NAND.

Merci Artouste !

michelm:
Oui 0 ou 12v ce n'est pas ça qui est compliqué, avec les circuits logiques j'avais inversé avec un NAND.

Merci Artouste !

ça risque finalement d'etre assez simple :grin:
dans ton ancien montage , tu recupere du creneau sous 5V ?

Avec les circuits logiques ça fonctionnait directement en 12V, en sortie je fermais une boucle du compteur vélo avec un transistor. Le compteur de vélo a d'origine 2 fils qui vont à un ILS fixe actionné par un aimant sur la roue.

J'espère que je vais comprendre la méthode si c'est assez simple !

michelm:
Avec les circuits logiques ça fonctionnait directement en 12V, en sortie je fermais une boucle du compteur vélo avec un transistor. Le compteur de vélo a d'origine 2 fils qui vont à un ILS fixe actionné par un aimant sur la roue.

J'espère que je vais comprendre la méthode si c'est assez simple !

bonjour
Dans un premier temps j'essaierai ceci
hard = optocoupleur
soft = test des durée creneaux géré par interruption sortie sur serial

enum PinAssignments {
  encoderPinA = 2,

};

unsigned long Tparc=0; //  temps de parcours du secteur
unsigned long Tact=0; // Test pour  micros() en entrée 
unsigned long ParcMax=3000000; // delai max en µs pour parcourir un secteur, si > arret theorique de la roue sur le secteur arrivée
unsigned long Tparct[256] ; // tableau de long stockant les valeurs micros() à chaque interruption


byte Iparc=0; // indice pour parcourir Tparct
byte Iinit=1; // numero du 1er secteur concerné par Tparc[0] V= 1--->12 , pas encore utlisé ici 

boolean Sint=false; // passé par l'interruption oui/non
void setup() {

  pinMode(encoderPinA, INPUT_PULLUP);


  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);

  Serial.begin(115200);
}


void loop(){


  if (Sint==true)
  {

    Serial.print(">"); // pour test d'entre/sortie de secteur (rotation) ,indique passage par int0 

    Sint=false;
  }

  if (micros()-Tact > ParcMax) { // tempo en µsecondes pour test si pas eu d'interruption = roue à l'arret sur 1 secteur (theorie)


    Tact=micros();
    Serial.println();
    Serial.print("-- passe tempo --> SECTEURS PARCOURUS = ");  
    Serial.println(Iparc-1);
    for (byte i=1; i < Iparc; i++){
      Tparc=Tparct[i]-Tparct[i-1];
      Serial.print(Tparc); 
      Serial.print(";"); // delimiteur pour log tableur

    } 

    Serial.println();

    Iparc=0;
  }




}

// Interrupt on A changing state
void doEncoderA(){


  
  Tparct[Iparc]=micros(); // plus rapide 
  Iparc ++;

  Sint=true;

}

Bonjour,

Pour le hard il faut mettre une forte résistance sinon ça perturbe l'injection et le moteur tourne mal.
J'avais mis 100 k ohm.

Pour le programme pour le moment je ne comprends pas !
Pourquoi roue à l'arrêt, on ne compte pas de rotations mais des durées d'impulsions d'injection, c'est peut-être une question de vocabulaire ?

Je pensais quand même utiliser :
dureeInj = pulseIn(injecteur, LOW);
pour mesurer un temps d'injection

et ensuite le cumuler dans une variable peut-être (unsigned long ?) et vérifier (if) si le total est égal à xx ms et dans ce cas envoyer une impulsion calibrée au compteur de vélo ? Bien sûr remettre la variable à 0 et recommencer...

Pour le moment j'ai écris ça pour faire une simulation et lire le temps d'injection pas la liaison série :

/*
Mesure temps d'injection cumulé pour envoie impulsion au compteur de vélo qui affiche en Litres par heure
Pour une simulation la broche 2 injecteur est connectée par un fil en 3 qui est la sortie simulation
*/

const int injecteur = 2;              // broche information injection
const int simul = 3;                  // broche PWM pour simulation injecteur
const int consommation = 13;          // broche envoie consommation au compteur
unsigned long dureeInj;               // variable utilisée pour stocker la durée d'injection


void setup()  
{
 Serial.begin(9600);       // seulement pour simulation et affichage
 pinMode(injecteur, INPUT);   
 pinMode(simul, OUTPUT);
 pinMode(consommation, OUTPUT);
 digitalWrite (injecteur, HIGH);  // entrée injecteur est normalement à 1 au repos 
}
 
void loop()  
{
analogWrite(simul, 192);    // simulation avec F= 490 hz avec une valeur moyenne à état 0 (injection) : environ 0.5 ms à 192 soit 24% de T 2.04ms

dureeInj = pulseIn(injecteur, LOW);     // mesure temps d'injection quand on a 0 v
Serial.println(dureeInj);               // envoie durée injection sur port série seulement pour simulation
delay(1000);                            // tempo 1 sec pour affichage
dureeInj = pulseIn(injecteur, HIGH);    // mesure temps de repos injection on a 12v sur l'injecteur
Serial.println(dureeInj);               // envoie durée repos injection sur port série
delay(1000);                            // tempo 1 sec pour affichage
}

Je dois partir mais je m'y remets demain !

Merci

Bonjour,

J'ai compris (enfin je crois !) comment cumuler mes temps d'injection, il suffisait que je fasse
cumulInj = cumulInj + tempsInj et le remettre à 0 quand la condition est exacte ici : cumulInj >= 20 ms de temps cumulé d'injection, c'est vraiment très basique et j'ai cherché longtemps pour ne faire que ça !

Il faut dire qu'au début j'avais écrit le contraire et que ça me faisait une erreur et je cherchais à faire autrement alors que ce n'était qu'une question de syntaxe...

Maintenant il faudrait faire autrement que delay (100) pour l'impulsion de sortie, sinon évidemment pendant delay je rate toutes les impulsions d'injection !

/*
Mesure temps d'injection pour compteur de vélo qui affiche en Litres par heure
Pour une simulation la broche 2 injecteur est connectée par un fil en 3 qui est la sortie simulation
*/

const int injecteur = 2;        // broche capteur injection
const int simul = 3;            // broche PWM pour simulation injecteur
const int consommation = 13;    // broche envoie consommation au compteur
unsigned long dureeInj = 0;     // variable utilisée pour stocker la durée d'une injection
unsigned long reposInj = 0;     // variable utilisée pour stocker la durée d'un repos d'injection
unsigned long cumulInj = 0;     // variable utilisée pour stocker le cumul des durées d'injection


void setup()  
{
 pinMode(injecteur, INPUT);
 pinMode(simul, OUTPUT);
 pinMode(consommation, OUTPUT);
 digitalWrite (injecteur, HIGH);  // entrée injecteur est normalement à 1 au repos 
 digitalWrite(consommation,LOW);  // sortie consommation est à 0
}
 
void loop()  
{
analogWrite(simul, 192);    // test 490 hz avec une valeur moyenne à état 0 : environ 0.5 ms à 192 soit 24% de T 2.04ms

dureeInj = pulseIn(injecteur, LOW);
cumulInj = cumulInj + dureeInj;

if (cumulInj >= 20000)
{
digitalWrite(consommation,HIGH);
delay(100);
digitalWrite(consommation,LOW);
cumulInj = 0;
}

}

michelm:
Bonjour,

J'ai compris (enfin je crois !) comment cumuler mes temps d'injection, il suffisait que je fasse
cumulInj = cumulInj + tempsInj et le remettre à 0 quand la condition est exacte ici : cumulInj >= 20 ms de temps cumulé d'injection, c'est vraiment très basique et j'ai cherché longtemps pour ne faire que ça !

Il faut dire qu'au début j'avais écrit le contraire et que ça me faisait une erreur et je cherchais à faire autrement alors que ce n'était qu'une question de syntaxe...

Maintenant il faudrait faire autrement que delay (100) pour l'impulsion de sortie, sinon évidemment pendant delay je rate toutes les impulsions d'injection !

bonjour
il faut que tu passe par de la comparaison de millis()
exemple rapide pour ton programme
(compile mais pas testé)

/*
Mesure temps d'injection pour compteur de vélo qui affiche en Litres par heure
Pour une simulation la broche 2 injecteur est connectée par un fil en 3 qui est la sortie simulation
*/

const int injecteur = 2;        // broche capteur injection
const int simul = 3;            // broche PWM pour simulation injecteur
const int consommation = 13;    // broche envoie consommation au compteur
unsigned long dureeInj = 0;     // variable utilisée pour stocker la durée d'une injection
unsigned long reposInj = 0;     // variable utilisée pour stocker la durée d'un repos d'injection
unsigned long cumulInj = 0;     // variable utilisée pour stocker le cumul des durées d'injection
boolean imp = false;            // impulsion sortie en cours vrai faux
unsigned long actu;             // temps actuel 
void setup()
{
  pinMode(injecteur, INPUT);
  pinMode(simul, OUTPUT);
  pinMode(consommation, OUTPUT);
  digitalWrite (injecteur, HIGH);  // entrée injecteur est normalement à 1 au repos
  digitalWrite(consommation, LOW); // sortie consommation est à 0
}

void loop()
{
  analogWrite(simul, 192);    // test 490 hz avec une valeur moyenne à état 0 : environ 0.5 ms à 192 soit 24% de T 2.04ms

  dureeInj = pulseIn(injecteur, LOW);
  cumulInj = cumulInj + dureeInj;

  if (cumulInj >= 20000)
  { imp = true;
    cumulInj = 0;
    digitalWrite(consommation, HIGH); // impulsion sortie etat haut
    actu = millis();
  }


  if (imp == true)
  {
    if (millis() - actu >= 100)
    {

      digitalWrite(consommation, LOW); // impulsion sortie etat bas 
      imp = false;
    }


  }
}

Bonjour,

OK merci, je comprends le principe mais pas encore la manière.
Je teste : il y a un souci la sortie reste à 1 en permanence...
Il faut que j'étudie comment on fait avec millis.

Je comprends que :

"actu = millis();" on prend le temps actuel de millis à cet instant du programme

"if (imp == true)" il me semble que forcément ça sera vrai car avant il y a eu "imp = true;" non ?

"if (millis() - actu >= 100)
{
digitalWrite(consommation, LOW); // impulsion sortie etat bas
imp = false;"

si le temps nouveau de millis - actu (l'ancien temps) est supérieur à 100 ms on met la sortie consommation à 0, et on met imp = faux

Ça devrait fonctionner, mais non la sortie consommation reste à 1 en permanence...

michelm:
Bonjour,

OK merci, je comprends le principe mais pas encore la manière.
Je teste : il y a un souci la sortie reste à 1 en permanence...
Il faut que j'étudie comment on fait avec millis.

edit , je redigeais pendant que tu repondais :grin:

attention à une chose , ta durée d'impulsion en sortie
si elle est superieure à 2 cycles , elle sera toujours à HIGH par recouvrement
j'ai fait un test avec tes parametres et en mettant un peu de serial pour tester , ça decroche au dessus de 80 ms
tes 100 ms viennent d'où ? sont contraint par quoi ?

programme legerement modifié pour verifier les passages par les etapes haut bas

/*
Mesure temps d'injection pour compteur de vélo qui affiche en Litres par heure
Pour une simulation la broche 2 injecteur est connectée par un fil en 3 qui est la sortie simulation
*/

const int injecteur = 2;        // broche capteur injection
const int simul = 3;            // broche PWM pour simulation injecteur
const int consommation = 13;    // broche envoie consommation au compteur
unsigned long dureeInj = 0;     // variable utilisée pour stocker la durée d'une injection
unsigned long reposInj = 0;     // variable utilisée pour stocker la durée d'un repos d'injection
unsigned long cumulInj = 0;     // variable utilisée pour stocker le cumul des durées d'injection
boolean imp = false;            // impulsion sortie en cours vrai faux
unsigned long actu;             // temps actuel 

void setup()
{
  Serial.begin(115200);
  pinMode(injecteur, INPUT);
  pinMode(simul, OUTPUT);
  pinMode(consommation, OUTPUT);
  digitalWrite (injecteur, HIGH);  // entrée injecteur est normalement à 1 au repos
  digitalWrite(consommation, LOW); // sortie consommation est à 0
}

void loop()
{
  analogWrite(simul, 192);    // test 490 hz avec une valeur moyenne à état 0 : environ 0.5 ms à 192 soit 24% de T 2.04ms

  dureeInj = pulseIn(injecteur, LOW);
  cumulInj = cumulInj + dureeInj;

  if (cumulInj >= 20000)
  { imp = true;
    cumulInj = 0;
    digitalWrite(consommation, HIGH); // impulsion sortie etat haut
    actu = millis();
    Serial.print("1");
  }


  if (imp == true )
  {
    
    
    if (millis() - actu >= 80) // çà decroche au dessus
    {

      digitalWrite(consommation, LOW); // impulsion sortie etat bas 
      imp = false;
      Serial.print("0");
    }


  }
}

Oui c'est trop long 100 ms !
C'était pour être sûr que le compteur prenne bien l'impulsion, mais dans la réalité je n'ai pas forcément besoin de 100 ms (à essayer) et les impulsions d'injection ne sont pas forcément aussi proches.

Super ça fonctionne un grand merci Artouste de m'avoir très bien guidé !