Bonjour,
Je suis sur un projet de boitier bioethanol dont le principe est de lire la valeur d'ethanol contenue dans un réservoir d'essence, convertir cette valeur en pourcentage d'augmentation de durée d'injection et prolonger la durée de commande des injecteurs.
Ayant besoin de 4 interruptions pour gérer les 4 cylindres et étant sur arduino nano, j'utilise les PCINT via la librairie PinChangeInterrupt.h.
En parallèle je voulais gérer un écran sur controleur st7735 pour monitorer certaines variables.
Or la partie affichage fait rater des interruptions, là j'affiche que le pourcentage d'ethanol, la fonction prend quand même 27 ms à exécuter et plus je rajoutes de variables à afficher plus il rate des injections (le moteur broute) alors qu'on est à un petite centaine de Hz.
Quelqu'un saurait expliquer pourquoi ? Le principe des interruptions est qu'elles ont la priorité. Or, ici ça ne semble pas être le cas. Je n'ai pas trouvé de cas d'interférence entre la gestion du SPI et les interruptions/timer1.
Si quelqu'un a des idées, je suis preneur...
#include "PinChangeInterrupt.h"
#include <Arduino.h>
//PARTIE AFFICHAGE
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
#define TFT_CS 5
#define TFT_RST A5 // Or set to -1 and connect to Arduino RESET pin
#define TFT_DC 3
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
unsigned int VRT;
volatile unsigned int frontMontantFlex, precedentfrontMontantFlex,periodeFlex, periodeVitesse, tempsCycleMoteur, frontMontantVitesse, precedentfrontMontantVitesse, timer, timer2 ;
volatile unsigned long tempsInjectionDeBase, momentOuvertureInj, prededentDeclenchementInj,tempsSupplementaireTick;
unsigned long periodeFlex2, frequence, injDutyCycle, tempsDepuisDerniereInj, dernierAffichage, derniereTemperature, dernierEthanol, dernierRPM;
unsigned int pourcentageEthanol, pourcentageProlongation, regimeMoteur;
float rapportReduction;
byte rapportEngage;
bool capteurDebranche;
bool initialisation = 1;
void setup() {
// init entrées inj
pinMode(14, INPUT);//les pullups sont en hardware
pinMode(15, INPUT);
pinMode(16, INPUT);
pinMode(17, INPUT);
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(14), interruptinj1, CHANGE);//revérifier si front montant ou descendant attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(14), testvide, RISING); 14,10
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(15), interruptinj2, CHANGE);//15,9
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(16), interruptinj3, CHANGE);//16,6
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(17), interruptinj4, CHANGE);//17,7
// init sorties inj
pinMode(10, OUTPUT);//INJ1
pinMode(9, OUTPUT);//INJ2
pinMode(6, OUTPUT);//INJ3
pinMode(7, OUTPUT);//INJ4
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
//Capteur Ethanol
pinMode(8, INPUT);
attachPinChangeInterrupt(digitalPinToPCINT(8), interruptFlex, FALLING);
//Sonde température
pinMode(A6, INPUT);
//Capteur Vitesse
pinMode(2, INPUT);
attachInterrupt(digitalPinToInterrupt(0), ISRvitesse, RISING);
//capteur point mort
pinMode(4, INPUT);//pullup probablement déjà gérée par l'ECU
inittimer();
tft.initR(INITR_MINI160x80); // Init ST7735S mini display
tft.setRotation(3);
tft.fillScreen(ST77XX_BLACK);
}
void interruptinj1(){
if(digitalRead(14)==LOW){//on vérifie si c'était l'ouverture de l'injecteur
digitalWrite(10, HIGH);//on commande l'injecteur dès que l'ecu envoie l'info
momentOuvertureInj = micros();
//calcul tours minute:
tempsCycleMoteur = micros() - prededentDeclenchementInj;
prededentDeclenchementInj = micros();
tempsDepuisDerniereInj=0;
}
else if(digitalRead(14)==HIGH){//L'ECU stoppe l'injection
TCNT1 = 0;//on initialise le timer 2 (en 8 bits) à 0
tempsInjectionDeBase = micros() - momentOuvertureInj;
tempsSupplementaireTick = tempsInjectionDeBase*2;//x2 car l tick c'est 0.5µs
tempsSupplementaireTick = tempsSupplementaireTick*pourcentageProlongation;//pourcentage déduit de la lecture du capteur ethanol
tempsSupplementaireTick = tempsSupplementaireTick/100;//divise par 100 pour un pourcentage
OCR1A = tempsSupplementaireTick;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt*/
}
}
void interruptinj2() {
if (digitalRead(15) == LOW) {//on vérifie si c'était l'ouverture de l'injecteur
digitalWrite(9, HIGH);//on commande l'injecteur dès que l'ecu envoie l'info
momentOuvertureInj = micros();
}
else if(digitalRead(15)==HIGH){//L'ECU stoppe l'injection
TCNT1 = 0;//on initialise le timer 2 (en 8 bits) à 0
tempsInjectionDeBase = micros() - momentOuvertureInj;
tempsSupplementaireTick = tempsInjectionDeBase*2;//x2 car l tick c'est 0.5µs
tempsSupplementaireTick = tempsSupplementaireTick*pourcentageProlongation;//pourcentage déduit de la lecture du capteur ethanol
tempsSupplementaireTick = tempsSupplementaireTick/100;//divise par 100 pour un pourcentage
OCR1A = tempsSupplementaireTick;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt*/
}
}
void interruptinj3() {
if (digitalRead(16) == LOW) {//on vérifie si c'était l'ouverture de l'injecteur
digitalWrite(6, HIGH);//on commande l'injecteur dès que l'ecu envoie l'info
momentOuvertureInj = micros();
}
else if(digitalRead(16)==HIGH){//L'ECU stoppe l'injection
TCNT1 = 0;//on initialise le timer 2 (en 8 bits) à 0
tempsInjectionDeBase = micros() - momentOuvertureInj;
tempsSupplementaireTick = tempsInjectionDeBase*2;//x2 car l tick c'est 0.5µs
tempsSupplementaireTick = tempsSupplementaireTick*pourcentageProlongation;//pourcentage déduit de la lecture du capteur ethanol
tempsSupplementaireTick = tempsSupplementaireTick/100;//divise par 100 pour un pourcentage
OCR1A = tempsSupplementaireTick;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt*/
}
}
void interruptinj4() {
if (digitalRead(17) == LOW) {//on vérifie si c'était l'ouverture de l'injecteur
digitalWrite(7, HIGH);//on commande l'injecteur dès que l'ecu envoie l'info
momentOuvertureInj = micros();
}
else if(digitalRead(17)==HIGH){//L'ECU stoppe l'injection
TCNT1 = 0;//on initialise le timer 2 (en 8 bits) à 0
tempsInjectionDeBase = micros() - momentOuvertureInj;
tempsSupplementaireTick = tempsInjectionDeBase*2;//x2 car l tick c'est 0.5µs
tempsSupplementaireTick = tempsSupplementaireTick*pourcentageProlongation;//pourcentage déduit de la lecture du capteur ethanol
tempsSupplementaireTick = tempsSupplementaireTick/100;//divise par 100 pour un pourcentage
OCR1A = tempsSupplementaireTick;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt*/
}
}
ISR(TIMER1_COMPA_vect) {//ISR déclenchée quand OCRn est atteint par le timer
//pour économiser du code, on peut tout couper à chaque fois
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
}
void loop() {
if((millis()- dernierEthanol)>100){
lectureEthanol();
}
if((millis()- dernierRPM)>30){
compteTours();
}
if((millis()- dernierAffichage)>200){
lectureTemperatureMoteur();
}
if((millis()- dernierAffichage)>1000){
ecran();
}
}
void interruptFlex(){
frontMontantFlex = micros();
periodeFlex= frontMontantFlex - precedentfrontMontantFlex;
precedentfrontMontantFlex = frontMontantFlex;
}
void lectureEthanol(){
frequence = 1000000/periodeFlex;//on calcule ici pour alléger l'ISR
if (frequence >150){//erreur
pourcentageEthanol = 10;//on considere que c'est de l'E10
}
else{
pourcentageEthanol = map(frequence, 50, 150, 0, 100);//on prend une fréquence qui va de x à x pour la convertir en pourcentage qui va de 0 à 100 //test avec vodka à 40-->170hz spirytus à 95-->150
}
pourcentageProlongation = map(pourcentageEthanol, 0, 85, 0, 33);// quand on a 100% d'ethanol on injecte 33% plus longtemps donc faut convertir quand on n'a pas 100% a verifier si c'es 33% pour 85% ou 100% d'ethanol
if(frequence==4294967295)
capteurDebranche = true;
else
capteurDebranche = false;
dernierEthanol=millis();
}
void compteTours(){
/*prévoir de le remettre à 0*/
regimeMoteur = 120000000/tempsCycleMoteur;//60 000 000 * 2 car les rpm sont le double du temps de cycle (4-temps oblige)
if(regimeMoteur>20000){
regimeMoteur = 0;
}
injDutyCycle = tempsInjectionDeBase * pourcentageProlongation;
injDutyCycle = injDutyCycle /100;
injDutyCycle = tempsInjectionDeBase + injDutyCycle;
injDutyCycle = injDutyCycle*100;
injDutyCycle = injDutyCycle/tempsCycleMoteur;
dernierRPM=millis();
}
void lectureTemperatureMoteur(){
VRT = analogRead(A0); //Acquisition analog value of VRT
//à voir plus tard
// En dessous de 7degrés il faut rajouter 10 à 20%
//
derniereTemperature=millis();
}
void ecran(){
unsigned long temps = millis();
String ligneEcran = "";
tft.setCursor(0, 0);
tft.setTextColor(ST77XX_GREEN,ST77XX_BLACK);
tft.setTextSize(3);
ligneEcran ="E85:" + String(pourcentageEthanol) + "%";
if(pourcentageEthanol<10){ligneEcran+=" "; }
if (ligneEcran.length()>8) //pour éviter un bug d'affichage
tft.println("E85:--");
else
tft.println(ligneEcran); //27ms en moyenne pour afficher juste l'ethanol en slow spi
/*
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW,ST77XX_BLACK);
ligneEcran ="RPM:" + String(regimeMoteur);
if(regimeMoteur<1000){ligneEcran+=" "; }
tft.println(ligneEcran);
tft.setTextColor(ST77XX_BLUE,ST77XX_BLACK);
ligneEcran ="D.C:" + String(injDutyCycle) + "%";
if(injDutyCycle<10){ligneEcran+=" "; }
if (ligneEcran.length()<9) //pour éviter un bug d'affichage
tft.println(ligneEcran);
tft.setTextSize(1);
tft.setTextColor(ST77XX_RED,ST77XX_BLACK);
ligneEcran ="Temp: " + String(VRT) + " ";
tft.println(ligneEcran);
ligneEcran =String(frequence) + " Hz ";
tft.println(ligneEcran);
*/
/*
String ligneEcran = "";
u8x8.setFont(u8x8_font_artossans8_r);//u8x8_font_artossans8_r, u8x8_font_chroma48medium8_r pas mal, u8x8_font_torussansbold8_r excellent, u8x8_font_pcsenior_f aussi
ligneEcran =String(regimeMoteur) + " RPM ";
u8x8.drawString(0,0, string2char(ligneEcran));
ligneEcran = "";
ligneEcran ="D.C: "+String(injDutyCycle) + "% ";
u8x8.drawString(0,2, string2char(ligneEcran));
u8x8.setFont(u8x8_font_profont29_2x3_f);//u8x8_font_artossans8_r, u8x8_font_chroma48medium8_r pas mal, u8x8_font_torussansbold8_r excellent, u8x8_font_pcsenior_f aussi
ligneEcran = "";
ligneEcran ="E: " +String(pourcentageEthanol) + "% ";
u8x8.drawString(0,4, string2char(ligneEcran));
*/
dernierAffichage=millis();
unsigned long duree = millis() - temps;
}
void ecran(){
String ligneEcran = "";
u8x8.setFont(u8x8_font_artossans8_r);//u8x8_font_artossans8_r, u8x8_font_chroma48medium8_r pas mal, u8x8_font_torussansbold8_r excellent, u8x8_font_pcsenior_f aussi
ligneEcran =String(regimeMoteur) + " RPM ";
u8x8.drawString(0,0, string2char(ligneEcran));
ligneEcran = "";
ligneEcran ="D.C: "+String(injDutyCycle) + "% ";
u8x8.drawString(0,2, string2char(ligneEcran));
u8x8.setFont(u8x8_font_profont29_2x3_f);//u8x8_font_artossans8_r, u8x8_font_chroma48medium8_r pas mal, u8x8_font_torussansbold8_r excellent, u8x8_font_pcsenior_f aussi
ligneEcran = "";
ligneEcran ="E: " +String(pourcentageEthanol) + "% ";
u8x8.drawString(0,4, string2char(ligneEcran));
dernierAffichage=millis();
}
void inittimer() {//timer1 sur 16bits
cli();
// parametrage du timer 1
TCCR1A = 0;//permet de définir le mode, ses bits 0 et 1 sont respectivement WGM20 etWGM21, 0 mode normal
TCCR1B = 0;
TCNT1 = 0;
TIFR1 = 0x00;//registre conprenant les flags d'overflow du timer
TIMSK1 = 0 ;// autorise les interruptions et leurs flags (modes OCIE1B , OCIE1A et TOIE1)
TCCR1B |= (1 << CS11); // 8 prescaler Définit le prescaler sur ses 3 premiers bits (en partant de la fin)
sei();
}