Using 4 Transistors seperately

Hello guys,

for a fuel injector measuring stand I need to use 4 trainsistors as switches seperately. The goal is to run all injectors seperately with several programs.
At the moment, the code works when Im using LED´s instead of transistors / injectors. So the program code is fine. If Im using only one Transistor, it works also fine.

The error occurs when using 2 or more Transistor for switching on injectors. In this case, all Transistors are becoming leading state, if any Transistor is switched to "high".

Lets take the sketch "blink without delay" as example. The goal would be, that the transistors switch on 2 injectors seperately one after each other and also shut one off injector 1 at the time, when injector 2 goes on.
With my wiring, all inejctors would go on, so both injectors would be switched off at any time.

Ive attached the current wirering.
Do you see any bugs that i missed?

EDIT: The Arduino is connected to an touchscreen, which also handles the function. For better visibility Ive reduced the drawing to the wiring with bug.

best regards,
Gustav

How much current does the injector need?
How much current does the power supply give?

Post your code. Read the forum guidelines to see how to properly post code and some hints on how to get the most from this forum.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

The injectors using 16 ohm coils, so they draw < 1A at 12V.
Im using a 12V 30A DC power supply.

The described error occurs at "void startventilate(){..." at line 341.

#include <SoftPWM.h> //library for using non pwm pin as pwm pins
#include <SoftPWM_timer.h> //library for using non pwm pin as pwm pins
#include "TouchScreen.h" //touch library
#include "LCDWIKI_GUI.h" //Core graphics library
#include "LCDWIKI_KBV.h" //Hardware-specific library

LCDWIKI_KBV my_lcd(ILI9486, A3, A2, A1, A0, A4); //model,cs,cd,wr,rd,reset

// making digital pins to pwm pins and declaring them
#define PIN1_PWM    31
#define PIN2_PWM    33
#define PIN3_PWM    35
#define PIN4_PWM    37
//snippet for turn on injectors repeatedly with lower voltage (PWM)
const uint8_t PWMPins[4] = { PIN1_PWM, PIN2_PWM, PIN3_PWM, PIN4_PWM};
const uint8_t lastPWMIndex = sizeof(PWMPins) - 1;
const uint16_t openDuration_opentest1 = 250; //time period for void open test 1
const uint16_t openDuration_opentest2 = 500;  //time period for open test 2
uint32_t lastopen;
uint8_t currPWM = lastPWMIndex;

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//touch sensitivity for X
#define TS_MINX 906
#define TS_MAXX 116

//touch sensitivity for Y
#define TS_MINY 92
#define TS_MAXY 952

#define MINPRESSURE 10
#define MAXPRESSURE 1000

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

// declaration for grafics
void show_string(uint8_t *str, int16_t x, int16_t y, uint8_t csize, uint16_t fc, uint16_t bc, boolean mode)
{
  my_lcd.Set_Text_Mode(mode);
  my_lcd.Set_Text_Size(csize);
  my_lcd.Set_Text_colour(fc);
  my_lcd.Set_Text_Back_colour(bc);
  my_lcd.Print_String(str, x, y);
}

boolean is_pressed(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t px, int16_t py)
{
  if ((px > x1 && px < x2) && (py > y1 && py < y2))
  {
    return true;
  }
  else
  {
    return false;
  }
}

char currentpage;
unsigned long previousMillis;
unsigned long currentMillis;
unsigned long ventilateMillis;

// snippet for ventilation, putting on one injector after another repeatedly
const uint8_t ledPins[4] = { 31, 33, 35, 37 };
const uint8_t lastIndex = sizeof(ledPins) - 1;
const uint16_t blinkDuration = 200; //time period for void ventilation
uint32_t lastBlink;
uint8_t currLed = lastIndex;
//declarate matching parameters
int matchtime = 0;
int dynamicmatchtime = 0;
int vmax = 0;
int vmin = 0;
int vmindyn = 0;
int vmaxdyn = 0;

int buttonleakcheckstate = LOW;
int buttonventilatestate = LOW;
int buttonopentest1state = LOW;
int buttonopentest2state = LOW;
int dynamicmatchstate = 0;

