//AFR-Logger-Afficheur-compte-tours. Mesure de T donc N par polling char Ver[] = " Version du 3_3_17"; //Hardware: 7805 alim 5V( branché sur +12V de l'auto) + HC 05 ou 06, 9600bps, Arduino (Uno, Nano etc) //Ce sketch a 3 fonctions: --Logger (enregistre)la valeur de l'AFR tous les bip microsecondes(typique 0.2s) //AFFICHEUR des resultats sous forme de tableau à exporter vers Excel. //COMPTER-TOURS : precis pour le réglage de la carburation, vitesse de rafraichissement ajustable //La capture des étincelle se fait au primaire de la bobine par connexion directe et non par pince inductive //Ceci procure un double avantage:fiabilité de capture et aucune pince inductive necessaire //Les commandes sont envoyées via un smartphone/tablette Android //LOGGER: on affiche le regime de demarrage de l'essai par Ndem = 4000, par exemple //et le regime de fin d'essai, Nfin = 6000 par exemple //On peut enregistrer plusieurs essais consecutifs. //AFFICHEUR: Copier la fenetre du moniteur et sauver en fichier .CSV, reconnu par Excel. //APPLI Smartphone conseillée: ,excellente et va bien aussi avec HC-06! //Sur l'ecran de cette appli, 3 points en haut à droite:Settings, decocher Carriage return, garder Line Feed //Une fois pour toutes : // via la fonction Bluetooth du smartphone on donne le mot de passe du module qui est toujours 1234. //Lancer l’appli qui recherche le module HC 05/06 et s’y connecte. La première fois : 3 points en haut à droite : Settings, //décocher Carriage return, garder Line Feed. Ensuite programmer le bouton central par appui prolongé : //Button Name c, Command : c et decocher Carriage return, garder Line Feed //Ainsi l’appui sur c par exemple est identique à l’envoi de la lettre ’c’ sur Smartphone et moniteur. //Idem sur moniteurIDE Arduino en bas à droite, choisir Nouvelle ligne et 9600 bauds //Une autre appli BlueTerm+ a l'avantage en mode comptetours d'afficher les t/mn au même endroit sur la ligne //mais elle est moins complète et n'a pas de boutons programmables //***************MODE D'EMPLOI************************** //Connecter le fil de sortie du primaire de la bobine sur D12 de l'Arduino (Uno, Nano...) //Connecter la masse et le + sur le +12 de la bobine. //Connecter la sonde AFR sur A4 //Adapter Ncyl si necessaire. Activer le BT sur le smartphone.Lancer #include "TimerOne.h" #include // EEPROM.read(adEP);EEPROM.write(adEP); #include SoftwareSerial BT(10, 11); // RX,TX respectivement int unsigned long bip = 500000;//Timer1 IT toutes les bip microseconds, typique 200000 String Salut = "Bonjour, AFR Logger-Afficheur -CompteTours"; //Affiché au demarrage // L'objet String a des methodes: .readStringUntil('r') et .toInt() byte Type_de_log[] = {'A', 'F', 'R', '1'};//Acceleration byte Label_x[] = {'N', ' ', 't', '/', 'm', 'n'}; byte Label_y[] = {'A', 'F', 'R', '*', '1', '0'}; int Ndem = 10;//N/100, demarrage du log, par defaut int Nfin = 40;//N/100,arret du log, par defaut int Ncyl = 4; //Declarer le nb de cylindre car on se connecte au primaire bobine, par defaut //Pour un moteur 2 temps, multiplier par 2 le nombre de cylindres //4 cyl 4temps, T=30ms/1000t/mn, T=5ms/6000t/mn //L'AFR est calculé par AFR = 2.94*InAFR + 7.4 //Ex: Pour InAFR = 5V, AFR = 22.2 //La conversion analogique numerique donne 0<=sig<=1023 //C'est une droite AFR = (2.94/1023)*sig +7.4 = a*sig + b float tCum = 0; //Cumul des temps c a d des bip = float Vref = 4.92; //Alim en volts float a = Vref * 2.94 / 1023;//pente float b = 7.4;//ordonnée à l'origine int Nmax = 0; //Affiché en fin d'essai int a1 = 0; //Pour EP_print, premièr byte int a2 = 40; //Pour EP_print, dernier byte String Accord = "c"; // Emis par le bouton c ou le clavier du smartphone ; #define Etin 12 //Entrée de l'étincelle, sur D12, montant #define InAFR A4 //Entrée analogique 0-5V de la sonde lambda linéaire #define Ad_ptr 0 //En EEP , ptr est stocké sur 2 bytes en 0 et 1 byte NomEssai = 1;//Les essais sont numerotés par 1,2,3... String Ligne;//Ligne lue au clavier jusqu'a \n int IntLigne = 0; //Ligne convertie en entier byte v = 0; //valeur lue de l'EP int ptr = 0;// Pointeur vers EEP, de 0 à 1023 int ptr_H = 0; //MSB de ptr int ptr_L = 0;//LSB de ptr byte x = 0; // sur axe horizontal, le temps cumulé en unités bip µs byte y = 0; // sur axe vertical , N et AFR int sig = 0; //Valeur de 0 à 1023 lue sur InAFR int unsigned long T = 0; //T période entre deux fronts d'étincelle en mus int unsigned N = 0; //N t/mn instantané. En fait c'est N / 100 int unsigned long prec_H = 0; //temps d'arrivée du front precedent en µs //float k = 300000; //Calcul de N /100 pour entree bobine 4 cyl float k = 1200000; //Calcul de N/100 pour entree , 4 temps,1 cyl: N=60, T=20ms int rafN = 1000; //Rafraichissement de N en mode compteTours int pas_rafN = 100; //En ms pour ++ ou -- sur rafN //DEBUG //Deux macros de debug #define ps(v) Serial.print("Ligne_") ; Serial.print(__LINE__) ;Serial.print(" ; ") ; Serial.print(#v) ; Serial.print(" = ") ;Serial.println((v)) ; Serial.println(" Sketch stop"); while (1); //Exemple, à la ligne 140, l'instruction ps(var1); //inprimera "Ligne_140var1 = 18 Sketch stop" //Macro pc(v)de debug pour imprimer le numero de ligne, le nom d'une variable, sa valeur, //puis s'arreter et attendre un clic de souris sur le bouton 'Envoyer'en haut de l'ecran seriel pour continuer. #define pc(v) Serial.print("Ligne_") ; Serial.print(__LINE__) ;Serial.print(" ; ") ; Serial.print(#v) ;Serial.print(" = ") ; Serial.println((v)) ; Serial.println(" Clic bouton 'Envoyer' pour continuer") ;while (Serial.available()==0);{ int k_ = Serial.parseInt() ;} //Exemple, à la ligne 145, l'instruction pc(var2); // inprimera "Ligne_145var2 = 25.3 Clic bouton 'Envoyer' pour continuer" ///////////////////LES FONCTIONS///////////////////////////// void Afficheur() ///////////////////////////////////////////////// { //ScanLog();//Afficher tous les essais en EEPROM VerifEntete();//Imprime le debut de l'EEPROM Serial.println(F("Pour tracer ces courbes sous Excel : ")); Serial.println(F("Copier les 2 ou 3 colonnes d'un essai avec Ctrl+C ")); Serial.println(F("Coller dans un editeur de texte rudimentaire ")); Serial.println(F("Renommer le fichier de .txt en .csv ")); Serial.println(F("Un double clic lancera Excel avec ces colonnes ")); while (1) { ptr++; //pointe vers valeur suivant le 255 de fin d'essai v = EEPROM.read(ptr); if (v == 255)break; //Fin des essais NomEssai = v; //les x,y vont suivre tCum = 0; //Demarre l'axe des temps BT.print(F("Essai : ")); Serial.print(F("Essai : ")); //Afficher son nom BT.println(NomEssai); Serial.println(NomEssai); //BT.println(); Serial.println( while (v != 255) { ptr++; x = EEPROM.read(ptr); if (x == 255)break;//Sortie normale sur fin d'essai tCum = tCum + bip;//Cumul des temps en µs Serial.print(tCum / 1000000); BT.print(tCum / 1000000); //tCum en secondes Serial.print(";"); BT.print(";"); //P; semi colon pour format ComaSV! Serial.print(x * 100); BT.print(x * 100); //N t/mn Serial.print(";"); BT.print(";"); //P; semi colon pour format ComaSV! ptr++; y = EEPROM.read(ptr); if (y == 255)break;//Sortie anormale!!! Serial.println(y ); BT.println(y );//AFR*10 } BT.println(F("c pour essai suivant ")); Serial.println(F("c et Envoyer pour essai suivant ")); GetLigne();//Attente ici pour lancer la capture dans CoolTerm } BT.println(F("Fin des essais. A bientot ")); Serial.println(F("Fin des essais. A bientot ")); BT.println(F("Pour redemarrer, bouton Reset sur l'Arduino")); Serial.println(F("Pour redemarrer, bouton Reset sur l'Arduino")); while (1);//Boucle ici indefiniement. } void clotureEssai() //////////////////////////////////////////////////////// { NomEssai++;//Pour essai suivant ptr++; //Laisser un 255 comme fin d'essai Put_ptr();//Sauver ptr pour prochain essai, vers le nom de l'essai Serial.println(F("Fin d'essai ")); BT.println(F("Fin d'essai ")); Serial.print("N max t/mn = "); BT.print("N max t/mn = "); Serial.println(Nmax * 100); BT.println(Nmax * 100); Serial.println(); BT.println(); } void compteTours()/////////////////////////////////////////// { BT.println(); BT.println(); BT.println("Suggestion: pour une sensibilite maximale, garder Ncyl = 1"); Ncyl = 1; GetNcyl(); k = 100 * k; //Pour la fonction compteTours, N en t/mn (et non t/mn/100) BT.println(); BT.println(F("A tout moment, possibilite d'ajuster la vitesse de rafraichissement par :")); BT.println(); BT.println(F(" 'p'lus + + ou 'm'oins - -")); BT.println(); BT.println(" N t/mn"); while (1) { GetN(); //Utiliser l'appli BlueTerm+ qui reconnait CR=13:on ecrit N, on attend, CR, on imprime des espaces, CR BT.print(N); delay(rafN); BT.write(13); BT.print(" "); BT.write(13); GetLigneauVol(); //Rafraichir deg_dem si + p ou - m au clavier if (Ligne == "m")rafN = rafN + pas_rafN;//Moins vite, attendre plus if (Ligne == "p")rafN = rafN - pas_rafN; if (rafN < pas_rafN)rafN = 10;// Le plus vite est 10ms } } void EcritNomEssai() { Get_ptr(); //A chaque debut d'essai, c'est à dire quand N depasse Ndem EEPROM.write(ptr, NomEssai); ptr++; Put_ptr(); } void EP_init()////////////////////while (1); delay(1000);/ { EP_raz(); // Ecrit 255 ds toute l'EP for (int i = 2; i <= 5; i++)EEPROM.write(i, Type_de_log[i - 2]); for (int i = 6; i <= 11; i++)EEPROM.write(i, Label_x[i - 6]); for (int i = 12; i <= 17; i++)EEPROM.write(i, Label_y[i - 12]); EEPROM.write(Ad_ptr, 0); EEPROM.write(Ad_ptr + 1, 19); //Init ptr vers Nom du premier essai NomEssai = 1; //Premier Essai } void EP_print()////////////////////while (1); delay(1000); { // imprime EEP de a1 à a2 for (int i = a1; i <= a2; i++) { int j = EEPROM.read(i); Serial.print(i); BT.print(i); Serial.print("\t"); BT.print("\t");//Tabulation, interessant Serial.print(j); BT.print(j); //Pour imp des valeurs 0-255 Serial.print("\t"); BT.print("\t");//Tabulation Serial.write(j); BT.write(j);//Pour imp des car Ascii Serial.println(); BT.println(); delay(4); } } void EP_raz()////////////////////while (1); delay(1000);/ { // Ecrit 255 ds toute l'EP for (int i = 0; i <= 1023; i++) EEPROM.write(i, 255); //Tout à 255, code de fin d'essai } void GetLigne()/////////////////////////// { //CharLu=65;Serial.println( CharLu);donne 65 et Serial.write( CharLu);donne A while (1) //Lire une ligne , fin par \n { if (BT.available() ) { Ligne = BT.readStringUntil('\n'); BT.println();//Ex "z" ou "4500" break; } if (Serial.available() ) { Ligne = Serial.readStringUntil('\n'); Serial.println();//Ex "z" ou "4500" break; } } IntLigne = Ligne.toInt();//la string "4500" donne l'entier 4500 } void GetLigneauVol()//////////////////////// { if (BT.available() ) { Ligne = BT.readStringUntil('\n'); BT.println();//Ex "z" ou "4500" } if (Serial.available() ) { Ligne = Serial.readStringUntil('\n'); Serial.println();//Ex "z" ou "4500" } } void GetN()/////////////////////////////////////// { while (digitalRead(Etin) == 1); //Attente si encore niveau haut while (digitalRead(Etin) == 0); //Attendre front montant prec_H = micros(); while (digitalRead(Etin) == 1);//Attente descente/ while (digitalRead(Etin) == 0); //Attendre front montant T = micros() - prec_H ; // prec_H = micros(); // float k = 300000; N = float(k) / float(T); //C'est N/100 en fait } void GetNcyl()//////////////////////////////////////////// { Serial.print(F("Nombre de cylindres = ")); BT.print(F("Nombre de cylindres = ")); Serial.println(Ncyl); BT.println(Ncyl); Serial.println(F("c ou taper la valeur desiree ")); BT.println(F("c ou taper la valeur desiree")); GetLigne(); if ((IntLigne >= 1) && (IntLigne <= 12)) Ncyl = IntLigne; //Les car sont<255 BT.print("Nombre de cylindres = "); BT.println(Ncyl); k = k / Ncyl; //Ajuster pour calcul de N } void GetNdem()//////////////////////////////////// { BT.print("Ndemarrage = "); Serial.print("Ndem= "); BT.println(Ndem * 100); Serial.println(Ndem * 100); //= 500) && (IntLigne <= 10000)) Ndem = IntLigne / 100; //Les car sont<255 BT.print("Ndem = "); BT.println(Ndem * 100); BT.println(); Serial.print("Ndem = "); Serial.println(Ndem * 100); } void GetNfin()//////////////////////////////////// { BT.print("Nfin= "); Serial.print("Nfin= "); BT.println(Nfin * 100); Serial.println(Nfin * 100); //= 500) && (IntLigne <= 10000)) Nfin = IntLigne / 100; //Les car sont<255 BT.print("Nfin = "); BT.println(Nfin * 100); BT.println(); Serial.print("Nfin = "); Serial.println(Nfin * 100); BT.println(F("En attente de demarrage")); Serial.println(F("En attente de demarrage")); } void Get_ptr()////////////////////while (1); delay(1000);/////////////// { //Relit ptr de l'EP ptr_H = EEPROM.read(0); ptr_L = EEPROM.read(1); ptr = (ptr_H << 8 ) + ptr_L; } void isrBip()/////////////////////////////////////////// { Timer1.stop();//Overflow de Timer1 vient d'arriver x = N; //t/mn /100 ex: 51 pour 5100t/mn sig = analogRead(InAFR);//0-1023 pour 0- Vref typique 4.9 Volts y = 10 * (a * float(sig) + b) ; // AFR*10, de 740 à 2220 noInterrupts(); Wxy();//Ecrit en EP interrupts(); delay(10); Timer1.initialize(bip);//Relancer le Timer1 pour bip µs } void Log()///////////////////////////////////////////////// { ScanLog();//Afficher tous les essais en EEPROM BT.println(F("A la fin des essais: bouton Reset sur l'Arduino")); Serial.println(F("A la fin des essais: bouton Reset sur l'Arduino")); BT.println(); Serial.println(); GetNcyl(); while (1) //Propose de demarrer un essai c'est à dire le log de paires N,AFR { BT.print("Essai "); Serial.print("Essai "); BT.println(NomEssai); Serial.println(NomEssai); GetNdem(); //N de demarrage d'essai GetNfin(); //N de fin d'essai while (1) //On attend ici tant que N = Ndem)break; //On peut demarrer } EcritNomEssai();//Sauver en EEP le nom d'essai BT.print("Essai "); Serial.print("Essai "); BT.print(NomEssai); Serial.print(NomEssai); BT.println(" en cours "); Serial.println(" en cours"); Timer1.attachInterrupt(isrBip);//Toutes les bip ms, executer l'isrBip() Timer1.initialize(bip); //Lancer le Timer1 while (1) //Continuer tant que N < Narret, sinon fin d'essai { // Dans cette boucle, on attent les IT d'overfow de Timer1, toutes les bip microseconds GetN(); if (x > Nfin) //x et non N, pourquoi? En ts cas indispensable! { Timer1.stop(); Timer1.detachInterrupt(); Nmax = x; x = 0;//Fin d'essai break; } } clotureEssai();//Afficher Nmax } } void Put_ptr()////////////////////while (1); delay(1000);/////////////// { //Sauve ptr en EP EEPROM.write(0, highByte(ptr)); EEPROM.write( 1, lowByte(ptr)); } void ScanLog()/////////////////////////// { VerifEntete();//Extrait le debut de l'EEPROM while (1) { ptr++; //pointe vers valeur suivant le 255 de fin d'essai v = EEPROM.read(ptr); if (v == 255)break; //Fin des essais NomEssai = v; //les x,y vont suivre BT.print("Essai : "); Serial.print("Essai : "); //Afficher son nom BT.println(NomEssai); Serial.println(NomEssai); //BT.println(); Serial.println( while (v != 255) { ptr++; //ignorer les x,y v = EEPROM.read(ptr); } } //Fin de cet essai, ptr pointe sur 255 de fin d'essai //Ici fin de tous les essais Put_ptr();//Sauver ptr vers le premier essai vierge NomEssai++;//Pour futur essai BT.print("Memoire restante: "); BT.print(1024 - ptr); BT.println(" sur 1024 "); Serial.print("Memoire restante: "); Serial.print(1024 - ptr); Serial.println(" sur 1024 "); BT.println(" c sinon taper z pour reinitialiser la memoire! ATTENTION! "); Serial.println(" c et Envoyer sinon z et Envoyer pour EFFACER la memoire! ATTENTION! "); GetLigne(); if (Ligne == "z") { EP_init(); BT.println("Pour redemarrer, bouton Reset sur l'Arduino"); Serial.println("Pour redemarrer, bouton Reset sur l'Arduino");; while (1);//On s'arrete ici } } void VerifEntete()//////////////////////////////// { //Affichage sur PC et smartphone, utilisée par ScanLog() et Afficheur() // Avec Coolterm par exemple, l'ecran peut etre capturé dans un fichier.csv //Afficher nom du log Serial.println(); Serial.println(); Serial.println(); Serial.println(F("Important! En bas de l'ecran, a droite, selectionner Nouvelle Ligne ")); Serial.println(); Serial.println(); Serial.println(); delay(2000); BT.println("Relecture de la memoire EEPROM "); Serial.println("Relecture de la memoire EEPROM "); BT.println(); Serial.println(); BT.print("Nom de ce Log: "); Serial.print("Nom de ce Log: "); for (int i = 2; i <= 5; i++)BT.write(EEPROM.read(i)); for (int i = 2; i <= 5; i++)Serial.write(EEPROM.read(i)); BT.println(); Serial.println();//A la ligne après Write BT.print("Axe horizontal: "); Serial.print("Axe horizontal: "); for (int i = 6; i <= 11; i++)BT.write(EEPROM.read(i)); for (int i = 6; i <= 11; i++)Serial.write(EEPROM.read(i)); BT.println(); Serial.println();//A la ligne après Write BT.print("Axe vertical: "); Serial.print("Axe vertical: "); for (int i = 12; i <= 17; i++)BT.write(EEPROM.read(i)); for (int i = 12; i <= 17; i++)Serial.write(EEPROM.read(i)); BT.println(); Serial.println();//A la ligne après Write BT.println(); Serial.println(); BT.println(); Serial.println();//A la ligne après Write BT.println("Si ces caracteres sont bizarres, pour reinitialiser la memoire taper z" ); Serial.println("Si ces caracteres sont bizarres, effacer toute la memoire en tapant z" ); BT.println(" Sinon continuer avec c" ); Serial.println(" Sinon continuer avec c" ); GetLigne(); if (Ligne == "z")EP_init(); ptr = 18; //Init le pointeur à l'EP vers debut premier essai NomEssai = 0; v = EEPROM.read(ptr);// doit être 255, debut d'essai if (v != 255) { BT.print(F("Erreur! Redemarrer et z pour Effacer la memoire")); Serial.print(F("Erreur! Redemarrer et z pour Effacer la memoire")); while (1);//On s'arrete ici } } void Wxy() ////////////////////while (1); delay(1000); { // Ecrit la paire en EEP et sauve le pointeur en EEP Get_ptr(); //Relit ptr de l'EEP EEPROM.write(ptr, x); ptr++; EEPROM.write(ptr, y); ptr++; Put_ptr(); } void setup() ///////////////////////////////////////////////////////////// { pinMode(Etin, INPUT);//1 qd etincelle BT.begin(9600);//La liaison série soft D10 et D11 vers module Bt HC05 ou 06 !!!VERIFIER cette vitesse!! Serial.begin(9600);//La série standard, hardware, D0 et D1 vers PC!!VERIFIER cette vitesse!! BT.println(); Serial.println(); BT.println(); Serial.println(); Serial.println(__FILE__); Serial.println(__DATE__); Serial.println(__TIME__); BT.println(__DATE__); BT.println(__TIME__); BT.print(" "); Serial.println(Ver); BT.println(Ver); BT.println(); BT.println(); Serial.println(Salut); BT.println(Salut); BT.println(); BT.println(); } void loop()///////////////////////////////////// { BT.println(" Choisir le log "); BT.println("--ou l'afficheur"); BT.println("--ou le compte-tours") ; // Serial.println(" Choisir le log ou l'afficheur ou le compte-tours") ; BT.println(); //Serial.println(); while (1) //On a 3 s pour appuyer sur le bouton c ( c pour le moniteur) { BT.println("Demarrer le log c ?") ; Serial.println("Demarrer le log? c et Envoyer ") ; Ligne = "";//Raz Ligne delay(3000);//Attendre le choix GetLigneauVol(); if (Ligne == Accord)Log();//Soit le bouton c pour le smartphone, soit c pour le moniteur BT.println("Demarrer l'afficheur c ?") ; Serial.println("Demarrer l'afficheur? c et Envoyer ") ; Ligne = "";//Raz Ligne delay(3000);//Attendre le choix GetLigneauVol(); if (Ligne == Accord)Afficheur();//Soit le bouton c pour le smartphone, soit c pour le moniteur BT.println("Demarrer le compte-tours c ?") ; Serial.println("Demarrer le compte-tours c ?") ; Ligne = "";//Raz Ligne delay(3000);//Attendre le choix GetLigneauVol(); if (Ligne == Accord) compteTours();//Soit le bouton c pour le smartphone, soit c pour le moniteur } }