//***************************************************************** //ChronoAcc pour Arduino Nano (ou autres compatibles) char Ver[] = "Ver. du 19_2_16"; //***************************************************************** //Mesure le temps écoulé pour passer de N1 à N2 t/mn //L'objectif est de quantifier la variation de performances entre réglages //Le capteur d'étincelles doit être branché sur un fil de bougie #include // EEPROM.read(adEP);EEPROM.write(adEP); #include //lcd.begin(16, 2);lcd.clear();colonnes 0-15,lignes 0-1 //lcd.setCursor(15,0)= col 15, ligne 0;lcd.print(" text"); LiquidCrystal lcd(12, 10, 5, 4, 3, 6);// On instancie un lcd // pins: R/S ==12, Enable==10, puis D4-D7==5,4,3,6.Ne pas oublier e // l'eclairage (pin 15 et 16 du LCD), et le contraste à 0.5v environ, pin 3 du LCD byte deb = 1; //pour debugging, voir SETUP() const int BP1 = 8; //Entrée sur D8, boutons poussoir vers la masse, avec Pullup à +5V const int BP2 = 7; //Entrée sur D7 const int inPulse = 2; //Entrée sur D2 du front d'étincelle const int N1init = 3000; //Pour premier run après initialisation const int N2init = 6200; // const int stepN = 100;// t/mn increment de N const int unsigned long K = 120000000;// Pour calcul de Nt/mn = K/T, T en µs int N1 = 0; //t/mn les bornes désirées, ajustées avec les BP int N2 = 0; //t/mn int T2 = 0; //Dans Run(), sert pour comparer T à T2 byte b1 = 0; //état de BP1 pour cet échantillon byte b2 = 0; //état de BP2 pour cet échantillon byte sig1 = 0; //cumul de b1 durant un cycle d'echantillonage byte sig2 = 0; //cumul de b2 durant un cycle d'echantillonage byte nEch = 10; //Nombre d'echantillons des BP pendant un cycle byte espEch = 100;//espacement des échantillons en ms byte sLong = 8; // Le BPI poussé est déclaré Long quand sigI>=sLong volatile int unsigned long D = 0; //Accumule la durée d'un run, en µs volatile int cumDF = 0; //Flag pour D volatile int unsigned long T = 0; //T période entre deux fronts d'étincelle en µs volatile int unsigned long prec_H = 0; //temps d'arrivée du front precedent en µs volatile int unsigned N = 0; //N t/mn instantané, N=K/T volatile int affNF = 0; // Flag d'affichage ou non de N par AffN() int bpF = 0; //Flag de l'état des Boutons Poussoirs, de 0 à 5 int runC = 0; //Numero du run courant int NC = 0; //Numero, 1 ou 2 de N utilisé dans AjusteN12() int varN = 0; //Utilisée pour la valeur de N qui deviendra N1 ou N2, dans AjusteN12() int altAff = 0; //alterner l'écriture de N carl'écriture sur LCD ajoute 1ms à T //////////////EEPROM lecture et écriture exclusivement en 16 bis///////////////////// int ptR = 0; // pointeur (EEPROM 0,1)à la première mémoire vide pour recevoir un run int adEP = 0; //adresse dans l'EEPROM int dEP = 0; //data lu ou à ecrire en EEPROM, 16 bits void AffGeneral()////////////////////while (1); delay(1000);////////////////////////// //Affichage general de l'ecran sauf N le régime moteur actuel { noInterrupts();//Pas d'IT, indispensable pour cette fonction d'affichage! lcd.clear();//On affiche N1, N2, et D mais pas leur valeur, c'est un fond d'écran lcd.print("N1 "); lcd.print(int(N1)); lcd.setCursor(0, 1); lcd.print("N2 "); lcd.print(int(N2)); lcd.print(" D= "); lcd.print(int(D)); interrupts();//Reactiver les IT des fronts } void AffN()////////////////////while (1); delay(1000);///////////////////////////// { N = K / T; //calculé ici pour quel'isr ne travail que sur T pour des raisons de rapidité if (affNF == !0)//si ce flag=0, pas d'affichage de N { delay(5); lcd.setCursor(8, 0); lcd.print("N= ");//pour ne pas laisser de traces de chiffres qd N grand lcd.setCursor(12, 0);// lcd.print(int(N)); delay(5); } } void AffRun()////////////////////while (1); delay(1000);///////////////////////////// //adEP pointe au début du Run stocké en EEP.Calcul et affiche runC, le N° de ce Run { ReadEP16(); N1 = dEP; ReadEP16(); N2 = dEP; ReadEP16(); D = dEP; AffGeneral(); //N1, N2, et D, pas Run runC = (adEP - 2 ) / 6; //N° de Run calculé avec ptR lcd.setCursor(8, 0); lcd.print("Run "); lcd.print(runC); delay(100); } void AjusteN12()////////////////////while (1); delay(1000);///////////////////////////// //Entre avec NC=1 ou 2.En sortie N1 ou N2 modifié { //noInterrupts();//Alors que AffGeneral() a besoin des IT, ici non,!!!??? affNF = 0; //pas de N affiché durant cette fonction varN = N1; if (NC == 2)varN = N2; // On va travailler sur varN lcd.clear();//ligne 0, col 0 lcd.print("-"); lcd.setCursor(15, 0); lcd.print("+"); lcd.setCursor(0, 1);//descendre la ligne lcd.print("N"); lcd.print(NC); lcd.print(" "); lcd.print(varN); //N1 ou N2 bpF = 0; while (bpF != 5) { LecBP(); //delay(100); switch (bpF) { case 0: break; //aucun BP poussé case 1: case 3: varN = varN - stepN; break; //BP1 poussé, court ou long, c'est - case 2: case 4: varN = varN + stepN; break; //BP2 poussé, court ou long, c'est + case 5: if (NC == 1) N1 = varN; else N2 = varN; break; //les deux BP poussés,on sort default: { //erreur , arret Serial.print("Ligne_"); Serial.print(__LINE__); while (1); } } //fin du switch lcd.setCursor(5, 0);//ecrire la valeur de N1 ou N2 lcd.print(varN); delay(100); }//Fin du while,on sort si bpF=5 } void Ech()////////////////////while (1); delay(1000);//////////////////////////// //Lire l'état des deux BP { b1 = !digitalRead(BP1); sig1 = sig1 + b1; //Etat instantané et cumul des b1 2 b2 = !digitalRead(BP2); sig2 = sig2 + b2; } void IniT()////////////////////while (1); delay(1000);//////////////////////////// //Si on maintient BP1 avant la mise sous tension ou Reset.Indispensable à la première utilisation!! { if (digitalRead(BP1) == 0) RazLog(); //on effacer le log des runs en EEPROM et la première fois initialiser ptR=2!!! lcd.clear(); lcd.print(" Bienvenue"); lcd.setCursor(1, 1); lcd.setCursor(13, 1); lcd.print("PhL"); delay(1000); lcd.clear();//ligne 0, col 0 lcd.print(" ChronoAcc");//en ligne 0 lcd.setCursor(0, 1);//descendre la ligne lcd.print(Ver); //N° de version delay(4000);// Ecran d'accueil pour 4s lcd.clear();//ligne 0, col 0 lcd.print("N en t/mn");//en ligne 0 lcd.setCursor(0, 1);//descendre la ligne lcd.print("D en 1/100 s"); delay(2000); affNF = 0; cumDF = 0; altAff = 0;//les flags à 0 adEP = 0; ReadEP16(); //Chercher ptR en 0,1 de l'EE //Si l'EEP a déja servi, en 0/1 on a 2 ou 8 ou 14 etc //On teste cela et sinon on écrit 2 pour l'initialiser/reinitialiser if ((dEP - 2) % 6 != 0) { //initialiser/reinitialiser dEP = 2; //On force ptR=2 adEP = 0; WriteEP16(); } ptR = dEP;//ptR pointe à la première mémoire vide pour stocker le run à venir if (ptR == 2) //EEPROM , pas de run stocké { runC = 0; //On part de 0 N1 = N1init; N2 = N2init; D = 0; } else { runC = (ptR - 2) / 6; //calcul du N° du dernier run stocké adEP = ptR - 6; //y pointer à N1 ReadEP16(); N1 = dEP; //lire les valeurs de N1,N2 et D de ce run ReadEP16(); N2 = dEP; ReadEP16(); D = dEP; } attachInterrupt(0, isr, FALLING); // pin on interrupt 0 (pin D2), front descendant AffGeneral(); } void isr() ////////////////////while (1); delay(1000);/////////////////////////// //executée à chaque front d'étincelle { T = micros() - prec_H; // T la periode = heure actuelle - heure du front precedent prec_H = micros();//Noter l'heure d'arrivée de ce nouveau front, pour le T à venir if (cumDF != 0) { D = D + T; //cumuler D pour ce run en cours et sortir tout de suite cumDF++; //A virer sauf pour VerifD() return; } if (altAff == 1) { //alternance de l'affichage AffN(); //calcul N=K/T ,un T sur 2 voir s'il faut afficher N( dépend de affNF) altAff = 2;//prochain N pas affiché, car vérolé par l'affichage de ce N au LCD } else altAff = 1;//Pour afficher le prochain N if (cumDF == !0)D = D + T; //cumuler D pour ce run en cours } void LecBP()////////////////////while (1); delay(1000);///////////////////////////// { bpF = 0; sig1 = 0; sig2 = 0; if ((digitalRead(BP1) == 1) && (digitalRead(BP2) == 1))return; //pas de BP poussé on ressort tout de suite //Au moins 1 BP poussé, le cycle qui suit durera nEch*espEch ms , typique 1000 ms for (int j = 1; j <= 10; j++) //ici un ou deux BP poussés, on démarre un cycle de nEch échantillons séparés de espEch ms { b1 = !digitalRead(BP1); sig1 = sig1 + b1; //Etat instantané et cumul des b1 2 b2 = !digitalRead(BP2); sig2 = sig2 + b2; if ((b1 == 1) && (b2 == 1))bpF = 5; //2BP poussés, l'enregistrer "au vol" dans bp5 delay(espEch);//Attendre entre deux échantillons } if (digitalRead(BP1) == 0); if (digitalRead(BP2) == 0); //attendre deux BP relachés // if (bpF = 5)delay(1000); if (bpF != 5)//Sauf si déjà bpF=5 pour deux BP poussés { if (sig1 != 0) { //C'est BP1 bpF = 1; //Bp1 poussé, court =1 ou long =3 if (sig1 >= sLong)bpF = 3; } else { //C'est BP2 bpF = 2; //Bp2 poussé, court =2 ou long =4 if (sig2 >= sLong)bpF = 4; } delay(100); } } void LecLog()////////////////////while (1); delay(1000);////////////////////////// { affNF = 0; //Pas d'afichage de N lcd.clear();//ligne 0, col 0 lcd.print("Lecture du Log"); delay(1000); adEP = 0; //pointer au début de l'EEPROM où ptR est stocké ReadEP16(); ptR = dEP; if (ptR == 2) { lcd.clear();//ligne 0, col 0 lcd.print("Log vide"); delay(3000); return; //on a fini, sortir } //ptR pointe à la première mémoire vide et adEP=2 au premier Run bpF = 0; AffRun(); //Afficher le premier Run while (bpF != 5) { LecBP(); switch (bpF) { case 0: case 5: break;// 5 = 2 BP, sortie de lecture de log case 2: case 4: if (adEP < ptR )AffRun(); break; //BP2 lent ou rapide, lire Run case 1: case 3: if (adEP >= 14) { //Run n affiché, adEP pointe au début de Run n+1 adEP = adEP - 12;//remonter de deux Runs, pour pointer adEP à Run n-1 AffRun(); } break; default: { //fin anormale, arret ici. Serial.print("Ligne_"); Serial.print(__LINE__); while (1); } delay(100); } delay(100); //fin de switch } //si bpF=5, sortir //interrupts(); } void LogRun()////////////////////while (1); delay(1000);//////////////////////////// // Run juste terminé, ecrit N1,N2,D en EEPROM,. Mets à jour ptR en EEP 0 { adEP = ptR; dEP = N1; WriteEP16(); dEP = N2; WriteEP16(); dEP = D; WriteEP16(); ptR = adEP; //ajuster ptR vers prochaine mémoire libre adEP = 0; dEP = ptR; WriteEP16();//sauver ptR en EEPROM } void RazLog()////////////////////while (1); delay(1000);////////////////////////// //Pour effacer le Log en EEPROM et aussi à executer au tout premier démarrage { affNF = 0; //Pas de N while (digitalRead(BP1) == 0); //Attendre tant que BP1 poussé lcd.clear();//ligne 0, col 0 lcd.print("Effacer le log ? ");//en ligne 0 lcd.setCursor(0, 1);//descendre la ligne lcd.print("Si oui,BPd"); while (digitalRead(BP2) == 1); //Attendre tant que BP2 non poussé adEP = 0; dEP = 2; WriteEP16(); //Ecrire en 0/1 EEPROM ptR=2 } void ReadEP16()//////////////////while (1); delay(1000);/////////////////////// //à l'adresse adEP, lire 16 bits et les mettre dans dEP { if (adEP > 1022)adEP = 1022; //Butée EEP va de 0 à 1023 int hiB = EEPROM.read(adEP);// Serial.print("hiB__");Serial.println(hiB); adEP++; int loB = EEPROM.read(adEP);//Serial.print("loB__");Serial.println(loB); adEP++; //preparer prochaine adresse dEP = (hiB << 8) + loB; } void ReprintEeprom(int n16)//////while (1); delay(1000);///////////////////// //Imprimer n16 entiers à partir de l'adresse 0 en EEPROM { Serial.println("EEPROM a partir de 0, valeurs en 16 bits "); adEP = 0; { for (int i = 0; i < n16; i++) { ReadEP16(); Serial.println(dEP); } } } void Run() //////////////////while (1);////////////////////////////////// { affNF = 1; //afficher N if (N2 <= N1) { lcd.clear(); lcd.print("N2 < N1 !!!"); delay(3000); return; } if (N1 <= N) { lcd.clear(); lcd.print("N1 < "); delay(3000); return; } lcd.clear(); lcd.print("N1 "); lcd.print(int(N1)); //delay(1000); lcd.setCursor(0, 1); lcd.print("Pour stopper:BPd "); T2 = K / N2; //On va comparer T à T2 while (N < N1) { if (digitalRead(BP2) == 0)return; //Avorter le run } //Le Run démarre vraiment ici D = 0; cumDF = 1; //Raz de D qui cumule les T affNF = 0; //Pas de N lcd.clear(); lcd.setCursor(0, 0); lcd.print("On vise " ); lcd.print(N2); lcd.setCursor(0, 1); lcd.print("Pour stopper:BPd "); while (T > T2)//Evite dle temps de calcul de N { if (digitalRead(BP2) == 0) { affNF = 1; //Avorter le run cumDF = 0; return; } } //le run s'arrète ici cumDF = 0; //Arreter le cumul dans D affNF = 0; //ne pas afficher N lcd.clear(); delay(1000); runC = (ptR - 2) / 6; //calcul du N° du dernier run stocké runC++; //nouveau Run D = D / 10000; //Convertir µs = 1/1000 000 s en 1/100 s AffGeneral(); //Affiche N1,N2,Run et D lcd.setCursor(8, 0); lcd.print("Run "); lcd.print(runC); delay(100); LogRun(); //En registrer ce run en EEPROM bpF = 0; delay(100); while ( bpF != 5) { delay(100); // Attendre les deux BP poussés pour sortir LecBP(); } delay(100); lcd.clear(); lcd.print("Enregistre"); delay(2000); } void VerifD() //Pour verifier la precision du calcul de D.Voir SETUP { cumDF = 1; //Demarrer la mesure de D while (cumDF < 100); //Ici le nombre de fronts à totaliser Serial.println("cumDF et D en microsecondes "); Serial.println(cumDF); Serial.println(D); while (1); } void WriteEP16() //////////////////while (1); delay(1000);//////////////////// { if (adEP > 1022)adEP = 1022; //Butée EEP va de 0 à 1023 EEPROM.write(adEP, highByte (dEP)); //MSByte adEP ++; EEPROM.write(adEP, lowByte (dEP)); //LSByte adEP++; //preparer prochaine adresse } //////////////////////////////////////////////////////////////////////// void setup()//////////////////while (1); delay(1000);////////////////////////// ///////////////////////////////////////////////////////////////////////// { deb = 1; //pour debugging //Dans l'ecran seriel, afficher le nom du sketch, la date et l'heure, avec ces macros du langage C Serial.begin(9600); Serial.println(__FILE__); Serial.println(__DATE__); Serial.println(__TIME__); lcd.begin(16, 2);//16 colonnes, 2 lignes pinMode(inPulse, INPUT_PULLUP);//Entrée du front sur INT 0, mis à la masse par Triac pinMode(BP1, INPUT_PULLUP);//Chaque BP met son entrée à la masse quand poussé pinMode(BP2, INPUT_PULLUP);//Donc digitalRead(BP1)==0 , si BP1 poussé/ON IniT();//Attachera l'isr à l'interruption IT 0 ReprintEeprom(15);//Pour info,imprimer le début de l'EEPROM, ici 15 valeurs //VerifD();while (1);// Decommenter pour lancer la mesure de D puis son impression } /////////////////////////////////////////////////////////////////////////// void loop()/////////////////////while (1); delay(1000);///////////////// //////////////////////////////////////////////////////////////////////////// { affNF = 1; //Autoriser l'affichage de N sur le LCD delay(300); LecBP(); //Lire l'état des deux Bouton Poussoirs: calcul bpF switch (bpF) { case 0: break; //aucun BP poussé case 1: Run(); AffGeneral(); break; //BP1 poussé peu de temps, lancer un Run case 2: break; //BP2 poussé peu de temps, aucun effet case 3: NC = 1; AjusteN12(); AffGeneral(); break;//BP1 long, modifier N1 case 4: NC = 2; AjusteN12(); AffGeneral(); break;//BP2 long, modifier N2 case 5: LecLog(); AffGeneral(); break;//les deux BP ,lire du log des Runs default: { //fin anormale, arret ici. Serial.print("Ligne_"); Serial.print(__LINE__); while (1); } } delay(50);//fin du switch } ////////////////DEBUGGING//////////////////////// //int deb = 0; //si 0, pas de printde debug, voir SETUP pour sa valeur actuelle // Breakpoint du pauvre, activé selon deb=0 ou non //if(deb!=0){ Serial.print("Ligne_");Serial.print(__LINE__);while (Serial.available()==0);int _zz = Serial.read();} //La macro du langage C, __LINE__, fournit le N° de ligne dans le listing. //Pour continuer, dans le haut de l'ecran Seriel, entrer un car au clavier puis Return //Plus simple: avec arret aprés le N° de ligne , le nom de la variable et sa valeur // { Serial.print("Ligne_");Serial.print(__LINE__);Serial.print(" nom var = ";Serial.println(var);while (1);} //Une autre possibilité est de générer ou non du code de debug à la compilation. //#define DEBUG // #if defined DEBUG #endif //////////////////////////////////////////////////