void setup() {
  my_lcd.Init_LCD();
  my_lcd.Fill_Screen(WHITE);
  drawhomescreen();
  currentpage = '0';

  pinMode(31, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(37, OUTPUT);

  SoftPWMBegin(); // starting pwm functionality of non pwm pins

  for (auto pin : ledPins) { // functionality for ventilation function
    pinMode(pin, OUTPUT);
  }
  for (auto pin : PWMPins) { // functionality for ventilation function
    pinMode(pin, OUTPUT);
  }

  pinMode(31, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(37, OUTPUT);
}

void loop() {
  Serial.begin(9600);
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  ////////////// general functionality of pages ////////////////////////////////

  if (currentpage == '0') {

    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);

      if (is_pressed(10, 50, 310, 100, p.x, p.y)) //400 ccm clicked
      {
        matchtime = 6000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 150, 310, 200, p.x, p.y)) //470 ccm clicked
      {
        matchtime = 5000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 250, 310, 300, p.x, p.y)) //600 ccm clicked
      {
        matchtime = 4000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 350, 310, 400, p.x, p.y)) //900 ccm clicked
      {
        matchtime = 3000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        ventilateMillis = currentMillis;
      }
    }
  }

  if (currentpage == '1') {
    startventilate();
    currentMillis = millis();

    if ((buttonventilatestate == LOW) && (currentMillis - ventilateMillis > 5000)) {
      button_ventilate();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonventilatestate == HIGH))
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {
        digitalWrite(31, LOW);
        digitalWrite(33, LOW);
        digitalWrite(35, LOW);
        digitalWrite(37, LOW);
        currentpage = '2';
        leakcheck(); // display screen "start leak check"
        currentMillis = millis();
        previousMillis = currentMillis;
      }
    }
  }

  if (currentpage == '2') {
    currentMillis = millis();

    if ((buttonleakcheckstate == LOW) && (currentMillis - previousMillis > 8000)) {
      button_leakcheck();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonleakcheckstate == HIGH))
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //leak check ok button clicked
      {
        currentpage = '3';
        drawmatching();
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 350, 310, 400, p.x, p.y)) //leak check Nok button clicked
      {
        my_lcd.Fill_Screen(WHITE);
        drawhomescreen();
        currentpage = '0';
      }
    }
  }

  if (currentpage == '3') {
    matching(matchtime);
  }

  if (currentpage == '4') {
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {

        my_lcd.Fill_Screen(WHITE);
        drawdynamicmatching();
        currentMillis = millis();
        previousMillis = currentMillis;
        currentpage = '5';

      }
    }
  }

  if (currentpage == '5') {
    dynamicmatching(dynamicmatchtime);
  }

  if (currentpage == '6') { // page for evalutating dynamic match results
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {

        my_lcd.Fill_Screen(WHITE);
        drawopentest1();
        currentMillis = millis();
        previousMillis = currentMillis;
        currentpage = '7';

      }
    }
  }


  if (currentpage == '7') {
    opentest1();
    currentMillis = millis();
    if ((buttonopentest1state == LOW) && (currentMillis - previousMillis > 8000)) { // wait 8 seconds till showing up button for open test
      button_opentest1();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonopentest1state == HIGH)) //enable touch function to let machine guy start the next step
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {
        my_lcd.Fill_Screen(WHITE);
        drawopentest2();
        currentMillis = millis();
        previousMillis = currentMillis;
        currentpage = '8';
      }
    }
  }

  if (currentpage == '8') {
    opentest2();
    currentMillis = millis();
    if ((buttonopentest2state == LOW) && (currentMillis - previousMillis > 8000)) { // wait 8 seconds till showing up button for open test
      button_opentest2();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonopentest2state == HIGH)) //enable touch function to let machine guy start the next step
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {
        my_lcd.Fill_Screen(WHITE);
        drawhomescreen();
        currentpage = '0';
      }
    }
  }
}

///////////////////////////functions///////////////////////////

void startventilate() { //code for ventilate injectors for fuel rail air evacuation
  uint32_t topLoop = millis();
  if (topLoop - lastBlink >= blinkDuration) {
    lastBlink = topLoop;
    digitalWrite(ledPins[currLed], LOW);  // switch off last injector
    if (++currLed > lastIndex) {
      currLed = 0;
    }
    digitalWrite(ledPins[currLed], HIGH); // turn next injector on
  }
}

