//Strobo-Logger-compte-tours T et N par interruptions (isrEtin() et isrFlash()avec Timer1) char Ver[] = " Version du 3_3_17"; //Chaque étincelle declenche l'isrEtin qui calcul T et lance Timer1 pour Ddeg µs //Timer1 génère une it qui lance isrFlash() qui émet 1 flash // Strobo Logger Afficheur details sur: http://a110a.free.fr/SPIP172/article.php3?id_article=152 //********IMPORTANT : Moniteur et HC05/06 tous à 9600bps********************** //Hardware: 7805 alim 5V( branché sur +12V de l'auto) + HC 05 ou 06, 9600bps, Arduino (Uno, Nano etc) //La capture des étincelle se fait au primaire de la bobine par connexion directe et non par pince inductive //Ceci a un triple avantage: luminositée du flash doublée, fiabilité de capture et aucune pince inductive necessaire //Les commandes sont envoyées via un smartphone/tablette Android //N et Avance sont affichés sur l'ecran et il existe 2 touches:Avance +, Avance - //Un bouton pousoir de log est present sur le flash pour enregistrer le couple (N,Avance). //On doit fournir le nombre de cylindres (4 temps) .Pour un 2 temps, multiplier par 2 //Ce sketch a 2 fonctions: Logger (enregistre)les paires (Nt/mn, Avance en degrès) //et Afficheur des resultats sous forme de tableau, puis sous Excel de courbe. //AFFICHEUR: Copier la fenetre du moniteur et sauver en fichier .CSV, bon pour Excel. //COMPTER-TOURS : precis pour le réglage de la carburation, vitesse de rafraichissement ajustable //APPLI Smartphone: conseillée ,excellente et va bien aussi avec HC-06! //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 pour les boutons extrème gauche Av-, command m,Extrème droite Av+,command p,garder Line Feed //Sur moniteurIDE Arduino en bas à droite, choisir Nouvelle ligne et 9600 bauds //***************MODE D'EMPLOI************************** //Connecter le fil de capture d'étincelle sur lasortie du primaire de la bobine //Connecter la masse puis le + sur le +12 de la bobine. // Activer le Bluetooth sur le smartphone.Lancer //La parametrer à la première utilisation seulement ( voir l'article Strobo Logger Afficheur) //************************************************* #include "TimerOne.h" #include // EEPROM.read(adEP);EEPROM.write(adEP); #include SoftwareSerial BT(10, 11); // RX,TX respectivement vers le HC05/06 à 9600bps String Salut = "Bonjour, Strobo-Logger-Afficheur-CompteTours"; //Affiché au demarrage // L'objet String a ses methodes: .readStringUntil('r') et .toInt() byte Type_de_log[] = {'S', 't', 'r', 'o'};//Stroboscope byte Label_x[] = {'N', ' ', 't', '/', 'm', 'n'};//Axe horizontal byte Label_y[] = {'A', 'V', ' ', 'd', 'e', 'g'};//Axe vertical int Ncyl = 4; //Declarer le nb de cylindre car on se connecte au primaire bobine //Pour un moteur 2 temps, multiplier par 2 le nombre de cylindres int D_Flash = 50; //Durée du flash en µs //C'est un compromis entre précision(faible étalement du spot ) et luminosité int a1 = 0; //Debug.Pour EP_print(), premièr byte int a2 = 140; //Debug.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 Etin 2 //Entrée de l'étincelle, sur D2, IT 0,montant #define Flash 4 //Sortie vers flash #define BPl 6 //Entrée BP de log, double celui du sphone #define LED13 13 //Led standard de l'Arduino #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 signed long T = 0; //Periode en cours(signée pour le calcul de D_deg) int unsigned long prec_H = 0; //Heure du front precedent en µs int unsigned long D_deg = 0;//Délai pour deg_dem degrès en µs int degT = 10000; //La periode T entre 2 étincelles correspond à degT degrés = 720/Ncyl en 4 temps //Exemple: pour 4 cylindres T correspond à 180° vilo (90° A à C) int unsigned long N = 0; //N en tours/mn, peut monter à plus de 44 000, 4 temps int signed deg_dem = 0; //Compteur des degrés demandés,affiché au smartphone int degInitial = 15; //Affiché au demarrage int D_deg_min = 15000;//En µs,lié à limite de la fonction delayMicroseconds() <16383 int milli_delay = 0; //Delai en ms, T > T_min int micro_delay = 0; //Delai en µs, T > T_min int tcor1 = 10;//Correctif attente avant flash en µs, N>6000t/mn 4 temps int tcor2 = 70;//Correctif attente avant flash en µs, N<6000t/mn 4 temps 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, N et t/mn byte y = 0; // sur axe vertical , Av en degrés 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 volatile float monDelai = 0;//Pour eviter delay() en conflit avec les isr() volatile float del = 100000; //attente 1.3s //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() ///////////////////////////////////////////////// { 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 // Serial.print("Essai : "); Serial.println(NomEssai); //Afficher son nom BT.print("Essai : "); BT.println(NomEssai); //BT.println(); Serial.println( while (v != 255) { ptr++; x = EEPROM.read(ptr); if (x == 255)break;//Sortie normale sur fin d'essai Serial.print(x * 100); BT.print(x * 100); 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); } //delay(1000);//Option // Serial.println("c et Envoyer pour essai suivant "); BT.println("c pour essai suivant "); GetLigne();//Attente ici pour lancer la capture dans CoolTerm } //Serial.println("Fin des essais. A bientot "); BT.println(F("Fin des essais. A bientot ")); BT.println(F("Pour redemarrer, bouton Reset sur l'Arduino")); while (1);//Boucle ici indefiniement. } void ClotureEssai()////////////////////////////////////// { NomEssai ++; ptr++; //Fin d'essai, sauter le 255 Put_ptr(); //Preparer ptr pour ecrire le nom du futur essai+ BT.println(F("Fin de l'essai ")); BT.println(""); // Serial.println("Fin de l'essai "); monDelai = 1 ; while (monDelai < del) monDelai++ ; //del=100 pour 1.24ms environ, del =10000 pour 126 ms environ } void compteTours()/////////////////////////////////////////// { IniT(); BT.println(); BT.println(); BT.println(F("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) { //L'isrEtin() calcul T en permanence //Utiliser l'appli BlueTerm+ qui reconnait CR=13:on ecrit N, on attend, CR, on imprime des espaces, CR BT.print(N = k / T); 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]); // EP_print();ps(ptr); for (int i = 6; i <= 11; i++)EEPROM.write(i, Label_x[i - 6]); //EP_print();ps(ptr); 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); { //Pour debug: 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 GetNcyl()//////////////////////////////////////////// { BT.print(F("Nb de cylindres = ")); BT.println(Ncyl); // Serial.print("Nb de cylindres = "); Serial.println(Ncyl); BT.println("c ou taper la valeur desiree"); // Serial.println("c ou taper la valeur desiree "); GetLigne(); if ((IntLigne >= 1) && (IntLigne <= 12)) Ncyl = IntLigne; //Les car sont<255 BT.print("Nb de cylindres = "); BT.println(Ncyl); k = k / Ncyl; //Ajuster pour calcul de N deg_dem = degInitial; //Avance au lancement degT = 720 / Ncyl; //La periode T entre 2 étincelles correspond à degT degrés D_deg = 200000; //Init 200ms } 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 IniT()////////////////////while (1); delay(1000);/////////////// { attachInterrupt(0, isrEtin, RISING); //IT0 sur D2, front montant, isrEtin() executée Timer1.attachInterrupt(isrFlash);//Emet lun flash, Ddeg après Etin Timer1.stop(); D_deg = 100000;//Premier flash 100ms } void isrEtin()/////////////////////////////// { T = micros() - prec_H; //D2 est monté, calculer T prec_H = micros(); //heure de début prochaine periode Timer1.initialize(D_deg);// Flash après delai D_deg µs } void isrFlash()//////////////////////////////// { Timer1.stop(); digitalWrite (Flash, 1); delayMicroseconds(D_Flash); digitalWrite (Flash, 0); digitalWrite (LED13, 1); delayMicroseconds(10 * D_Flash); digitalWrite (LED13, 0); D_deg = float(T * deg_dem) / float(degT); //Délai en µs pour les degrés demandés, periode suivante } void Log()///////////////////////////////////////////////// { ScanLog();//Afficher tous les essais en EEPROM BT.println(F("A la fin des essais: bouton Reset sur l'Arduino")); BT.println(); Serial.println(); Serial.println(F("A la fin des essais: bouton Reset sur l'Arduino")); GetNcyl();//Nombre de cylindres en 4temps while (1) //Nouvel essai { //Propose de demarrer un essai c'est à dire le log de paires (N,Av) BT.print("Essai en attente "); BT.println(NomEssai); Serial.print("Essai en attente "); //BT.print("N t/mn "); Serial.print("N t/mn "); BT.println(N * 100); Serial.println(N * 100); BT.print("Avance "); BT.println(deg_dem); BT.println("Quand le moteur tourne, c pour lancer un essai "); while (1) //Attendre ici quand moteur arrete { if (T < 200000)break; //Moteur en marche } Ligne = ""; //Le moteur tourne, attendre Accord de demarrage d'essai while (1) { Ligne = ""; Rafdeg_dem(); // mise à jour des degrés selon les boutons Av+ et Av- GetLigneauVol(); //delay(100); if (Ligne == Accord)break; } Ligne = ""; //Demarrer l'essai BT.print("Essai "); BT.print(NomEssai); // Serial.print("Essai "); Serial.print(NomEssai); BT.println(" en cours "); BT.println("Pour terminer l'essai, taper c "); // Serial.println(" en cours");Serial.println("c pour arreter "); EEPROM.write(ptr, NomEssai); ptr++; //Ecrit Nom de l'essai Put_ptr();//Sera lu par Wxy() while (1) //Essai en cours { Rafdeg_dem(); // Maj de deg_dem, lit Ligne au vol if (Ligne == Accord)break; // Ligne lue par Rafdeg_dem, on veut arreter l' essai if (digitalRead(BPl) == 0) //Log demandé par appui sur le BP { //On n'utilise pas delay() avec les interruptions, d'où ce delai calculé monDelai = 1 ; while (monDelai < del) monDelai++ ; //del=100 pour 1.24ms environ if (digitalRead(BPl) == 0);//Anti rebob, attendre si encore appuyé N = k / T; //Calcul des t/mn/100 if (N >= 60)break; //N> 6000t/mn, erreur x = N; y = deg_dem;//Avance en degrés Wxy();//Ecrit en EP BT.print("Av = "); BT.println(deg_dem); BT.print("N = "); BT.println(N * 100); BT.println("c pour arreter "); Serial.println("c pour arreter "); } Ligne = "";//Essai en cours } Ligne = "";//Fin d'essai ClotureEssai(); } } void Put_ptr()////////////////////while (1); delay(1000);/////////////// { //Sauve ptr en EP EEPROM.write(0, highByte(ptr)); EEPROM.write( 1, lowByte(ptr)); } void Rafdeg_dem()///////////////////////////////////// //Mise à jour de deg_dem, avance demandée { GetLigneauVol(); //Rafraichir deg_dem si + p ou - m au clavier if (Ligne == "m") { deg_dem--; //Bouton Av-- ou m Ligne = ""; BT.print("Av degres "); BT.println(deg_dem); // Serial.print("Av degre "); Serial.println(deg_dem); } if (Ligne == "p") { deg_dem++; //Bouton Av++ ou p Ligne = ""; BT.print("Av degres "); BT.println(deg_dem); // Serial.print("Av degre ");Serial.println(deg_dem); } } 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 : "); BT.println(NomEssai); //Afficher son nom // Serial.print("Essai : "); Serial.println(NomEssai); while (v != 255) { ptr++; //ignorer les x,y v = EEPROM.read(ptr); } } //Fin de cet essai, ptr pointe sur 255 de fin d'essai //Fin de tous les essais Put_ptr();//Sauver ptr vers le premier essai vierge NomEssai++;//Pour futur essai BT.print("Mem restante: "); BT.print(1024 - ptr); BT.println(" sur 1024 "); // Serial.print("Mem restante: "); Serial.print(1024 - ptr); Serial.println(" sur 1024 "); BT.println(F(" c sinon taper z pour Effacer!! toute la memoire ")); // Serial.println(" c sinon z et Envoyer pour EFFACER "); GetLigne(); if (Ligne == "z")EP_init(); } 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(F("Si ces caracteres sont bizarres, effacer toute la memoire en tapant z" )); // Serial.println("Si ces caracteres sont bizarres, effacer toute la memoire en tapant z" ); BT.println(F(" 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("Erreur! Redemarrer et z pour Effacer la memoire"); while (1);//On s'arrete ici } } void Wxy() ////////////////////while (1); delay(1000); { // Ecrit la paire en EP 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 pinMode(Flash, OUTPUT);// pinMode(LED13, OUTPUT);//Repetiteur de flash pinMode(BPl, INPUT_PULLUP);//BP de log, pour mettre en memoire la paire N,Av 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(__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(); // EP_print(); while (1); //Pour debug IniT(); // while (1){Serial.println(T); BT.println(T);delay(1000);} } 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 } }