Jump to content

Toine5013

Members
  • Posts

    37
  • Joined

  • Last visited

  • Days Won

    4

Toine5013 last won the day on September 2 2022

Toine5013 had the most liked content!

1 Follower

Location information

  • Localisation
    Caen (14)

Converted

  • My First Name
    Antoine
  • Ma Biographie
    Passionné de tout ce qui roule, fait du bruit et sent mauvais !
  • Professionnel de la VW ?
    NON
  • Newsletter F4E
    NON

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Toine5013's Achievements

  1. Salut ! Génial ton logiciel de simulation, c'est pile poil ce qu'il me faudrait pour avancer mes projets. Où peut-on le trouver? Il est payant? Effectivement le comportement que l'on voit sur le scope est exactement celui désiré. Pour OCR1A, D correspond au délai à appliquer entre le passage de la cible et l'ISR pour déclencher l'étincelle au bon moment. D en microsecondes divisé par 4 donne un D en cycles horloge. Je retranche 2 cycles horloge au résultat pour faire une correction car j'ai constaté un léger décalage entre le théorique et le réel. J'ai pas vraiment d'explication pour ça. Pour OCR1B, on doit mettre la bobine en charge 54° après l'étincelle (3 dixièmes de 180°). Du coup, dès le passage de la cible je configure le registre pour déclencher la charge bobine dans un délai correspondant à D + Davant_rech (les 50° pour l'étincelle + les 54° d'attente avant mise en charge). Je divise également ce délai par 4 pour le convertir en cycles horloge et je retranche 2 cycles pour la correction. OCR1A = 2076, c'est cohérent: ça représente les 50° sachant que 180° font 7450 OCR1B = 4328, ça colle également: ça représente les 50° + les 54° d'attente avant mise en charge. Par contre, j'ai fait des essais en peu plus poussés sur ma voiture, même si c'est mieux en configurant manuellement les Timers, j'ai toujours le problème d'interruption capricieuse... Alors peut-être qu'il pourrait être résolu en utilisant des artifices supplémentaires pour filtrer, mettre en forme le signal etc, je pense que pour ce que l'on fait le jeu n'en vaut pas la chandelle et je reviens donc pour les prochaines versions à l'ancienne méthode de détection de la cible, à savoir en pooling dans la loop(). Comme on l'avait dit, sur un 4 cylindres, à 7000tr/min ça nous laisse 4,2ms entre deux passages de cible pour exécuter des fonctions: Il y a de la marge ! C'est une petite déception mais tout ce travail a été loin d'être vain car j'y ai appris entre autres à manipuler les Timers "à la source" et ça offre bien plus de souplesse et de possibilités qu'en passant par les bibliothèques. Par exemple, avec un seul Timer, j'ai réussi à piloter deux sorties de façon indépendantes (pour faire fonctionner deux paires d'injecteurs en semi-séquentiel), là où en passant par les bibliothèques on ne pouvait piloter qu'une seule sortie et donc faire de l'injection simultanée. J'ai également réussi à gérer en parallèle une pompe à essence électrique. Ca peut servir pour ceux qui veulent alimenter leurs carbus ainsi. Autre chose, j'ai aussi pu valider l'utilisation de bobines jumostatiques => à suivre... Pour ma pomme, j'avance également sur mon projet d'injection et je vais changer d'arduino pour passer sur du méga pro mini: à peine plus gros qu'un Nano, mais plus de mémoire et surtout 5 Timers dont 4 en 16bits ! Là, il y a moyen de faire de l'injection séquentielle phasée et bien d'autres choses encore. Je reparlerai de tout ça en temps voulu ?
  2. Salut à tous ! Grande nouvelle, le problème d'interruption capricieuse est réglé ! Bilan: ça ne venait pas d'un problème de signal mais bien un problème logiciel. (Ca ne m'empêchera pas de passer sur un Pull-up externe à l'avenir) En fait l'ISR n'appréciait l'appel à micros() et le lancement du Timer1 via la librairie Timerone.h. J'ai contourné le problème en configurant manuellement le Timer. Au passage de la cible, je calcule directement la période avec le comptage du Timer1, et le remet à zéro. Le Timer1 peut déclencher des interruptions par comparaison avec une valeur donnée. Sur le schéma ci desssus, la ligne rouge représente la valeur de comptage du Timer. Finalement, c'est beaucoup plus simple ainsi et la loop() est désormais totalement indépendante. Ca va me permettre de revoir toute l'architecture du programme. Voici le bout de code correspondant: volatile int unsigned long overflow_count = 0; volatile int unsigned long T = 0; volatile bool etincelle = 0; volatile int unsigned long D = 0; volatile int unsigned long Davant_rech = 0; /* Version d'essai pour validation fonctionnement par ISR Fait fonctionner le moteur avec une avance fixe Une ISR est déclenchée au passage de la cible: Le Timer 1 est remis à 0 en début de période. 3 ISR sont configurées sur ce timer: -la première quand la valeur Timer atteint la valeur A correspondante à D => l'étincelle est déclenchée -la deuxième quand la valeur Timer atteint la valeur B correspondante à D + Davant_rech => la bobine est mise en charge - la troisième en cas de débordement du Timer (il peut compter jusqu'à 524ms avant de déborder) cette troisième ISR sert à compter les périodes T supérieures à 524ms, elle ne sert donc que pour les régimes inférieurs à 115 tr/min */ void setup() { Serial.begin(115200); pinMode(2, INPUT_PULLUP); pinMode(3, OUTPUT); cli(); // désactive les interruptions EICRA = 0b000000010; // Règle l'interruption broche D2 sur FALLING EIMSK = 0b000000001; // Autorise les interruptions sur D2 TCCR1A = 0b000000000; // Règle le Timer1 TCCR1B = 0b000000011; // Règle le prediviseur Timer1 à 64 => 1 clock = 4µs TIMSK1 = 0b000000111; // Autorise les interruptions par comparaison registre OCR1A, OCR1B, et overflow sei(); // Réactive les interruptions } ISR(TIMER1_COMPA_vect){ // ISR qui déclenche l'étincelle digitalWrite(3, HIGH); } ISR(TIMER1_COMPB_vect){ // ISR qui remet en charge la bobine digitalWrite(3, LOW); } ISR(TIMER1_OVF_vect){ // ISR déclenchée par overflow Timer1 (pour calcul période T) overflow_count++; // Compte le nombre de débordements TCNT1 = 0; // Remet Timer 1 à 0 } ISR(INT0_vect){ // ISR déclenchée par le passage de la cible T = overflow_count*65535 + TCNT1; // Calcul la période en cycles horloges TCNT1 = 0; // Remet le Timer à 0 overflow_count = 0; // Remet le compteur overflow à 0 pour le prochain calcul T = T * 4; // Convertit les cycles d'horloge en unité de temps (un cycle = 4µs) D = T / 180 * 50; // Calcule le délai avant étincelle (pour respect avance allumage) Davant_rech = T * 3 / 10; // Calcule le délai avant recharge bobine (pour respect Dwell) OCR1A = (D/4-2); // Fixe le seuil d'interruption OCR1B = ((D + Davant_rech)/4-2); } void loop() { } Affaire à suivre !
  3. Salut à vous ! J'ai peut être (je dis bien peut être) des nouvelles intéressantes concernant les interruptions: après avoir essayé différentes pistes pour localiser un problème de programmation, j'ai fini par simuler le signal du capteur hall par le PWM d'une autre broche, connectée à la broche n°2. Les interruptions et le calcul du régime sont stables au tr/min près ! Ma théorie est la suivante: la détection par interruption exige pour fonctionner correctement un signal plus propre que la méthode "traditionnelle". Je pense que l'utilisation du pull-up interne à l'arduino y est pour quelque chose: avec un pull up interne, le courant de tirage est de 0,1 mA. Assez faible ce qui rend le signal plus sensible aux parasites @Pod Voici l'extrait d'un article sur le pull-up trouvé sur le net: Il y a toutefois d’autres considérations plus difficiles à quantifier : Si la ligne est capacitive, le temps de montée du signal augmente avec la valeur de la résistance. L’effet est certainement négligeable pour un interrupteur actionné manuellement. Si la résistance est trop élevée, le courant qui circule devient très faible et si sa valeur devient proche du courant de fuite le comportement n’est plus celui attendu, sachant en plus qu’un faible courant peut être plus facilement perturbé par le bruit électromagnétique présent sur la ligne Pod, est ce que tu confirme ? Souvenez vous, j'avais mesuré le courant de tirage de la broche 6 du module à 3.3mA (celle qui initialement se branche au signal du capteur), ce qui veut dire que le capteur Hall supporte cette valeur. Valeur également supportée par la broche de l'arduino. Je vais donc essayer d'utiliser un pull-up externe de 1500ohm, ce qui me donnera 3.3mA, et voir comment ça se comporte. A suivre...
  4. Pod, Au delà des capacités en programmation, il peut être difficile de comprendre la logique d'un programme qui n'est pas le sien. J'ai mis pas mal de temps avant de bien comprendre les réalisations de Philippe. Pour la modification du firmware, en effet j'en ai déjà entendu parler mais il me semble qu'une fois la modification faite, il devient impossible de reprogrammer l'Arduino, à moins de remettre le firmware avec un autre Arduino. Je crois que Philippe en parle sur sa page. Pour la commande Serial.flush(), si je me trompe pas c'est surtout important quand l'Arduino recoit des données par le port série. A creuser. En effet, calc_D() sert à calculer le délai pour déclencher l'étincelle au moment voulu et Davant_rech le temps avant mise en charge de la bobine pour respecter le rapport cyclique de 30% OFF 70%ON sur un cycle. Pour le Tcor, en fait c'est assez simple: le délai D représente le temps à appliquer entre la détection de la cible et le point d'avance. Mais avant d'appliquer ce délai, il doit être calculé et ce calcul prends un certain temps (330µs dans mon programme). Ce temps "mort" est donc pris en compte et retranché de D. La méthode que j'ai utilisé pour le déterminer est la suivante: Je prends la valeur de micros() en début et en fin de calcul et je fait la soustraction. Entre les deux graphiques oui la différence est l'utilisation du Timer. Je le lance à la fin de calc_D avec l'instruction suivante: Timer1.initialize(D); cette instruction lance un compte à rebours en tache de fond et déclenche une interruption logicielle une fois le compte à rebours terminé. Et c'est le gros avantage du Timer: il travaille en temps masqué contrairement à une attente type delay() qui met le programme principal en pause. Pour les essais avec interruption j'ai bien utilisé un déclenchement sur front. En effet c'est bien plus facile à visualiser avec un chronogramme, ça m'a pris un peu de temps mais une image vaut mille mots ? Pour finir, le connecteur: bien joué !! C'est le bon, et pas cher en plus ?
  5. Alors comment dire... Ce connecteur est une vraie tannée à trouver ! Indisponible sur le net, j'ai cherché partout et j'ai fini par aller en casse auto. Les golf 3 ont également ce connecteur
  6. Salut à vous ! J'ai quelques nouvelles. Tout d'abord, Pod, je te laisse entre les mains de Pierre pour la résolution de ton problème. Si besoin, je suis tout de même disponible ? J'ai testé mon programme basé sur les interruptions et... Ca ne marche pas lol. Enfin disons que le moteur tourne mais assez mal. En fouillant un peu je me suis aperçu que la détection de la cible par une interruption génère des instabilités au niveau du calcul du régime (des variations de 100tr/min entre deux cycles, ce qui met la pagaille dans les calculs). Je ne sais pas vraiment pourquoi, mais en attendant je suis revenu à l'ancienne méthode de détection. Néanmoins, j'ai gardé l'application du délai D par un Timer et de ce fait gagné un temps précieux: Ancienne méthode: Nouvelle méthode: Ca ne parait pas comme ça, mais en 800µs un Arduino a le temps de faire pas mal de choses. J'ai également fait des essais de mesure de temps d'éxecution, et il est clair que la vitesse de transmission a un effet très important: A 9600 bauds l'envoi d'une ligne de données prends environ 4,5ms contre 0,9ms à 115200 bauds. Au régime de 7000tr/min, une période dure 4,2ms. Trop court pour laisser le temps au programme de finir son exécution avant le passage suivant de la cible. Voici ma dernière version de programme: /* ***************************AEPL module TZH******************************* Pour moteur 4 cylindres 4 temps Bobine allumage pilotée par module TSZ-H Table allumage pression / régime Possibilité d'utiliser presque n'importe quel capteur (pression absolue ou relative) Gestion de l'avance spécifique au ralenti pour régulation du régime (option désactivable) La gestion de l'avance au ralenti fonctionne sur le principe suivant: L'avance au ralenti est indépendante de la table d'allumage Elle est fixée à 10° dans le setup comme base de départ. On fixe une consigne de régime, avec une tolérance (exemple 800+-30tr/min) Si le régime est proche de cette consigne (exemple +-200tr/min), on applique l'avance ralenti. Tous les Ncycles (paramètre ajustable), on vérifie si le régime est dans la consigne Si il est dans la consigne, on ne change rien. Si il est hors consigne, on corrige l'avance d'un point et on conserve cette avance pour les Ncycles suivant. Le but d'espacer les corrections est de laisser le temps au régime de se stabiliser après une correction. Il est possible d'augmenter la vitesse d'éxecution de analogRead() en augmentant sa fréquence d'horloge(au détriment de la précision de la mesure) Elle est égale à: fréquence d'horloge CPU / facteur de division La configuration de la fréquence en fonction de ces variables est la suivante : ADPS2 | ADPS1 | ADPS0 | Facteur de division | Temps d'exécution analogRead() 1 1 1 128 110µs 1 1 0 64 60µs 1 0 1 32 30µs 1 0 0 16 16µs 0 1 1 8 8µs 0 1 0 4 4µs 0 0 1 2 2µs Les lignes suivantes sont à mettre en tête du programme #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif Celles-çi dans void Setup() sbi(ADCSRA, ADPS2); cbi(ADCSRA, ADPS1); cbi(ADCSRA, ADPS0); sbi vaut 1, cbi vaut 0. L'exemple ci dessus configure un facteur de division de 16 */ #include"TimerOne.h" // Timer pour gestion Module #ifndef cbi // #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // #endif // Pour configuration ADC #ifndef sbi // #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // #endif // // Attribution des entrées/sorties // #define Capteur 2 // Entrée digitale capteur hall #define Module 3 // Sortie module allumage #define Cap_MAP A0 // Entrée analogique capteur MAP #define Cap_AFR A1 // Entrée analogique capteur AFR // Configuration capteurs // #define AngleCapteur 60 // Les temps de calcul sont de 380us, soit 13° à 8000tr/min. Il faut placer le capteur à l'avance maxi + 13° avant PMH minimum bool Capteur_ON = LOW; // HIGH si Pin passe à 5V devant la cible (front montant), LOW si front descendant #define Umin 500 //(millivolts) Tension capteur MAP minimale #define Umax 4500 //(millivolts) Tension capteur MAP maximale #define MAP_min 0 //(KpA) Pression mini capteur MAP #define MAP_max 100 //(KpA) Pression maxi capteur MAP // Paramètres ajustables // #define Nmax 7000 // Régime de coupure moteur en tr/min #define Ndem 170 // Régime estimé au démarreur (pour premier cycle) #define Ncycles_Send_data 10 bool Send_data_active = true; bool Regulation_active = true; // Pour utiliser ou non la stratégie ralenti #define Consigne_ralenti 800 // Régime de consigne ralenti en tr/min #define Ncycles_ajustement 10 // Nombre de cycles avant nouvelle correction avance ralenti #define AAral_min 5 // AA mini au ralenti en °vilo #define AAral_max 18 // AA maxi au ralenti en °vilo #define Fourchette_ral 300 // Fourchette de régime pour application avance ralenti //***************** Table d'allumage en °vilebrequin ************************// // ************** Table 205 GTI 1,6 115cv origine************* // byte TabAA [11][13] = { // La première accolade représente le nombre de lignes, la deuxième les colonnes //7 11 15 21 27 35 39 45 51 56 60 70 80 tr/mn *100 {10, 10, 14, 22, 27, 27, 27, 27, 27, 32, 32, 31, 5}, //0 Kpa {10, 10, 14, 22, 27, 34, 33, 33, 32, 32, 32, 31, 5}, //10 {10, 10, 14, 22, 27, 34, 33, 33, 32, 32, 32, 31, 5}, //20 {10, 10, 15, 23, 28, 35, 34, 34, 33, 33, 33, 32, 5}, //30 {10, 10, 19, 27, 32, 39, 38, 38, 37, 37, 37, 36, 5}, //40 {10, 10, 23, 31, 36, 43, 42, 42, 41, 41, 41, 40, 5}, //50 {10, 10, 26, 34, 39, 46, 45, 45, 44, 44, 44, 43, 5}, //60 {10, 10, 26, 34, 39, 46, 45, 45, 44, 44, 44, 43, 5}, //70 {10, 10, 26, 34, 39, 46, 45, 45, 44, 44, 44, 43, 5}, //80 {10, 10, 26, 34, 39, 46, 45, 45, 44, 44, 44, 43, 5}, //90 {10, 10, 26, 34, 39, 46, 45, 45, 44, 44, 44, 43, 5} //100 }; // Pressions correspondantes aux lignes de la table d'allumage // #define T0 0 // Kpa #define T1 10 #define T2 20 #define T3 30 #define T4 40 #define T5 50 #define T6 60 #define T7 70 #define T8 80 #define T9 90 #define T10 100 // Régimes moteur correspondant aux colonnes de la table d'allumage // #define N0 700 // Tr/min #define N1 1100 #define N2 1500 #define N3 2100 #define N4 2700 #define N5 3500 #define N6 3900 #define N7 4500 #define N8 5100 #define N9 5600 #define N10 6000 #define N11 7000 #define N12 8000 //***************************** VARIABLES *********************************// // calcul Tcor // int unsigned long Temps_correction = 0; int unsigned long Debut_execution = 0; //*************** void Calc_N() *********************// int unsigned long H_prec = 0; // Heure précedente int unsigned long T_prec = 0; // Période précedente //(µs) Période en cours (360°vilebrequin) int unsigned long T = 0; // Période suivante int unsigned long Davant_rech = 0; // Délai a appliquer avant debut de charge bobine (pour respect du Dwell) int unsigned long N = 0; // Régime moteur en tr/min bool prem = false; // Flag pour premier calcul //*************** void Lec_CAP() *******************// int bit_Umin = 0; // Conversion tension capteur en Bit int bit_Umax = 0; // Idem int bit_MAP = 0; // Valeur analogique capteur MAP int somme_bit_MAP = 0; // int moy_bit_MAP = 0; // byte compteur_bit_MAP = 0; // int MAP = 0; // Pression absolue capteur MAP int bit_AFR = 0; // Valeur analogique sonde AFR int somme_bit_AFR = 0; // int moy_bit_AFR = 0; // byte compteur_bit_AFR = 0; // float AFR = 0; // Valeur AFR bool Flag_Map = false; // //*************** void Calc_D() ********************// byte Map = 0; // Papillon (ligne)pour entrer dans TabAA, de 0 à PapMax byte Reg = 0; // Regime (colonne) pour entrer dans TabAA, de 0 à RegMax float CT = 0; // Coefficient des Kpa pour interpollation float CN = 0; // Coefficient des Nt/mn pour interpollation float AA = 0; // (°vilo) Avance à l'allumage float D = 0; // Délai pour commande étincelle (en fonction de l'avance à l'allumage) #define Tcor 330 //Régulation ralenti// byte AAral = 0; // Avance à l'allumage au ralenti int Compteur_reg_ralenti = 0; // Compteur utilisé pour espacer les correction // void ISR_Gestion_bobine() // volatile bool Etincelle = false; // void Send_data() // byte Compteur_Send_data = 0; //******************************** FONCTIONS ************************************// void setup(){ Serial.begin(115200); pinMode(Capteur, INPUT_PULLUP); pinMode(Module, OUTPUT); sbi(ADCSRA, ADPS2); sbi(ADCSRA, ADPS1); cbi(ADCSRA, ADPS0); Timer1.attachInterrupt(ISR_Gestion_bobine); AAral = 10; // Fixe l'avance au ralenti à 10° comme base de départ, sera ajustée dans la stratégie ralenti selon le régime moteur Compteur_reg_ralenti = Ncycles_ajustement; bit_Umin = Umin / 4.9; // Convertit la tension min capteur MAP en Bit bit_Umax = Umax / 4.9; // Convertit la tension max capteur MAP en Bit prem = true; } void loop(){ while (digitalRead(Capteur) == !Capteur_ON); // Attente de la détection de la cible //Debut_execution = micros(); // Pour calcul Temps d'éxecution (pour essais) Calc_N(); // Calcul de T,N et Davant_rech Calc_D(); // Calcul de D pour prochain cycle Temps_correction = (micros()-Debut_execution); // Pour calcul Temps d'éxecution (pour essais) Lec_CAP(); // Lecture des capteurs Send_data(); // Log des données //Serial.println(MAP); //Serial.println(D); //Serial.println(Temps_correction); //Serial.println(N); //Serial.println(Compteur_reg_ralenti); //Serial.println(AA); while (digitalRead(Capteur) == Capteur_ON); // Attente si la cible est encore détectée } void Calc_N(){ T = micros() - H_prec; H_prec = micros(); Davant_rech = T * 3 / 10; N = 30000000 / T; if(prem==true) N = Ndem; prem = false; } void Calc_D(){ // Calcule le délai pour point d'allumage CalcMAP(); // Calcul de la ligne de TabAA suivant la pression MAP CalcReg(); // Calcul de la colonne de TabAA suivant le régime N //*************** Routine régulation ralenti *****************// if (Regulation_active == true && (N > (Consigne_ralenti-Fourchette_ral)) && (N < (Consigne_ralenti+Fourchette_ral))){ // Régulation configurée, régime dans la fourchette consigne +-200: on est au ralenti, on applique la stratégie AA = AAral; // AAral est fixée à 10° dans setup() comme base de départ, puis ajustée pour maintenir le régime au régime de consigne +-30trs/min Compteur_reg_ralenti --; // Le compteur sert à ne pas corriger l'avance à chaque cycle, pour laisser le temps au régime de se stabiliser if (N < (Consigne_ralenti - 30) && Compteur_reg_ralenti <= 0){ // Si le régime est sous le régime de consigne, on augmente l'avance d'un degré et remet le compteur à zéro pour voir si ça suffit AAral ++; if(AAral > AAral_max) AAral = AAral_max; Compteur_reg_ralenti = Ncycles_ajustement; } if (N > (Consigne_ralenti + 30) && Compteur_reg_ralenti <= 0){ // Si le régime est au dessus de la consigne, on diminue l'avance d'un degré AAral --; if(AAral < AAral_min) AAral = AAral_min; Compteur_reg_ralenti = Ncycles_ajustement; } } //*************************************************************// else { AA = TabAA[Map][Reg] ; AA = (TabAA[Map][Reg] * (1 - CT) * (1 - CN) + TabAA[Map + 1][Reg] * CT * (1 - CN) + TabAA[Map + 1][Reg + 1] * CT * CN + TabAA[Map][Reg + 1] * (1 - CT) * CN); } D = T / 180 * (AngleCapteur - AA)-Tcor; if(N < Nmax) Timer1.initialize(D); // Lancement du Timer pour déclenchament étincelle Etincelle = true; // Flag pour donner l'instruction à ISR } void Lec_CAP(){ if(Flag_Map == true){ somme_bit_MAP += analogRead(Cap_MAP);// Lecture de la valeur analogique capteur MAP compteur_bit_MAP ++; if(compteur_bit_MAP >= 10){ moy_bit_MAP = somme_bit_MAP / compteur_bit_MAP; MAP = map(moy_bit_MAP, bit_Umin, bit_Umax, MAP_min, MAP_max); // Conversion de cette valeur en Kpa MAP = constrain(MAP, MAP_min, MAP_max); somme_bit_MAP = 0; compteur_bit_MAP = 0; } Flag_Map = false; } else { somme_bit_AFR += analogRead(Cap_AFR); // Lecture de la valeur analogique capteur AFR compteur_bit_AFR++; if(compteur_bit_AFR >=10){ moy_bit_AFR = somme_bit_AFR / compteur_bit_AFR; AFR = map(moy_bit_AFR, 0, 1023, 100, 200); AFR = AFR / 10; somme_bit_AFR = 0; compteur_bit_AFR = 0; } Flag_Map = true; } } void Send_data(){ if (Send_data_active == true) { if(Compteur_Send_data <= 0){ // Compte à rebours terminé String Message = (("N") + String(N) + (",AA") + String(AA,0) + (",") + String(MAP) + ("MAP,AFR") + String(AFR,1)); // Préparation de la ligne de log //String Message = (("DATA,TIME,") + String(N) + (F(","))+String(AA) + (F(",")) + String(MAP) + (F(",")) + String(AFR)); Serial.println(Message); // Envoi des log vers port série Compteur_Send_data = Ncycles_Send_data; // Réinitialisation du compte à rebours } else { Compteur_Send_data--; } } } void ISR_Gestion_bobine(){ Timer1.stop(); // Arrêt du Timer if(Etincelle == true){ digitalWrite(Module, HIGH); // Coupure de la bobine pour déclenchement étincelle Etincelle = false; Timer1.initialize(Davant_rech); // Lancement du Timer pour mise en charge bobine } else{ digitalWrite(Module, LOW); // Mise en charge bobine } } void CalcReg(){ // Calcul le numero de colonne en fonction du régime N // ainsi que le coefficient CN pour interpoller AA dans la table // N12 limite supérieure, on commence à comparer à N11 if (N > N11){ Reg = 11; CN = (N - N11) / (N12 - N11); return; } if (N > N10){ Reg = 10; CN = (N - N10) / (N11 - N10); return; } if (N > N9){ Reg = 9; CN = (N - N9) / (N10 - N9); return; } if (N > N8){ Reg = 8; CN = (N - N8) / (N9 - N8); return; } if (N > N7){ Reg = 7; CN = (N - N7) / (N8 - N7); return; } if (N > N6){ Reg = 6; CN = (N - N6) / (N7 - N6); return; } if (N > N5){ Reg = 5; CN = (N - N5) / (N6 - N5); return; } if (N > N4){ Reg = 4; CN = (N - N4) / (N5 - N4); return; } if (N > N3){ Reg = 3; CN = (N - N3) / (N4 - N3); return; } if (N > N2){ Reg = 2; CN = (N - N2) / (N3 - N2); return; } if (N > N1){ Reg = 1; CN = (N - N1) / (N2 - N1); return; } Reg = 0; CN = (N - N0) / (N1 - N0); } void CalcMAP(){ // Calcul le numero de ligne en fonction du MAP // ainsi que le coefficient CT pour interpoller // T10 limite supérieure, on commence à comparer à T9 if (MAP > T9) { Map = 9; CT = (MAP - T9) / (T10 - T9); // Pour interpollation return; } if (MAP > T8) { Map = 8; CT = (MAP - T8) / (T9 - T8); return; } if (MAP > T7) { Map = 7; CT = (MAP - T7) / (T8 - T7); return; } if (MAP > T6) { Map = 6; CT = (MAP - T6) / (T7 - T6); return; } if (MAP > T5) { Map = 5; CT = (MAP - T5) / (T6 - T5); return; } if (MAP > T4) { Map = 4; CT = (MAP - T4) / (T5 - T4); return; } if (MAP > T3) { Map = 3; CT = (MAP - T3) / (T4 - T3); return; } if (MAP > T2) { Map = 2; CT = (MAP - T2) / (T3 - T2); return; } if (MAP > T1) { Map = 1; CT = (MAP - T1) / (T2 - T1); return; } Map = 0; CT = (MAP - T0) / (T1 - T0); } Comme vous pouvez le remarquer, cette version n'a plus grand chose à voir avec la précedente. -La saisie des avances se fait désormais avec une table et le calcul de D n'a plus rien à voir. En fait c'est une reprise de la méthode de calcul de l'injection de Philippe Loutrel. -L'avance au ralenti est indépendante et est ajustée en permanence pour maintenir un régime de consigne. C'est efficace: lorsque que l'on allume les phares par exemple, on voit bien l'avance augmenter et le régime est maintenu, là où il s'écroulait auparavent. -La mesure du capteur de pression est désormais faite sur plusieurs cycles pour moyenner cette valeur. Ce qui a pour effet de la rendre bien plus stable, là ou elle avait tendance à yoyoter, avec forcément un effet sur l'avance. -Grâce à l'utilisation du Timer pour le délai D, le programme a gagné en disponibilité et peut donc supporter plus de tâches. Je précise tout de même: cette version n'a pas encore été essayée sur la route, mais tous les essais que j'ai fait en statique démontre que les avances appliquées sont fidèles et stables, même à haut régime. Je pense donc qu'elle est essayable si le coeur vous en dit ? Bonne journée !
  7. Alors, par où commencer? ? Concernant les problèmes de log, j'ai écarté d'office un problème de "harware" car hors de l'utilisation de la fonction log, tout fonctionne parfaitement. C'est assez surprenant: au vu de sa simplicité il y aurait tellement de raisons pour que ça ne marche pas correctement mais le retour d'expérience des différents utilisateurs prouve le contraire. J'ai il y a quelques temps déjà échangé avec une personne qui a fait mon montage et l'a testé de façon un peu plus drastique que moi, il a épluché tous les signaux aux scope: aucun parasite malgré l'absence de blindages, les avances parfaitement respectées etc etc. Il a même réussi à démontrer que le NPN utilisé pour piloter le module est facultatif. On peut directement attaquer le module avec la sortie de l'Arduino, en inversant les états dans le programme. Quand je disais que je n'ai pas vraiment creusé le problème j'ai peut-être un peu exagéré car j'ai tout de même quelques pistes logicielles à ce sujet: En fait, quand on communique via le port série, l'établissement et la coupure de la liaison a pour conséquence de rebooter l'Arduino, ce qui explique la coupure du moteur. Pour l'instant, tous mes essais ont été effectués avec une vitesse de transmission de 9600bauds, ce qui est clairement trop lent et la grosse faiblesse du code tel qu'il est construit est que si la loop n'a pas fini son exécution au moment du passage de la cible, elle n'est pas vue par le programme. Du coup on saute une période et ça met la pagaille dans tous les calculs de régime, d'avance etc. Il est effectivement assez compliqué de faire du multitâche avec un Arduino mais c'est tout de même possible: Les gestions Speeduino avec un seul Arduino Uno gèrent allumage, injection, log, pression turbo etc etc. La clé étant de jouer avec les interruptions. C'est possible dans notre cas à condition de repenser l'architecture du programme. J'y ai réfléchi et j'ai normalement la solution: actuellement, la loop démarre au passage de la cible, elle s'éxecute et se met en attente du prochain passage. Là, on laisse tourner la loop et on déclenche une interruption lors du passage de la cible qui calcule le régime et lance un timer pour déclencher l'étincelle au moment voulu. Ainsi, le programme principal est libre pour exécuter d'autres fonctions et les temps de calcul n'ont plus d'importance. Ainsi on peut faire des logs et dans le cadre de mon futur projet, je pense même pouvoir gérer l'allumage et l'injection avec un seul Nano ! J'ai adapté le programme aujourd'hui, il me restera à l'essayer en réel. C'est une mise à jour assez importante car il y a pas mal d'évolutions par rapport au programme actuel, notamment l'utilisation d'une table pour les avances et une régulation du régime de ralenti par l'adaptation de l'avance. Je l'essaye dans la semaine et vous tiens au courant. Bonne soirée !
  8. Bonsoir à tous ! En effet je passe très peu sur ce forum, mais heureusement j'ai activé l'alerte sur ma boite mail quand un message est posté sur ce sujet ? Comme dit pierre 1302S, le code que j'ai publié en page 3 est fonctionnel et éprouvé. Si tu es intéressé par les fonctions de log malheureusement c'est plus compliqué: Lors des essais j'ai rencontrés quelques soucis assez fâcheux: la macro que j'utilise est très bien en soi si ce n'est que passé un certain régime moteur elle a tendance à planter ce qui a pour effet de couper l'Arduino et donc le moteur. Plutôt gênant, dangereux même ! Peut-être qu'elle ne suit pas la réception trop fréquente des données, ou est ce que ça vient de la "source", je ne sais pas et je n'ai pas pris le temps de creuser vraiment. Pareil pour la sortie que j'ai ajouté pour exploiter Powerdyn, le fonctionnement est très aléatoire en passant par l'entrée micro. Ce logiciel offre aussi la possibilité d'utiliser des fichiers log. Cette solution est beaucoup plus pertinente. Du coup, je m'oriente plus vers la création d'un logger, toujours à base d'Arduino, mais indépendant de l'allumage. J'ai déjà une ébauche: il servirait à Powerdyn et à extraire les données que l'on veut (régime, AFR etc). Le code est quasi abouti, il me reste à faire le boitier pour pouvoir attaquer des essais. Avec cette solution pas de problème: ça peut planter, on met pas la voiture en panne ? et une fois qu'on a fini nos réglages, on peut le retirer de la voiture. Il ne faut pas être trop pressé, j'ai pas mal de choses sur le feu et ma voiture est plus ou moins immobilisée pour le moment (une fuite d'huile un peu chiante). Je vous tiendrai au courant ! PS: Pierre, je te recontacte prochainement par mail ?
  9. Je ne connaissait pas non plus, j'ai trouvé ça en tapant "acquisition de données Arduino" sur Google. Voici un lien qui explique le fonctionnement https://www.instructables.com/Système-DAcquisition-De-Données-DAQ-Avec-Arduino-E/ Sinon j'ai fait un 2eme graphique, avec un nuage de points, pas mal pour avoir une vue d'ensemble: En abscisse le régime moteur, en ordonnée la dépression, et la couleur des points représente la richesse. J'en ai fait un deuxième avec plus de nuances de couleur et des points plus petits (une par point d'AFR soit 10 au total), à voir à l'usage lequel des deux sera le plus parlant. Là c'est simple: on roule et à la fin on obtient un beau nuage. En fonction des couleurs on identifie rapidement les zones à corriger. Bon, rien de nouveau ça existe déjà (genre MegaLogViewer de EFI Analytics), mais là c'est gratuit ?
  10. Aujourd'hui j'ai un peu bossé: J'ai fait un graphique Excel avec la macro PLX - DAQ, disponible sur le net. C'est une macro qui permet d'extraire les données envoyées via le port série et de les mettre dans des colonnes Excel, j'ai juste eu à créer et mettre à l'échelle le graphique. Le code que j'ai mis plus haut ne fonctionne pas, à oublier, je publierai bientôt le code fonctionnel. Le résultat me plaît bien et c'est une grande aide pour celui qui veut affiner les réglages de son moteur. Un petit lien youtube : A suivre...
  11. Salut à tous ! Quelques nouvelles: Pour l'instant tout fonctionne correctement. Avec seulement 150kms de parcourus il est un peu tôt pour se prononcer, mais ça a l'air fiable ?. J'ai apporté quelques modifications au code, notamment pour extraire des données via le port série. On y retrouve le régime moteur, l'avance à l'allumage (centrifuge+dépression), la valeur de dépression à l'admission pour en déduire la charge (en millimètres de mercure), et la valeur AFR de ma sonde lambda large bande. Il reste à faire un beau fichier Excel pour transformer ces valeurs en courbes. Le code: //Mr Philippe Loutrel pour l'AEPL original //Mr Dedessus les Moutiers Christophe pour la version Panhard avec prise en compte de la dépression //Mr Zorgati Antoine pour la version Peugeot avec sortie Powerdyn, prise en compte de la dépression et utilisation du module Bosch TSZ-H à la place de l'IGBT14C40L //Courbe d'avance à dépression à renseigner de la façon suivante: //int xhigh = 0;// Dépression correspondant à l'avance maxi, convertie en bits //int xlow = 0;// Dépression correspondant à l'avance mini, convertie en bits //int yhigh = 0;// Avance à dépression maxi, en degrés vilebrequin //int ylow = 0;// Avance mini de départ, toujours égale à zéro //Formule à appliquer pour la conversion dépression(mmHg) en bits: Nbits = 1,0912 x Dep(mmHg)+102,3 //Valable pour le capteur FAE réf 16111 //Courbe d'avance centrifuge à renseigner de la façon suivante: //int N[] = {0, 1300, 2000, 3500, 7000, 0}; //int Ang[] = {0, 0, 12, 24, 21, 0}; //const int Avancestatique = 10; //Chaque couple N Ang correspond à un point de la courbe centrifuge //L'avance statique est à ajouter à la courbe //Exemple ici: à 2000trs/min, l'avance centrifuge sera de 12°+10° d'avance statique soit 22° au vilebrequin //Courbe dépression à renseigner int xhigh = 604;// valeur ADC haute pour conversion de la valeur mmHg haute int xlow = 320;// valeur ADC basse pour conversion de la valeur mmHg basse int yhigh = 12;// valeur de la limite en degré haute int ylow = 0;// valeur de la limite en degré basse soit 0 degré //Courbe centrifuge à renseigner int N[] = {0, 1200, 2000, 3500, 7100, 0}; int Ang[] = {0, 0, 12, 24, 20, 0}; const int Avancestatique = 10; //Valeurs à renseigner selon les caractéristiques de votre moteur const int AngleCapteur = 60; //Avance statique de calage du capteur, en degrés vilebrequin const int CaptOn = 0; //CapteurOn = 1 si le signal est donné par un passage 0=>5V (front montant), CapteurOn = 0 si front descendant //Valeurs à renseigner selon la façon dont est cablé votre Arduino const int Module = 3; //Sortie D3 vers Module const int Powerdyn = 4; //Sortie D4 vers prise Jack (pour exploitation Powerdyn) const int Cible = 2; //Entrée D2 du capteur à effet Hall const int Injection = 5; //Sortie D5 vers Nano injection //Les valeurs suivantes n'ont pas lieu d'être modifiées int unsigned long T = 0; int unsigned long prec_H = 0; int unsigned long Tant = 0; int Dep = 0; int unsigned long D = 0; int unsigned long Ddep = 0; int unsigned long Dcent = 0; int milli_delay = 0; int micro_delay = 0; int milli_delay_avant_rech = 0; int micro_delay_avant_rech = 0; int unsigned long Davant_rech = 0; int N1 = 0; int Ang1 = 0; int N2 = 0; int Ang2 = 0; int* pN = &N[0]; int* pA = &Ang[0]; float k = 0; float C1[20]; float C2[20]; float Tc[20]; int Tlim = 0; int j_lim = 0; const int Tcor = 340; //correction en µs du temps de calcul pour D 120µs + 120µs de lecture de dépression + 140µs de traitement byte compteur_Signal_injection = 0; byte compteur_Send_data = 0; int Regime = 0; const unsigned char PS_16 = (1 << ADPS2); const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0); const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1); const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); //********************LES FONCTIONS************************* void CalcD ()////////////////// { Dep = analogRead(A0); // Mesure de la dépression float Degdep = map(Dep, xhigh, xlow, yhigh, ylow); // Détermination de l'avance à dépression if (Degdep < 0) { Degdep = 0; } else if (Degdep > yhigh) { Degdep = yhigh ; } else ; Ddep = T / 180 * Degdep; // Conversion de l'angle d'avance en délai for (int j = 1; j <= j_lim; j++) { if (T >= Tc[j]) { Dcent = float(T * C1[j] + C2[j]) ; // Détermination de l'avance centrifuge D = Dcent - Ddep - Tcor; // Détermination du délai à appliquer pour, temps de calcul pris en compte break; //Sortir, on a D } } } void Etincelle () { if (D < 14000) { delayMicroseconds(D); } else { milli_delay = ((D / 1000) - 2); micro_delay = (D - (milli_delay * 1000)); delay(milli_delay); delayMicroseconds(micro_delay); } digitalWrite(Module, 1); digitalWrite(Powerdyn, 1); Davant_rech = T * 3 /10; if (Davant_rech < 14000) { delayMicroseconds(Davant_rech); } else { milli_delay_avant_rech = ((Davant_rech / 1000) - 2); micro_delay_avant_rech = (Davant_rech - (milli_delay_avant_rech * 1000)); delay(milli_delay_avant_rech); delayMicroseconds(micro_delay_avant_rech); } digitalWrite(Module, 0); digitalWrite(Powerdyn, 0); } void setup() { Serial.begin(115200); pinMode(Cible, INPUT); pinMode(Module, OUTPUT); pinMode(Powerdyn, OUTPUT); pinMode(Injection, OUTPUT); ADCSRA &= ~PS_128; ADCSRA |= PS_64; N1 = 0; Ang1 = 0; int i = 0; pN++; pA++; for (i = 1; *pN != 0; i++) { N2 = *pN; Ang2 = *pA; k = float(Ang2 - Ang1) / float(N2 - N1); C1 = float(AngleCapteur - Avancestatique - Ang1 + k * N1) / 180; C2 = - float(30000000 * k) / 180; Tc = float(30000000 / N2); N1 = N2; Ang1 = Ang2; pN++; pA++; } j_lim = i - 1; Tlim = Tc[j_lim]; } void loop() { while (digitalRead(Cible) == !CaptOn); T = micros() - prec_H; Regime = 30000000 / T; prec_H = micros(); if (T > Tlim) { CalcD(); Etincelle(); } if (T < Tlim) { T = Tant; CalcD(); Etincelle(); } if (Regime<=6500){ Send_data();} Signal_injection(); Tant = T; while (digitalRead(Cible) == CaptOn); } void Send_data() { if (compteur_Send_data >=9) { float AFR = analogRead(A1)/10+100 ; int Dep_mmHg = (Dep-102)*9/10; byte AA = AngleCapteur-(180*(Dcent-Ddep)/T); String Message = ("N"+String(Regime)+(",AA")+String(AA)+(",mmHg")+String(Dep_mmHg)+(",AFR")+String(AFR)); Serial.println(Message); compteur_Send_data =0; } else { compteur_Send_data++; } } void Signal_injection() { if (compteur_Signal_injection >= 3) { digitalWrite (Injection, 1); delayMicroseconds(50); digitalWrite (Injection, 0); compteur_Signal_injection = 0; } else { compteur_Signal_injection++; } } La fonction Signal_injection() sert à envoyer un signal à chaque cycle (soit 2 tours vilo). Pour un autre projet ?
  12. lebriiice, Sur nos moteur (1600CT), on a une lumière différence sur le cylindre 3 pour limiter la chauffe car il est a la peine en refroidissement. Intéressant, du coup je suppose que le décalage diminue l'avance du cylindre 3. Astucieux, je ne connaissait pas ! C'est bon à savoir si jamais j'ai l'occasion de bosser sur un Flat4 ? Dans mon cas, je pense plus à une piètre qualité de fabrication, le distributeur étant à l'origine prévu pour une Golf. En tout cas, sacré sujet et beau dossier bien alimenté et riche en info. Merci ! Ca fait toujours plaisir de recevoir des compliments quand on a bossé dur sur un sujet, et si ça peut vous servir, c'est tout bénéf ! Pod, ça va être sympa de voir comment fonctionne la partie capteur à depression Oui, autant pour une conduite On/Off la dépression est inutile, autant on y trouve un intéret en utilisation routière. Sur mon auto, la capsule à dépression était HS depuis un moment, je l'ai achetée et toujours conduite ainsi. Avec le nouvel allumage, je suis pour l'instant en courbe d'origine et j'ai senti la différence au niveau souplesse. Preuve de l'utilité de la chose ?
  13. Maintenant que je suis sûr du code, le voici: #include <TimerOne.h> // Philippe Loutrel pour l'AEPL original // Christophe Dedessus les Moutiers pour la version Panhard avec prise en compte de la dépression // Antoine Zorgati pour la version Peugeot avec sortie Powerdyn, prise en compte de la dépression et utilisation du module Bosch TSZ-H à la place de l'IGBT14C40L //Courbe d'avance à dépression à renseigner de la façon suivante: //int xhigh = 604;// Dépression correspondant à l'avance maxi, convertie en bits //int xlow = 320;// Dépression correspondant à l'avance mini, convertie en bits //int yhigh = 12;// Avance à dépression maxi, en degrés vilebrequin //int ylow = 0;// Avance mini de départ, toujours égale à zéro //Formule à appliquer pour la conversion dépression(mmHg) en bits: Nbits = 1,0912 x Dep(mmHg)+102,3 //Valable pour le capteur FAE réf 16111 //Courbe d'avance centrifuge à renseigner de la façon suivante: //int N[] = {0, 1300, 2000, 3500, 7000, 0}; //int Ang[] = {0, 0, 12, 24, 21, 0}; //const int Avancestatique = 10; //Chaque couple N Ang correspond à un point de la courbe centrifuge //L'avance statique est à ajouter à la courbe //Exemple ici: à 2000trs/min, l'avance centrifuge sera de 12°+10° d'avance statique soit 22° au vilebrequin //Courbe dépression à renseigner int xhigh = 604;// valeur ADC haute pour conversion de la valeur mmHg haute int xlow = 320;// valeur ADC basse pour conversion de la valeur mmHg basse int yhigh = 12;// valeur de la limite en degré haute int ylow = 0;// valeur de la limite en degré basse soit 0 degré //Courbe centrifuge à renseigner int N[] = {0, 1300, 2000, 3500, 7000, 0}; int Ang[] = {0, 0, 12, 24, 21, 0}; const int Avancestatique = 10; //Valeurs à renseigner selon les caractéristiques de votre moteur int Ncyl = 4;//Nombre de cylindres const int AngleCapteur = 60;//Avance statique de calage du capteur, en degrés vilebrequin const int CaptOn = 0; //CapteurOn = 1 si le signal est donné par un passage 0=>5V (front montant), CapteurOn = 0 si front descendant const int Nplancher = 1000; // vitesse en t/mn jusqu'a laquelle l'avance à dépression = 0°, utile si la prise de dépression est en aval du papillon des gaz (pour ne pas perturber le ralenti) //Valeurs à renseigner selon la façon dont est cablé votre Arduino const int Module = 3; //Sortie D3 vers Module const int Powerdyn = 4; //Sortie D4 vers prise Jack (pour exploitation Powerdyn) const int Cible = 2; //Entrée D2 du capteur à effet Hall //Les valeurs suivantes n'ont pas lieu d'être modifiées int unsigned long D = 0; int unsigned long Ddep = 0; int unsigned long Dsum = 0; int milli_delay = 0; int micro_delay = 0; float Tplancher = 0; const int tcor = 380; //correction en µs du temps de calcul pour D 120µs + 120µs de lecture de dépression + 140µs de traitement int unsigned long Davant_rech = 0; int unsigned long Tprec = 0; int unsigned long prec_H = 0; int unsigned long T = 0; int unsigned long Tant = 0; int N1 = 0; int Ang1 = 0; int N2 = 0; int Ang2 = 0; int* pN = &N[0]; int* pA = &Ang[0]; float k = 0; float C1[20]; float C2[20]; float Tc[20]; int Tlim = 0; int j_lim = 0; int unsigned long NT = 0; int AngleCibles = 0; int UneEtin = 1; float uspardegre = 0; int Dep = 0; float Degdep = 0; int unsigned long Vitesse = 0; float Delaideg = 0; unsigned long Stop_temps; unsigned long Tempsecoule = 0; const unsigned char PS_16 = (1 << ADPS2); const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0); const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1); const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); //********************LES FONCTIONS************************* void CalcD () { for (byte j = 1; j <= j_lim; j++) { if (T >= Tc[j]) { D = float(T * C1[j] + C2[j]); Ddep = (Degdep * Delaideg ) ; //if (T > Tplancher){Ddep=0}; //Pour activer cette fonction, enlever les // en début de ligne Dsum = D - Ddep - tcor ; break; } } } void Etincelle () { if (Dsum < 14000) { delayMicroseconds(Dsum); } else { milli_delay = ((Dsum / 1000) - 2); micro_delay = (Dsum - (milli_delay * 1000)); delay(milli_delay); delayMicroseconds(micro_delay); } digitalWrite(Module, 1); digitalWrite(Powerdyn, 1); Stop_temps = micros(); Davant_rech = T * 3 /10; Timer1.initialize(Davant_rech); UneEtin = 1; } void Init () { AngleCibles = 720 / Ncyl; NT = 120000000 / Ncyl; Tplancher = 120000000 / Nplancher / Ncyl; Prep_courbe(); Serial.print("Tc = "); for (int i = 1 ; i < 8; i++)Serial.println(Tc); Serial.print("Tlim = "); Serial.println(Tlim); Serial.print("C1 = "); for (int i = 1 ; i < 8; i++)Serial.println(C1); Serial.print("C2 = "); for (int i = 1 ; i < 8; i++)Serial.println(C2); Timer1.attachInterrupt(isr_GestionIbob); } void Prep_courbe() { 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); C1 = float(AngleCapteur - Avancestatique - Ang1 + k * N1) / float(AngleCibles); C2 = - float(NT * k) / float(AngleCibles); Tc = 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 } void isr_GestionIbob() { Timer1.stop(); if (UneEtin == 1) { digitalWrite(Module, 0); digitalWrite(Powerdyn, 0); } UneEtin = 0; } void setup() { Serial.begin(115200); if (Ncyl < 2)Ncyl = 2; pinMode(Cible, INPUT_PULLUP); pinMode(Module, OUTPUT); pinMode(Powerdyn, OUTPUT); ADCSRA &= ~PS_128; // you can choose a prescaler from above. // PS_16, PS_32, PS_64 or PS_128 ADCSRA |= PS_64; // set our own prescaler to 64 Init(); } void loop() { while (digitalRead(Cible) == !CaptOn); T = micros() - prec_H; prec_H = micros(); Dep = analogRead(A0); Degdep = map(Dep, xhigh, xlow, yhigh, ylow); if (Degdep < 0) { Degdep = 0; } else if (Degdep > yhigh) { Degdep = yhigh ; } else ; Vitesse = NT / T; Delaideg = NT / Vitesse / float(AngleCibles); if (T > Tlim) { CalcD(); Etincelle(); } if (T < Tlim) { T = Tant; CalcD(); Etincelle(); Vitesse = NT / Tant; } while (digitalRead(Cible) == CaptOn); Tempsecoule = Stop_temps - prec_H ; Tant = T; }
  14. Bon j'ai essayé ce matin, toujours pas bon... Faut se rendre à l'évidence, ça ne vient pas d'une fuite de courant, néanmoins, ça vient forcément du distributeur. Du coup, je me suis penché sur la partie signal de celui-çi. J'ai observé le signal de sortie avec la prise que j'ai dédié à Powerdyn, ce qui m'a permis au passage de tester cette fonction Voilà ce que j'en ai tiré avec Audacity: Visiblement, on a bien les 4 cylindres mais on peut observer des irrégularités (3 temps courts 1 temps long) J'ai mis à poil mon distributeur et j'ai localisé le coupable: la roue phonique! On voit clairement qu'une encoche est décalée... Après un petit coup de lime, c'est beaucoup mieux: J'ai tout remonté et miracle, tout est rentré dans l'ordre !!!! Quel bonheur ? Les 4 cylindres sont bien présents à tout les régimes et logique, le ralenti est devenu bien stable ? On peut voir que le signal est maintenant bien régulier: J'aurai dû m'en douter: il faut être un peu naïf (ou c*n, c'est comme on veut!) pour penser qu'une pièce adaptable à 47 balle serait aussi bien faite que l'original Bosch à 250e... A suivre...
  15. C'est précisément à cette pièce que je pense. Il y en a bien une fournie avec le distributeur mais elle respire pas la qualité (adaptable oblige...) La partie entourée m'a l'air d'être une zone de faiblesse Mon idée est que les ratés ne se produisent pas à un régime donné mais plutôt à une avance donnée. J'ai repéré la position du doigt et sur des faibles avances on est plus proche de cette zone qu'à des avances plus grandes. Ca expliquerai qu'à haut régime il n'y a pas de souci. Ca expliquerai aussi pourquoi ça se produit que sur un cylindre: Cette zone est celle où le doigt est en position pour l'allumage du cylindre n°2. J'ai essayé d'isoler avec du ruban d'électricien , ça n'a rien changé mais c'est peut-être insuffisant. J'ai retrouvé un couvercle en plastique d'origine Bosch, ça sera surement mieux mais il va falloir attendre demain, il est un peu tard pour faire ronfler le moteur dans le garage ?. Si c'est vraiment ça, c'est vicelard comme panne...
×
×
  • Create New...