void leakcheck() {

  my_lcd.Fill_Screen(WHITE);
  show_string("DICHTHEITSPRUEFUNG!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("KEINE DUESE TROPFT", 10, 100, 2, RED, BLACK, 1);
  show_string("VENTIL SCHLIESSEN", 10, 200, 2, RED, BLACK, 1);
}

void matching(int matchtime) {

  currentMillis = millis();//starts timer for matching

  if (currentMillis - previousMillis <= matchtime) {
    digitalWrite(31, HIGH);
  }
  if (currentMillis - previousMillis <= 2 * matchtime && currentMillis - previousMillis > matchtime ) {
    digitalWrite(31, LOW);
    digitalWrite(33, HIGH);
  }
  if (currentMillis - previousMillis <= 3 * matchtime && currentMillis - previousMillis > 2 * matchtime ) {
    digitalWrite(33, LOW);
    digitalWrite(35, HIGH);
  }
  if (currentMillis - previousMillis <= 4 * matchtime && currentMillis - previousMillis > 3 * matchtime)  {
    digitalWrite(35, LOW);
    digitalWrite(37, HIGH);
  }

  if (currentMillis - previousMillis > 4 * matchtime) {
    digitalWrite(37, LOW);
    currentpage = '4'; // nach matching automatisch auf folgeseite weiterleiten
    drawresults();// nach matching automatisch auf folgeseite weiterleiten
  }
}

void dynamicmatching(int dynamicmatchtime) {
  dynamicmatchstate = 0;
  currentMillis = millis();
  for (int i = 0; i <= 1000; i++) { // dynamic matching takes 1000 pulses, each in length of dynamicmatchtime
    dynamicmatchstate = 1;

    if (currentMillis - previousMillis <= dynamicmatchtime) {
      digitalWrite(31, HIGH);
    }
    if (currentMillis - previousMillis <= 2 * dynamicmatchtime && currentMillis - previousMillis > dynamicmatchtime ) {
      digitalWrite(31, LOW);
      digitalWrite(33, HIGH);
    }
    if (currentMillis - previousMillis <= 3 * dynamicmatchtime && currentMillis - previousMillis > 2 * dynamicmatchtime ) {
      digitalWrite(33, LOW);
      digitalWrite(35, HIGH);
    }
    if (currentMillis - previousMillis <= 4 * dynamicmatchtime && currentMillis - previousMillis > 3 * dynamicmatchtime)  {
      digitalWrite(35, LOW);
      digitalWrite(37, HIGH);
    }


    if (dynamicmatchstate == 0) { // after running the test:
      turnallinjoff();
      currentpage = '6';
      drawdynamicresults();//
    }
  }
}

void opentest1() { // code for test proper injector opening at engine start conditions (8V voltage, 3 Bar pressure, 2.5ms opening pulsewidth)

  uint32_t topLoop = millis();
  if (topLoop - lastopen >= openDuration_opentest1) {
    lastopen = topLoop;
    SoftPWMSetPercent(PWMPins[currPWM], 0);  // switch off last injector
    if (++currPWM > lastPWMIndex) {
      currPWM = 0;
      delay(100); // not very sexy, but works
    }
    SoftPWMSetPercent(PWMPins[currPWM], 10); // set outputpin to 10% of source voltage (dont forget transistor characteristik)

  }
}

void opentest2() { // code for test proper injector opening at full power conditions (13V voltage, 7 Bar pressure, 5ms opening pulsewidth)

  uint32_t topLoop = millis();
  if (topLoop - lastopen >= openDuration_opentest2) {
    lastopen = topLoop;
    SoftPWMSetPercent(PWMPins[currPWM], 0);  // switch off last injector
    if (++currPWM > lastPWMIndex) {
      currPWM = 0;
      delay(100); // not very sexy, but works
    }
    SoftPWMSetPercent(PWMPins[currPWM], 10); // set outputpin to 10% of source voltage (dont forget transistor characteristik)
  }
}


///////////////////////////grafical setup buttons///////////////////////////

void button_leakcheck() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("ALLE DICHT", 100, 435, 3, WHITE, BLACK, 1);
  my_lcd.Set_Draw_color(RED);
  my_lcd.Fill_Rectangle(10, 350, 310, 400);
  show_string("UNDICHT", 100, 365, 3, WHITE, BLACK, 1);
  buttonleakcheckstate = HIGH;
}

void button_ventilate() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
  buttonventilatestate = HIGH;
}

void button_opentest1() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
  buttonopentest1state = HIGH;
}

void button_opentest2() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
  buttonopentest2state = HIGH;
}

///////////////////////////grafical setup pages///////////////////////////

void drawhomescreen()
{
  my_lcd.Set_Draw_color(BLACK);
  show_string("Duesengroesse waehlen!", 10, 11, 2, BLACK, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 50, 310, 100);
  show_string("400 ccm", 100, 65, 3, WHITE, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 150, 310, 200);
  show_string("470 ccm", 100 , 165, 3, WHITE, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 250, 310, 300);
  show_string("600 ccm", 100, 265, 3, WHITE, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 350, 310, 400);
  show_string("900 ccm", 100, 365, 3, WHITE, BLACK, 1);

  buttonleakcheckstate = LOW;
  buttonventilatestate = LOW;
  buttonopentest1state = LOW;
  buttonopentest2state = LOW;
}

