//Allumage pour 125 RDX (deux temps deux cylindres)Antonio Correia https://as3-rdx-club.clicforum.fr/t7031-Allumage-AEPL-duino-sur-2R6.htm?start=15#p227614 //Programme original Aepl-Duino_16_06_20 de Philippe Loutrel //Description détaillée sur http://loutrel.org/aeduino.php //Le programme a été allégé au maximum de toutes les options non utiles pour mon utilisation (multicourbes, commande par BT etc) //Supression de l'avance à 0° en dessous de 500tr/mn (pas trop de risque sur retour de kick sur 125 et permet un meilleur démarage) //Un circuit par cylindre pour plus de sécurité //2 capteurs (vilo), 2 arduinos dans un boitier alu, 2 igbt hors du boitier, 2 bobines //Si un des elements claque dans le circuit alimentant un cylindre il reste l'autre cylindre pour rentrer aux bercailles // Allumage electronique programmable - Arduino Nano et compatibles //****************************************************************************** //************** Seulement 6 lignes à renseigner obligatoirement.**************** //**********Ce sont: Na Anga Ncyl AngleCapteur CaptOn Dwell****************** //___1___ Na[] régime moteur en t/mn //Na[] et Anga[] doivent obligatoirement débuter puis se terminer par 0, et contenir des valeurs entières >=1 //Le dernier Na fixe la ligne rouge, c'est à dire la coupure de l'allumage. //Le nombre de points est libre.L'avance est imposée à 0° entre 0 et Nplancher t/mn //Attention.....Pas de pleine charge avec trop d'avance, danger pour les pistons!!! int Na[] = {0, 500, 1000, 1500, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 0};//t/*mn vilo //__2__Anga [] degrés d'avance vilebrequin correspondant ( peut croitre ou decroitre) int Anga[] = {0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0}; //__3__Ncyl Nombre de cylindres, moteur 4 temps.Multiplier par 2 pour moteur 2 temps int Ncyl = 2; //__4__Position en degrès vilo du capteur( Hall ou autre ) AVANT le PMH étincelle du cylindre N°1 const int AngleCapteur = 40; //__5__CapteurOn = 1 déclenchement sur front montant (par ex. capteur Hall "saturé") //CapteurOn = 0 déclenchement sur front descendant (par ex. capteur Hall "non saturé").Voir fin du listing const int CaptOn = 1; //__6__Dwell //Dwell = 2 pour alimentation de la bobine seulement trech ms par cycle, 3ms par exemple //Obligatoire pour bobine 'electronique' de faible resistance: entre 2 et 0.5ohm.Ajuster trech //Sur le 125 RDX le Dwell est de 40% ==> à 12000 on a 3ms par bobine par tour donc il suffit de 3ms pour la recharge const int Dwell = 2; //************************************************************************************ //**********************GENERALITES********************************* //Valable pour tout type de capteur soit sur vilo soit dans l'allumeur (ou sur l'arbre à came) //La Led(D13) existant sur tout Arduino suit le courant dans la bobine:ON bobine alimentée //En option, multi-étincelles à bas régime pour denoyer les bougies //Pour N cylindres,2,4,6,8,12,16, 4 temps, on a N cames d'allumeur ou N/2 cibles sur le vilo //**********************LES OPTIONS********************** //*************Variantes de Dwell et Multi-éticelles************** //Si Dwell=2, temps de recharge bobine, 3ms= 3000µs typique, 7ms certaines motos const int trech = 3000; const int tetin = 500; //Typique 500 à 1000µs, durée etincelle regimes >Ntrans //Si multi-étincelle désiré jusqu'à N_multi, modifier ces deux lignes const int Multi = 1;//1 pour multi-étincelles const int N_multi = 2000; //t/mn pour 4 cylindres par exemple //Surtout utile pour denoyer les bougies à bas régime //************Ces 3 valeurs sont eventuellement modifiables***************** const int unsigned long Dsecu = 3000000;//Securite: bobine coupee à l'arret apres Dsecu µs //***************************************************************************** #include "TimerOne.h" //***********************Variables du sketch************************************ const int Bob = 4; //Sortie D4 vers bobine.En option, on peut connecter une Led avec R=330ohms vers la masse const int Cible = 2; //Entrée sur D2 du capteur, R PullUp const int Led13 = 13; //Temoin sur tout Arduino, suit le courant de bobine int unsigned long D = 0; //Delai en µs à attendre après la cible pour l'étincelle int milli_delay = 0; int micro_delay = 0; int tcor = 140; //correction en µs du temps de calcul pour D int unsigned long Davant_rech = 0; //Delai en µs avant la recharge de la bobine. int unsigned long prec_H = 0; //Heure du front precedent en µs int unsigned long T = 0; //Periode en cours int unsigned long Tprec = 0;//Periode precedant la T en cours, pour calcul de Drech int N1 = 0; //Couple N,Ang de debut d'un segment int Ang1 = 0; //Angle d'avance vilo en degrès int N2 = 0; //Couple N,Ang de fin de segment int Ang2 = 0; int* pN = &Na[0];//pointeur au tableau des régimes. Na sera la courbe par defaut int* pA = &Anga[0];//pointeur au tableau des avances. Anga sera la courbe par defaut float k = 0;//Constante pour calcul de C1 et C2 float C1[30]; //Tableaux des constantes de calcul de l'avance courante float C2[30]; //Tableaux des constantes de calcul de l'avance courante float Tc[30]; //Tableau des Ti correspondants au Ni //Si necessaire, augmenter ces 3 valeurs:Ex C1[40],C2[40],Tc[40] int Tlim = 0; //Période minimale, limite, pour la ligne rouge int j_lim = 0; //index maxi des N , donc aussi Ang int unsigned long NT = 0;//Facteur de conversion entre N et T à Ncyl donné int unsigned long NTa = 0;//Facteur de conversion entre N et T pour affichage sur smartphone int Naff = 30; //Pour affichage sur smartphone nb de tours à ignorer int ctNaff = 0; // Compteur de Naff int AngleCibles = 0;//Angle entre 2 cibles, 180° pour 4 cyl, 120° pour 6 cyl, par exemple int UneEtin = 1; //=1 pour chaque étincelle, testé et remis à zero par isr_GestionIbob() int Ndem = 390;//Vitesse estimée du vilo entrainé par le Kick en t/mn //environ 390 tr/mn au premier tour - 750 tr/mn environ sur deuxieme tour int unsigned long Tdem = 0; //Periode correspondante à Ndem,forcée pour le premier tour int Mot_OFF = 0;//Sera 1 si moteur detecté arrété par l'isr_GestionIbob() int unsigned long Ttrans; //T transition de Dwell 4 int unsigned long T_multi = 0; //Periode minimale pour multi-étincelle //Permet d'identifier le premier front et forcer T=Tdem, ainsi que Ibob=1, pour demarrer au premier front //********************LES FONCTIONS************************* void CalcD ()////////////////// // Noter que T1>T2>T3... { for (int j = 1; j <= j_lim; j++)//On commence par T la plus longue et on remonte { if (T >= Tc[j]) { //on a trouvé le bon segment de la courbe d'avance D = float(T * ( C1[j]) + C2[j]) ;//D en µs, C2 incorpore le temps de calcul tcor break; //Sortir, on a D } } } void Etincelle ()////////// { if (D < 14000) { // Currently, the largest value that will produce an accurate delay is 16383 µs delayMicroseconds(D); //Attendre D } } else { milli_delay = ((D / 1000) - 2);//Pour ces D longs, delayMicroseconds(D)ne va plus. micro_delay = (D - (milli_delay * 1000)); delay(milli_delay); // delayMicroseconds(micro_delay); } digitalWrite(Bob, 0);//Couper le courant, donc étincelle digitalWrite(Led13, 0); //Temoin //Maintenant que l'étincelle est émise, il faut rétablir Ibob au bon moment if (Multi && (T >= T_multi))Genere_multi(); else { Davant_rech = 1000; //1ms off par cycle Timer1.initialize(Davant_rech);//Attendre Drech µs avant de retablire le courant dans la bobine } UneEtin = 1; //Pour signaler que le moteur tourne à l'isr_GestionIbob(). } void Genere_multi()////////// { //L'etincelle principale a juste été générée delay(1); //Attendre fin d'etincelle 1ms digitalWrite(Bob, 1);//Retablir le courant delay(3); //Recharger 3ms digitalWrite(Bob, 0);//Première etincelle secondaire delay(1); //Attendre fin d'etincelle 1ms digitalWrite(Bob, 1);//Retablir le courant delay(2); //Recharger 2 ms digitalWrite(Bob, 0);//Deuxième etincelle secondaire delay(1); //Attendre fin d'etincelle 1ms digitalWrite(Bob, 1);//Retablir le courant pour étincelle principale } void Init ()///////////// //Calcul de 3 tableaux,C1,C2 et Tc qui serviront à calculer D, temps d'attente //entre la detection d'une cible par le capteur et la generation de l'etincelle. //Le couple C1,C2 est determiné par la periode T entre deux cibles, correspondant au //bon segment de la courbe d'avance entrée par l'utilisateur: T est comparée à Tc { AngleCibles = 720 / Ncyl; //Cibles sur vilo.Ex pour 4 cylindres 180°, 120° pour 6 cylindres NT = 120000000 / Ncyl; //Facteur de conversion Nt/mn moteur, Tµs entre deux PMH étincelle //c'est à dire deux cibles sur vilo ou deux cames d'allumeur //// Ttrans = NT / Ntrans; //Calcul de la periode de transition pour Dwell 4 T_multi = NT / N_multi; //Periode minimale pour generer un train d'étincelle //T temps entre 2 étincelle soit 720° 1°=1/6N // delAv = 0; //Pas de decalage de courbe // delAv_F = 0; // Flag pour annuler affichage des RPM Tdem = NT / Ndem; //Periode imposée à la première étincelle qui n'a pas de valeur prec_H N1 = 0; Ang1 = 0; //Toute courbe part de 0 int i = 0; //locale mais valable hors du FOR pN++; pA++; //sauter le premier element de tableau, toujours =0 for (i = 1; *pN != 0; i++)//i pour les C1,C2 et Tc.Arret quand regime=0. //pN est une adresse (pointeur) qui pointe au tableau N.Le contenu pointé est *pN { N2 = *pN; Ang2 = *pA;//recopier les valeurs pointées dans N2 et Ang2 k = float(Ang2 - Ang1) / float(N2 - N1);//pente du segment (1,2) C1[i] = float(AngleCapteur - Ang1 + k * N1) / float(AngleCibles); C2[i] = - float(NT * k) / float(AngleCibles) - tcor; //Compense la durée de calcul de D Tc[i] = float(NT / N2); // N1 = N2; Ang1 = Ang2; //fin de ce segment, début du suivant pN++; pA++; //Pointer à l'element suivant de chaque tableau } j_lim = i - 1; //Revenir au dernier couple entré Tlim = Tc[j_lim]; //Ligne rouge Serial.print("Ligne_"); Serial.println(__LINE__); Serial.print("Tc = "); for (i = 1 ; i < 15; i++)Serial.println(Tc[i]); Serial.print("Tlim = "); Serial.println(Tlim); Serial.print("C1 = "); for (i = 1 ; i < 15; i++)Serial.println(C1[i]); Serial.print("C2 = "); for (i = 1 ; i < 15; i++)Serial.println(C2[i]); //Timer1 a deux roles: //1)couper le courant dans la bobine en l'absence d'etincelle pendant plus de Dsecu µs //2)après une étincelle, attendre le delais Drech avant de retablir le courant dans la bobine //Ce courant n'est retabli que trech ms avant la prochaine étincelle, condition indispensable //pour une bobine à faible resistance, disons inférieure à 3 ohms.Typiquement trech = 3ms à 7ms Timer1.attachInterrupt(isr_GestionIbob);//IT d'overflow de Timer1 (16 bits) Timer1.initialize(Dsecu);//Le courant dans la bobine sera coupé si aucune etincelle durant Dsecu µs Mot_OFF = 1;// Signalera à loop() le premier front digitalWrite(Bob, 0); //par principe, couper la bobine digitalWrite(Led13, 0); //Temoin } void isr_GestionIbob()////////// { Timer1.stop(); //Arreter le decompte du timer if (UneEtin == 1) { digitalWrite(Bob, 1); //Le moteur tourne,retablire le courant dans bobine digitalWrite(Led13, 1);//Temoin } else { digitalWrite(Bob, 0); digitalWrite(Led13, 0); //Temoin//Moteur arrete, preserver la bobine, couper le courant Mot_OFF = 1;//Permettra à loop() de detecter le premier front de capteur } UneEtin = 0; //Remet le detecteur d'étincelle à 0 Timer1.initialize(Dsecu);//Au cas où le moteur s'arrete, couper la bobine apres Dsecu µs } //////////////////////////////////////////////////////////////////////// void setup()/////////////// ///////////////////////////////////////////////////////////////////////// { Serial.begin(9600);//Ligne suivante, 3 Macros du langage C Serial.println(__FILE__); Serial.println(__DATE__); Serial.println(__TIME__); pinMode(Cible, INPUT_PULLUP); //Entrée front du capteur sur D2 pinMode(Bob, OUTPUT); //Sortie sur D4 controle du courant dans la bobine pinMode(Led13, OUTPUT);//Led d'origine sur tout Arduino, temoin du courant dans la bobine // Tst_BT(); //Option pour tester le Bluetooth, à commenter normalement Init();// Executée une fois au demarrage et à chaque changement de courbe } /////////////////////////////////////////////////////////////////////////// void loop() //////////////// //////////////////////////////////////////////////////////////////////////// { while (digitalRead(Cible) == !CaptOn); //Attendre front actif de la cible T = micros() - prec_H; //front actif, arrivé calculer T prec_H = micros(); //heure du front actuel qui deviendra le front precedent if ( Mot_OFF == 1 ) { //Demarrage:premier front de capteur T = Tdem;//Fournir T = Tdem car prec_H n'existe par pour la première étincelle digitalWrite(Bob, 1);//Alimenter la bobine digitalWrite(Led13, 1); //Temoin Mot_OFF = 0; //Le moteur tourne } if (T > Tlim) //Sous la ligne rouge? { CalcD(); // Top(); //Oui, generer une etincelle Etincelle(); } while (digitalRead(Cible) == CaptOn); //Attendre si la cible encore active } /////////////////Exemples de CAPTEURS///////////////// //Capteur Honeywell cylindrique 1GT101DC,contient un aimant sur le coté,type non saturé, sortie haute à vide, //et basse avec une cible en acier. Il faut CapteurOn = 0, declenchement sur front descendant. //Le capteur à fourche SR 17-J6 contient un aimant en face,type saturé, sortie basse à vide, //et haute avec une cible en acier. Il faut CapteurOn = 1, declenchement sur front montant. //Pour les Ncyl pairs:2,4,6,8,10,12, le nombre de cibles réparties sur le vilo est Ncyl/2 //Dans les deux cas (capteur sur vilo ou dans l'alumeur) la periode entre deux cibles et la même car l'AàC tourne à Nvilo/2 //Pour les Ncyl impairs 1,3 5, 7?,9? il FAUT un capteur dans l'alumeur (ou AàC) ////////////////DEBUGGING//////////////////////// //Voir http://www.loutrel.org/Arduinodebugging.php //Macro ps(v) de debug pour imprimer le numero de ligne, le nom d'une variable, sa valeur //puis s'arreter definitivement //#define ps(v) Serial.print("Ligne_") ; Serial.print(__LINE__) ; 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(#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" //float gf = 0;//pour boucle d'attente,gf GLOBALE et FLOAT indispensable // gf = 1; while (gf < 2000)gf++;//10= 100µs,100=1.1ms,2000=21.8ms //void Top()////////// //{ digitalWrite(Bob, 1); //Crée un top sur l'oscillo // gf = 1; while (gf < 10)gf++;//gf DOIT être Globale et Float 10=100µs,2000=21.8ms, retard/Cible=50µs // digitalWrite(Bob, 0); // //}