void drawventilate() {

  my_lcd.Fill_Screen(WHITE);
  show_string("STARTE PUMPE & EINSTELLEN!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("3,0 BAR", 30, 100, 3, RED, BLACK, 1);
}

void drawmatching() {

  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK PRUEFEN & EINSTELLEN!", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("3,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("...", 10, 150, 2, RED, BLACK, 1);
}

void drawdynamicmatching() {
  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK PRUEFEN & EINSTELLEN!", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("3,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("...", 10, 150, 2, RED, BLACK, 1);
}

void drawopentest1() {
  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK !", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("3,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("Alle DUESEN", 10, 150, 2, RED, BLACK, 1);
  show_string("MUESSEN RICHTIG OEFFNEN", 10, 200, 2, RED, BLACK, 1);
}

void drawopentest2() {
  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK STEIGERN AUF!", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("7,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("Alle DUESEN", 10, 150, 2, RED, BLACK, 1);
  show_string("MUESSEN RICHTIG OEFFNEN", 10, 200, 2, RED, BLACK, 1);
}

void drawresults() { // shows matching reference values for the machine users decision, if tolerance is okay

  my_lcd.Fill_Screen(WHITE);
  show_string("WERTE PRUEFEN!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("MINIMUM:", 30, 100, 3, BLACK, BLACK, 1);
  show_string("20", 180, 100, 3, BLACK,  BLACK, 1); //use arguments for better program
  show_string("MAXIMUM:", 30, 200, 3, BLACK, BLACK, 1);
  show_string("23", 180, 200, 3, BLACK, BLACK, 1);  //use arguments for better program

  //fertig button
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
}

void drawdynamicresults() { // shows matching reference values for the machine users decision, if tolerance is okay

  my_lcd.Fill_Screen(WHITE);
  show_string("WERTE PRUEFEN!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("MINIMUM:", 30, 100, 3, BLACK, BLACK, 1);
  show_string("dymic minimum", 180, 100, 3, BLACK,  BLACK, 1); //use arguments for better program
  show_string("MAXIMUM:", 30, 200, 3, BLACK, BLACK, 1);
  show_string("dyn max", 180, 200, 3, BLACK, BLACK, 1);  //use arguments for better program

  //fertig button
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
}

void turnallinjoff() {
  digitalWrite(31, LOW);
  digitalWrite(33, LOW);
  digitalWrite(35, LOW);
  digitalWrite(37, LOW);
}

Hi guys,

Ive done some further testing. The situation is, that ALL transistors becoming leading state, if just ONE SINGLE transistor is "switched on" by 5V UBE.

So strangely I control 2 or more Transistors with just one Base of one Transistor connected to the arduino.

I think it must be a wiring bug, but I at the moment Im not able to find the bug.
Does anybody see the bug in my wiring?

What about the layout of your wiring - is everything twisted pair with its return wire?

I'd be more worried by the code - you are using SoftPWM library so there's interrupts flying around changing the state of your pins I think.

Hi,
What are the transistors you are using?
Can I suggest you write some simple code that turns your injectors ON and OFF every 250ms.
No fancy PWM, just plain old hard switching to prove your circuit.
Lets check the hardware with some simple code to get started.
Have you got back EMF protection diodes on the injectors?

I am surprised you are not using MOSFETs, in particular devices designed to control injector current.
Google;

injector driver mosfet

Tom... :grinning: :+1: :coffee: :australia:
PS. A circuit diagram would be nice, hand drawn with component label and pin names. Reverse Engineer your project.

are you sure it works 100% with only leds ?
then start thinking on wiring and transistor circuit. you ve mentioned a coil. has it protection? reverse Diode ? ive seen "logic" problems many times without that diode at each coil

Thanks Tom! The Mosfet Driver was exatly what im searching for.

I replaced the Transistors by this Mosfet drivers, now the basic function are working.
To prevent failures because of induction of the coils Ive used Diodes.

Two things are left, I really would appreciate it if you guys also have good Input.
First, i want to reduce the Injector Voltage at "void opentest1" to 8V. The injector should be switched on with 8V Voltage, then switched off etc.
The PWM Ports of my MEGA2560 are all used by the TFT Touch. My first Idea was, to realize the Voltage drop by using the PWM library. ATM the Voltage is still 12V without drop, also if i use 10% PWM Duty cycle.

Do you have an idea, if the error occurs bcs. of mistakes codewise or bcs. of hardwarewise problems?

Second, Im willed to switch 4 injectors on for 3 milliseconds by function "void dynamicmatching". The injectors should be switched on one after each after. For better understanding, switch injectors on like:

Injector 1: 0-3ms
Injector 2: 3-6ms
...
Injector 4: 9-12ms

This procedure should be runned 1000 times, then it should stop. Running the procedure one time means every single injector is switched on one time.

The current code works, but works very poorly, means that the timing for opening and closing is very inaccurate. It seems like the Arduino is not fast enough to open and close the injectors at the correct point of time. The serial Port also shows, that the timing is incorrect.

Do you see any mistakes at the code, which lead to this error?

#include <SoftPWM.h> //library for using non pwm pin as pwm pins
#include <SoftPWM_timer.h> //library for using non pwm pin as pwm pins
#include "TouchScreen.h" //touch library
#include "LCDWIKI_GUI.h" //Core graphics library
#include "LCDWIKI_KBV.h" //Hardware-specific library

LCDWIKI_KBV my_lcd(ILI9486, A3, A2, A1, A0, A4); //model,cs,cd,wr,rd,reset

// making digital pins to pwm pins and declaring them
#define PIN1_PWM    31
#define PIN2_PWM    33
#define PIN3_PWM    35
#define PIN4_PWM    37
//snippet for turn on injectors repeatedly with lower voltage (PWM)
const uint8_t PWMPins[4] = { PIN1_PWM, PIN2_PWM, PIN3_PWM, PIN4_PWM};
const uint8_t lastPWMIndex = sizeof(PWMPins) - 1;
const uint16_t openDuration_opentest1 = 250; //time period for void open test 1
const uint16_t openDuration_opentest2 = 500;  //time period for open test 2
uint32_t lastopen;
uint8_t currPWM = lastPWMIndex;

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//touch sensitivity for X
#define TS_MINX 906
#define TS_MAXX 116

//touch sensitivity for Y
#define TS_MINY 92
#define TS_MAXY 952

#define MINPRESSURE 10
#define MAXPRESSURE 1000

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

// declaration for grafics
void show_string(uint8_t *str, int16_t x, int16_t y, uint8_t csize, uint16_t fc, uint16_t bc, boolean mode)
{
  my_lcd.Set_Text_Mode(mode);
  my_lcd.Set_Text_Size(csize);
  my_lcd.Set_Text_colour(fc);
  my_lcd.Set_Text_Back_colour(bc);
  my_lcd.Print_String(str, x, y);
}

boolean is_pressed(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t px, int16_t py)
{
  if ((px > x1 && px < x2) && (py > y1 && py < y2))
  {
    return true;
  }
  else
  {
    return false;
  }
}

char currentpage;
unsigned long previousMillis;
unsigned long currentMillis;
unsigned long ventilateMillis;

// snippet for ventilation, putting on one injector after another repeatedly
const uint8_t ledPins[4] = { 31, 33, 35, 37 };
const uint8_t lastIndex = sizeof(ledPins) - 1;
const uint16_t blinkDuration = 200; //time period for void ventilation
uint32_t lastBlink;
uint8_t currLed = lastIndex;
//declarate matching parameters
int matchtime = 0;
int dynamicmatchtime = 0;
int vmax = 0;
int vmin = 0;
int vmindyn = 0;
int vmaxdyn = 0;

int buttonleakcheckstate = LOW;
int buttonventilatestate = LOW;
int buttonopentest1state = LOW;
int buttonopentest2state = LOW;
//int dynamicmatchstate = 0;
int dynamicmatchruns = 0;
int previousdynamicmatchruns = 0;

void setup() {
  my_lcd.Init_LCD();
  my_lcd.Fill_Screen(WHITE);
  drawhomescreen();
  currentpage = '0';

  pinMode(31, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(37, OUTPUT);

SoftPWMBegin(); // starting pwm functionality of non pwm pins

  for (auto pin : ledPins) { // functionality for ventilation function
    pinMode(pin, OUTPUT);
  }
  for (auto pin : PWMPins) { // functionality for ventilation function
    pinMode(pin, OUTPUT);
  }

  pinMode(31, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(37, OUTPUT);

  Serial.begin(115200);

  Serial.println("hallo");


}

void loop() {
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  ////////////// general functionality of pages ////////////////////////////////

  if (currentpage == '0') {

    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);

      if (is_pressed(10, 50, 310, 100, p.x, p.y)) //400 ccm clicked
      {
        matchtime = 6000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 150, 310, 200, p.x, p.y)) //470 ccm clicked
      {
        matchtime = 5000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 250, 310, 300, p.x, p.y)) //600 ccm clicked
      {
        matchtime = 4000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 30ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 350, 310, 400, p.x, p.y)) //900 ccm clicked
      {
        matchtime = 3000;         // 5s static matching time for this type
        dynamicmatchtime = 3; // 3ms danymic matching time
        vmin = 20;  // min static volume for this type
        vmax = 23;  // max static volumen for this type
        vmindyn = 5; //min dyn. volumen for this type
        vmaxdyn = 8; //max dyn. volumen for this type
        currentpage = '1';
        drawventilate(); // display next page
        currentMillis = millis();
        ventilateMillis = currentMillis;
      }
    }
  }

  if (currentpage == '1') {
    startventilate();
    currentMillis = millis();

    if ((buttonventilatestate == LOW) && (currentMillis - ventilateMillis > 5000)) {
      button_ventilate();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonventilatestate == HIGH))
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {
        digitalWrite(31, LOW);
        digitalWrite(33, LOW);
        digitalWrite(35, LOW);
        digitalWrite(37, LOW);
        currentpage = '2';
        leakcheck(); // display screen "start leak check"
        currentMillis = millis();
        previousMillis = currentMillis;
      }
    }
  }

  if (currentpage == '2') {
    currentMillis = millis();

    if ((buttonleakcheckstate == LOW) && (currentMillis - previousMillis > 8000)) {
      button_leakcheck();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonleakcheckstate == HIGH))
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //leak check ok button clicked
      {
        currentpage = '3';
        drawmatching();
        currentMillis = millis();
        previousMillis = currentMillis;
      }

      if (is_pressed(10, 350, 310, 400, p.x, p.y)) //leak check Nok button clicked
      {
        my_lcd.Fill_Screen(WHITE);
        drawhomescreen();
        currentpage = '0';
      }
    }
  }

  if (currentpage == '3') {
    matching(matchtime);
  }

  if (currentpage == '4') {
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {

        my_lcd.Fill_Screen(WHITE);
        drawdynamicmatching();
        dynamicmatchruns = 0;
        previousdynamicmatchruns = 0;
        currentMillis = millis();
        previousMillis = currentMillis;
        currentpage = '5';

      }
    }
  }

  if (currentpage == '5') {
    dynamicmatching(dynamicmatchtime);
  }

  if (currentpage == '6') { // page for evalutating dynamic match results
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {

        my_lcd.Fill_Screen(WHITE);
        drawopentest1();
        currentMillis = millis();
        previousMillis = currentMillis;
        currentpage = '7';

      }
    }
  }


  if (currentpage == '7') {
    opentest1();
    currentMillis = millis();
    if ((buttonopentest1state == LOW) && (currentMillis - previousMillis > 8000)) { // wait 8 seconds till showing up button for open test
      button_opentest1();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonopentest1state == HIGH)) //enable touch function to let machine guy start the next step
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {
        currentpage = '8';
        turnallinjoff();
        my_lcd.Fill_Screen(WHITE);
        drawopentest2();
        currentMillis = millis();
        previousMillis = currentMillis;
        
      }
    }
  }

  if (currentpage == '8') {
    opentest2();
    currentMillis = millis();
    if ((buttonopentest2state == LOW) && (currentMillis - previousMillis > 8000)) { // wait 8 seconds till showing up button for open test
      button_opentest2();
    }

    if ((p.z > MINPRESSURE && p.z < MAXPRESSURE) && (buttonopentest2state == HIGH)) //enable touch function to let machine guy start the next step
    {
      p.x = map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
      p.y = map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
      if (is_pressed(10, 420, 310, 470, p.x, p.y)) //fertig button clicked
      {
        currentpage = '0';
        turnallinjoff();
        my_lcd.Fill_Screen(WHITE);
        drawhomescreen();
        
      }
    }
  }
}

///////////////////////////functions///////////////////////////

void startventilate() { //code for ventilate injectors for fuel rail air evacuation
  uint32_t topLoop = millis();
  if (topLoop - lastBlink >= blinkDuration) {
    lastBlink = topLoop;
    digitalWrite(ledPins[currLed], LOW);  // switch off last injector
    if (++currLed > lastIndex) {
      currLed = 0;
    }
    digitalWrite(ledPins[currLed], HIGH); // turn next injector on
  }
}

void leakcheck() {

  my_lcd.Fill_Screen(WHITE);
  show_string("DICHTHEITSPRUEFUNG!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("KEINE DUESE TROPFT", 10, 100, 2, RED, BLACK, 1);
  show_string("VENTIL SCHLIESSEN", 10, 200, 2, RED, BLACK, 1);
}

void matching(int matchtime) {

  currentMillis = millis();//starts timer for matching

  if (currentMillis - previousMillis <= matchtime) {
    digitalWrite(31, HIGH);
  }
  if (currentMillis - previousMillis <= 2 * matchtime && currentMillis - previousMillis > matchtime ) {
    digitalWrite(31, LOW);
    digitalWrite(33, HIGH);
  }
  if (currentMillis - previousMillis <= 3 * matchtime && currentMillis - previousMillis > 2 * matchtime ) {
    digitalWrite(33, LOW);
    digitalWrite(35, HIGH);
  }
  if (currentMillis - previousMillis <= 4 * matchtime && currentMillis - previousMillis > 3 * matchtime)  {
    digitalWrite(35, LOW);
    digitalWrite(37, HIGH);
  }

  if (currentMillis - previousMillis > 4 * matchtime) {
    digitalWrite(37, LOW);
    currentpage = '4'; // nach matching automatisch auf folgeseite weiterleiten
    drawresults();// nach matching automatisch auf folgeseite weiterleiten
  }
}

void dynamicmatching(int dynamicmatchtime) {


  if (dynamicmatchruns <= 1000) {
    previousdynamicmatchruns = dynamicmatchruns;
    currentMillis = millis();
    Serial.println("lauf nummer = ");
    Serial.println(dynamicmatchruns);

    if (currentMillis - previousMillis <= dynamicmatchtime) {
      digitalWrite(31, HIGH);
      Serial.println("Düse 1 an");
    }
    if (currentMillis - previousMillis <= 2 * dynamicmatchtime && currentMillis - previousMillis > dynamicmatchtime ) {
      digitalWrite(31, LOW);
      digitalWrite(33, HIGH);
      Serial.println("Düse 2 an");

    }
    if (currentMillis - previousMillis <= 3 * dynamicmatchtime && currentMillis - previousMillis > 2 * dynamicmatchtime ) {
      digitalWrite(33, LOW);
      digitalWrite(35, HIGH);
       Serial.println("Düse 3 an");
    }
    if (currentMillis - previousMillis <= 4 * dynamicmatchtime && currentMillis - previousMillis > 3 * dynamicmatchtime)  {
      digitalWrite(35, LOW);
      digitalWrite(37, HIGH);
      Serial.println("Düse 4 an");
    }
    if (currentMillis - previousMillis > 4 * dynamicmatchtime) {
      digitalWrite(37, LOW);
      Serial.println(">4 erreicht, alle düsen aus");

      dynamicmatchruns = previousdynamicmatchruns + 1;
      Serial.println("pm +1 erhöt");
      previousMillis = currentMillis;
    }
  }

  if (dynamicmatchruns > 1000) {
    Serial.println("dynamic beendet");
    turnallinjoff();
    currentpage = '6';
    drawdynamicresults();
  }
}





void opentest1() { // code for test proper injector opening at engine start conditions (8V voltage, 3 Bar pressure, 2.5ms opening pulsewidth)

  uint32_t topLoop = millis();
  if (topLoop - lastopen >= openDuration_opentest1) {
    lastopen = topLoop;
   SoftPWMSetPercent(PWMPins[currPWM], 0);  // switch off last injector
   
    if (++currPWM > lastPWMIndex) {
      currPWM = 0;
      delay(100); // not very sexy, but works
    }
    SoftPWMSetPercent(PWMPins[currPWM], 10); // set outputpin to 10% of source voltage (dont forget transistor characteristik)

  }
}

void opentest2() { // code for test proper injector opening at full power conditions (13V voltage, 7 Bar pressure, 5ms opening pulsewidth)

  uint32_t topLoop = millis();
  if (topLoop - lastopen >= openDuration_opentest2) {
    lastopen = topLoop;
    SoftPWMSetPercent(PWMPins[currPWM], 0);  // switch off last injector
    if (++currPWM > lastPWMIndex) {
      currPWM = 0;
      delay(100); // not very sexy, but works
    }
    SoftPWMSetPercent(PWMPins[currPWM], 10); // set outputpin to 10% of source voltage (dont forget transistor characteristik)
  }
}


///////////////////////////grafical setup buttons///////////////////////////

void button_leakcheck() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("ALLE DICHT", 100, 435, 3, WHITE, BLACK, 1);
  my_lcd.Set_Draw_color(RED);
  my_lcd.Fill_Rectangle(10, 350, 310, 400);
  show_string("UNDICHT", 100, 365, 3, WHITE, BLACK, 1);
  buttonleakcheckstate = HIGH;
}

void button_ventilate() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
  buttonventilatestate = HIGH;
}

void button_opentest1() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
  buttonopentest1state = HIGH;
}

void button_opentest2() {
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
  buttonopentest2state = HIGH;
}

///////////////////////////grafical setup pages///////////////////////////

void drawhomescreen()
{
  my_lcd.Set_Draw_color(BLACK);
  show_string("Duesengroesse waehlen!", 10, 11, 2, BLACK, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 50, 310, 100);
  show_string("400 ccm", 100, 65, 3, WHITE, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 150, 310, 200);
  show_string("470 ccm", 100 , 165, 3, WHITE, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 250, 310, 300);
  show_string("600 ccm", 100, 265, 3, WHITE, BLACK, 1);

  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 350, 310, 400);
  show_string("900 ccm", 100, 365, 3, WHITE, BLACK, 1);

  buttonleakcheckstate = LOW;
  buttonventilatestate = LOW;
  buttonopentest1state = LOW;
  buttonopentest2state = LOW;
  dynamicmatchruns = 0;
}

void drawventilate() {

  my_lcd.Fill_Screen(WHITE);
  show_string("STARTE PUMPE & EINSTELLEN!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("3,0 BAR", 30, 100, 3, RED, BLACK, 1);
}

void drawmatching() {

  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK PRUEFEN & EINSTELLEN!", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("3,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("...", 10, 150, 2, RED, BLACK, 1);
}

void drawdynamicmatching() {
  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK PRUEFEN & EINSTELLEN!", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("3,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("...", 10, 150, 2, RED, BLACK, 1);
}

void drawopentest1() {
  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK !", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("3,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("Alle DUESEN", 10, 150, 2, RED, BLACK, 1);
  show_string("MUESSEN RICHTIG OEFFNEN", 10, 200, 2, RED, BLACK, 1);
}

void drawopentest2() {
  my_lcd.Fill_Screen(WHITE);
  show_string("DRUCK STEIGERN AUF!", 10, 10, 2, BLACK, BLACK, 1); // ggf ladezeichen o.ä. einfügen, so das konstante arbeit klar wird
  show_string("7,0 BAR", 10, 100, 2, RED, BLACK, 1);
  show_string("Alle DUESEN", 10, 150, 2, RED, BLACK, 1);
  show_string("MUESSEN RICHTIG OEFFNEN", 10, 200, 2, RED, BLACK, 1);

  show_string("ERGEBNISSE NOTIEREN", 10, 200, 2, BLACK, BLACK, 1);
  show_string("PUMPE ABSTELLEN", 10, 200, 2, RED, BLACK, 1);
}

void drawresults() { // shows matching reference values for the machine users decision, if tolerance is okay

  my_lcd.Fill_Screen(WHITE);
  show_string("WERTE PRUEFEN & EINTRAGEN!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("MINIMUM:", 30, 100, 3, BLACK, BLACK, 1);
  show_string("20", 180, 100, 3, BLACK,  BLACK, 1); //use arguments for better program
  show_string("MAXIMUM:", 30, 200, 3, BLACK, BLACK, 1);
  show_string("23", 180, 200, 3, BLACK, BLACK, 1);  //use arguments for better program
  show_string("NACH EINTRAGEN:", 30, 250, 2, BLACK, BLACK, 1);
  show_string("VENTIL OEFFNEN", 30, 300, 2, BLACK, BLACK, 1);
  show_string("ROEHREN LEEREN", 30, 350, 2, BLACK, BLACK, 1);
  show_string("VENTIL SCHLIESSEN", 30, 400, 2, BLACK, BLACK, 1);


  //fertig button
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
}

void drawdynamicresults() { // shows matching reference values for the machine users decision, if tolerance is okay

  my_lcd.Fill_Screen(WHITE);
  show_string("WERTE PRUEFEN UND EINTRAGEN!", 10, 10, 2, BLACK, BLACK, 1);
  show_string("MINIMUM:", 30, 100, 3, BLACK, BLACK, 1);
  show_string("10", 180, 100, 3, BLACK,  BLACK, 1); //use arguments for better program
  show_string("MAXIMUM:", 30, 200, 3, BLACK, BLACK, 1);
  show_string("14", 180, 200, 3, BLACK, BLACK, 1);  //use arguments for better program
  show_string("NACH EINTRAGEN:", 30, 250, 2, BLACK, BLACK, 1);
  show_string("VENTIL OEFFNEN", 30, 300, 2, BLACK, BLACK, 1);
  show_string("ROEHREN LEEREN", 30, 350, 2, BLACK, BLACK, 1);
  show_string("VENTIL SCHLIESSEN", 30, 400, 2, BLACK, BLACK, 1);



  //fertig button
  my_lcd.Set_Draw_color(BLUE);
  my_lcd.Fill_Rectangle(10, 420, 310, 470);
  show_string("FERTIG", 100, 435, 3, WHITE, BLACK, 1);
}

void turnallinjoff() {
  digitalWrite(31, LOW);
  digitalWrite(33, LOW);
  digitalWrite(35, LOW);
  digitalWrite(37, LOW);
}

The 16MHz Atmega is fast enough. Your code is causing loop() to take to long to cycle. You have two options, go faster to compensate for the code bloat or refine your code to be more efficient and event-driven. No doubt, moving up in frequency will give you some headroom, but going from an 8-bit to a 32-bit device will create some headaches in variable typing (int = 16-bit vs int = 32-bit)

When I'm doing something like this, I take the time to profile every block of code using micros() and shipping a reference "A/B/C/D ... Z) out the serial port for logging. I can then pop that into Excel and build a reference to where time is being used, perhaps excessively.

Also, get rid of the GLCD code and touch ... put it on another uC (perfect for a mini) and message back 'n forth over serial or I2C or SPI ... you could probably keep stuff on the Mega and use an RTOS but that really complicates dev and I do not think it is warranted here.

This is not good use of timing:

void matching(int matchtime) {

Pick an I/O port on the Mega and dedicate that to your injectors. Then you can bit-bang the port efficiently.
https://www.arduino.cc/en/Reference/PortManipulation

Using direct port manipulation, you should be able to handle the On/Off state of all injectors with one function. Just create a 2D matrix for all the states required and index what you want to control at that moment in time.

Good luck,

Ray

Thanks for your answer Ray.

Your answer is very contentfull, thanks for that. Ive got a lot left to learn!
At the moment im searching for a quick way to test the inejctors ASAP (Project should be finished weeks ago :x )
I really would like to use these one processor for the screen functionalty and also for controlling
the transistors. This is a example usecase for an arduino, isnt it?

Does the port registration really solves the issue? Like Ive undestood Reg helps out, if we need a time solution on microsecondsbase, in our case we just need it on millisecond-base (+-0,1 ms is enough). So for my understanding, the basic function like digitalWrite() etc. should be enough for our usecase.

I think the reason for the bag timing is - like u mentioned - my inefficient code.
What is in your opinion the smartest way to solve the "coat bloat" and transfer it into an event-driven code?

Im really excited about your answer.

consider

then matching() is called:


void matching(int matchtime) {

  currentMillis = millis();//starts timer for matching

  if (currentMillis - previousMillis <= matchtime) {
    digitalWrite(31, HIGH);
  }
  if (currentMillis - previousMillis <= 2 * matchtime && currentMillis - previousMillis > matchtime ) {
    digitalWrite(31, LOW);
    digitalWrite(33, HIGH);
  }
  if (currentMillis - previousMillis <= 3 * matchtime && currentMillis - previousMillis > 2 * matchtime ) {
    digitalWrite(33, LOW);
    digitalWrite(35, HIGH);
  }
  if (currentMillis - previousMillis <= 4 * matchtime && currentMillis - previousMillis > 3 * matchtime)  {
    digitalWrite(35, LOW);
    digitalWrite(37, HIGH);
  }

  if (currentMillis - previousMillis > 4 * matchtime) {
    digitalWrite(37, LOW);
    currentpage = '4'; // nach matching automatisch auf folgeseite weiterleiten
    drawresults();// nach matching automatisch auf folgeseite weiterleiten
  }
}

But then there is considerable time expended after matching() back in the the if(currentpage == ...) comparisons.

Ater making a selection on routine, you need to stay in that routine until the routine completes, then back in the main program post "test completed" on the display and any results that the operator needs ... do not print from within test functions ... log to highspeed serial or status to RAM-based array ... all I/O except injector control must be minimized!

the oid matching(int matchtime) {} function should be rewritten as a while loop until the test completes.

For lengthy tests that may need emergency pre-completion termination, an I/O pin signal must exist so you can do while in a compound conditional: that is while test time has not expired and emergency button has not been pressed.

Backup everything you currently have to a zip!!
Proceed with one test rewrite, test performance & timing to ensure that I am not full of .... err, not leading you astray :upside_down_face:

Good luck,

Ray

PS: for future projects, always mentally separate I/O from any human input/output concerns. Always measure the value of LCD/touch against overall uC critical timing and uC capability in SRAM, flash, and I/O. Were you to separate functionality, one uC would sends touchscreen commands to the other dedicated injector test engine code where timing and logging info could be collected.

Future reference, an old project for testing aircraft engines:
https://www.stm32duino.com/viewtopic.php?t=959

Dear Ray,

many thanks for your support!! You really helped me out with your knowledge :slight_smile:

Writing the code with while() instead of if() and using Port Registers are the solution!

best regards,
Gustav

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.