Go Down

Topic: advice needed for arduino as diesel injection brain... (Read 7906 times) previous topic - next topic

cyclegadget


PeterH is correct, I did not write the sketch properly. I need a signature under my avatar that says "Warning Novice on board!" .

I rewrote the return sketch, I think it is correct this time. Sorry for the mistake I made earlier.

Code: [Select]
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int DonesAnswer = 0;           // variable to pass "done" to         

long previousMillis = 0;        // will store last time LED was updated

long interval = 1200;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);   
  Serial.begin(9600); 
}

void loop()
{

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval)
  {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

   DonesAnswer = whatdonedoes();   // transfer "done" to DonesAnswer using the function

    Serial.print("done = ");
    Serial.println(DonesAnswer);

    digitalWrite(ledPin, DonesAnswer);
  }
}

////////////////////////////////function with a return called done//////////
int whatdonedoes()
{
  static int done = 0;  //set done to static int

  // if the LED is off turn it on and vice-versa:
  if (done == 1)
    done = 0;
  else
    done = 1;

  return done;
}
Good links: Eagle tutorial= http://www.youtube.com/playlist?list=PLDE1858BD83D19C70
General Arduion tutorials = http://tronixstuff.wordpress.com
http://www.gammon.com.au/forum/bbshowpost.php?bbtopic_id=123

japie

Nice signature ;-)

However I got the point about the done in this case. (in bash I use it to halt or continue script so this case was new to me)

I did some test with the program, added several "timestamps" and at the end of the loop printed them all. (to prevent serial prints to slow down things)
Very disturbing is the fact that reading analog and writing to pwm takes over 200uS, if this delay happens at the wrong point my injection timing will be 5-10 degree to late or even worse if that happens while injecting it can mean 20-30% more diesel which melts my pistons.
400HP+ with a 4 cylinder 2.0l diesel is a bit on the edge, with 200cc diesel per 1000 injections it will run around 1000 degree Celsius and the pistons will melt at 1100... (with 160cc 800 degree)

To wrap it all together; running a loop and take action based on interrupt created flags inside that loop isn't gonna work since injection moment and duration are both time critical give or take 10uS. (20 total)

So back to my first plan (disapproved by every coder around the world ;)

A loop that checks and set stuff, throttle, pump pressure, idle, rpm limiter etc.
Interrupts that open injector, wait injection time and close it. (during that time the loop is stalled but who cares)
connect timer to throttle so advance is manually controlled. (0 at idle, -45 at full load)
Main thing is that the time critical functions (opening and closing injectors) are interrupt driven, all other stuff can have some delay the only result of that can be that throttle feels a bit sloppy at high rpm (when times between interrupts get shorter) but in that case I was all ready holding on to my wheel and praying...

PeterH


Interrupts that open injector, wait injection time and close it. (during that time the loop is stalled but who cares)


As well as being ugly, I'm not at all convinced that you will get it to work. What would IMO be far better would be to use the timer interrupt to start the injection and at that time configure a timer to trigger another interrupt when the injection needs to end. This way the real time part of your code runs with minimal latency and does not lock the processor up for the duration of the injection, and the background processing in loop() can run and do whatever it needs to. Just ensure that you don't do anything that disables interrupts.
I only provide help via the forum - please do not contact me for private consultancy.

japie

#48
Feb 17, 2013, 07:37 pm Last Edit: Feb 17, 2013, 07:38 pm by japie Reason: 1
I have been searching for some solution to replace the delay and found http://playground.arduino.cc/Code/Timer1

Was thinking about the interrupt opening the injector and starting a timer, the timer does the closing so I suppose you where thinking the same.

shot in the dark:

Code: [Select]
attachInterrupt(18, Inject1, RISING);

void Inject1()
{
 // calculate how many uS 180 degrees last
 TimeFrame = (micros() - TimeOld);
 TimeOld = TimeFrame;
 // open injector1
 digitalWrite(inj1,HIGH);
 // start timer1
 Timer1.initialize(ThrottleDuration);
 Timer1.attachInterrupt(Close1);
}

void Close1()
{
 // close injector1
 digitalWrite(inj1, LOW);
}


Only I don't think I can share the timer between all 4 injectors but since I use the mega it seems I have 3 extra ones so 1,3,4 and 5 are all 16 bit.
From the docs timer0 is used for millis, micros, delay and PWM pin13 (my pump pressure output) so I won't touch it.

Does something like above work or am I ready for mental care? ;-)

PeterH


Only I don't think I can share the timer between all 4 injectors


If you have an even firing engine then you could just generate the interrupt at the total injection frequency rather than the per-cylinder frequency, and cycle through the cylinders in the appropriate order.

I've missed/forgotten how you're going to synchronise the injection with the engine physical position. Do you already have the crank position and engine phase sensing sorted out? Presumably you'll have some sort of phase locked loop tracking where (you think) the engine is.
I only provide help via the forum - please do not contact me for private consultancy.

cyclegadget


@japie

  Could you post the code that you used to find this
Quote
Very disturbing is the fact that reading analog and writing to pwm takes over 200uS,


I am not saying your wrong but, I can bench mark the Uno, Teensy 3.0, and the Due for comparison. I also have a Maple clone but, it is not as easy for me to put it to good use.
Good links: Eagle tutorial= http://www.youtube.com/playlist?list=PLDE1858BD83D19C70
General Arduion tutorials = http://tronixstuff.wordpress.com
http://www.gammon.com.au/forum/bbshowpost.php?bbtopic_id=123

japie

With some clever coding and dividing those 2 actions the times can probably be brought down but the main issue is that the time critical stuff is done in the loop, it should be real time...

The injection moment is in sync with the engine trough an alternator, I have a pcb with 4 IR transmitters on it and one with 4 receivers, between those there is a rotating plate with a little hole so at every TBP one of the receivers gets a pulse.
The casing with the PCB's in it can be attached to the throttle to create more advance when giving more throttle. (the above system has been used in the past by me and works flawless)
Nothing fancy, if receiver1 gets a pulse injector1 has to spray.

PeterH


The injection moment is in sync with the engine trough an alternator, I have a pcb with 4 IR transmitters on it and one with 4 receivers, between those there is a rotating plate with a little hole so at every TBP one of the receivers gets a pulse.


I don't know what a TBP is. When you say alternator, do you mean the alternator that provides electrical power for the vehicle? How is that connected to the crank?
I only provide help via the forum - please do not contact me for private consultancy.

afremont


For sure there are only 2 External Interrupts.
But almost every pin also supports PCINT, whichNick Gammon has a great page on and even shows them as being a little faster:
http://www.gammon.com.au/forum/?id=11488


Nice link, thanks.  Just nit-picking, but I believe that Timer1 Capture is also an external interrupt pin, making for a total of 3.
Experience, it's what you get when you were expecting something else.

japie

@cyclegadget

I did timings by adding stuff between lines like:
Code: [Select]
int readthrottle = micros();
and at the end of the loop print all of them in one line, substracting manually gave me the readings...

@PeterH

Sorry 4 misleading you, I am pretty busy with labour so most of the time I do computer stuff early in the morning before going to work.
I meant TDP or TDC: Top Dead Center, when the piston is in it's most uprising/compression point.
Also I don't mean alternator but distributor.
So I can give an electronical pulse at exactly the moment I want to inject, in the past I used almost the same setup  with an NE555 as timer for injection duration but since I got involved with the arduino while building a data logger I thought it was a nice idea to use it for injecting.
In my old setup the distributor ;-) was connected to the throttle so when giving more throttle the timing would advance from -10 to -50 degree TDP.

Actually there is nothing wrong with that, in my current conventional plunger Bosch A-pump I modified the plungers by grinding the top in an angle and the helix flat so when giving more throttle injection moment will advance. (normally the top of the plunger is flat, halfway down there is a groove in an angle (the helix) that is connected via another groove to the top, when the plunger moves upwards the helix will pass a hole and bleeds fuel from the top so at that point the injection stops. Since that helix is under an angle you can turn the plunger so the effective stroke of the plunger is extended and therefore delivering more fuel. http://transportation.centennialcollege.ca/oduffy/fuels/HD%20fuels%203/inline.pdf)

@afremont

The other timers also all connect to a pin so that would mean they are not useable.
When looking at the example code it looks like the timers can be used without using the pin attached to it, no clue.
Also no clue how to use the other 3...

If I can't find out I will use a microsecond delay, bad coding leaving the arduino doing a lot of nothing but see no reason why it should not work.

japie

#55
Feb 22, 2013, 04:25 pm Last Edit: Feb 22, 2013, 06:30 pm by japie Reason: 1
Hello there, got the basic timer code working:
Code: [Select]

#include "TimerOne.h"
#include "TimerThree.h"

int ledPin = 13;
volatile int state = LOW;
volatile int InjectionCycle1  = false;

void setup()
{
  pinMode(ledPin, OUTPUT);
  attachInterrupt(0, Inject1, RISING); // interrupt 0 = pin 2
  Timer1.initialize(1000000);
  Timer1.stop(); //stop the counter
  Timer1.disablePwm(9); // disables PWM on pin 9
  Timer1.disablePwm(10); // disables PWM on pin 10
  Serial.begin(9600);
}

void loop()
{
}

void Inject1()
{
  if (InjectionCycle1 == false)
  {
    Serial.print("start injection cycle: ");
    Serial.println (millis());
    InjectionCycle1 = true;
    Timer1.setPeriod(1000000);
    Timer1.attachInterrupt(OpenInjector1);
  }
}

void OpenInjector1()
{
  if (InjectionCycle1 == true)
  {
    Serial.print("open injector: ");
    Serial.println (millis());
    digitalWrite(ledPin, HIGH);
    Timer1.stop();
    Timer1.detachInterrupt();
    Timer1.setPeriod(2000000);
    Timer1.attachInterrupt(CloseInjector1);
  }
}

void CloseInjector1()
{
  if (InjectionCycle1 == true)
  {
    Serial.print("close injector: ");
    Serial.println (millis());
    Serial.println ("");
    digitalWrite(ledPin, LOW);
    InjectionCycle1 = false;
    Timer1.stop();
    Timer1.detachInterrupt();
  }
}


Tested this and it works as expected, next step integrate all other stuff, will port when I have it complete.
In this setup the timer replace delay. (and is not stalling the loop like delay)

edited since in first instance I used Timer1 and Timer3 both for both delays:
Using one timer for the cycle works also good so I can use Timer1 for cylinders 1 and 4 and Timer3 for cylinders 2 and 3.
Since the firing order is 1-3-4-2 there is 180 crank degree extra time between interrupt firing cycles, better would be a per cylinder dedicated timer but rewriting the Timer1 code for the extra timers on the mega is out off my league...

japie

Finished the total code for the injection system based on 2 timers.
Included idle revving, soft rpm limit for over-revving and hard rpm limit in case of driveline breakage.

cyclegadget


Japie, where did you download the timerone and timerthree libraries?

I was wanting to do some testing with your code but, I think maybe I am missing the correct library.

I am glad you have been sticking with your project and making it work!
Good links: Eagle tutorial= http://www.youtube.com/playlist?list=PLDE1858BD83D19C70
General Arduion tutorials = http://tronixstuff.wordpress.com
http://www.gammon.com.au/forum/bbshowpost.php?bbtopic_id=123

cyclegadget


Also, I want to say that you should speed up your serial baud rate to 115,200, which is the maximum that the IDE can use. If you have a terminal program, you maybe able to choose a much higher rate. Serial communication can really hurt the performance of your sketch. I will make a sketch to show you the difference. I will post it here soon.
Good links: Eagle tutorial= http://www.youtube.com/playlist?list=PLDE1858BD83D19C70
General Arduion tutorials = http://tronixstuff.wordpress.com
http://www.gammon.com.au/forum/bbshowpost.php?bbtopic_id=123

cyclegadget

Test code using 9600 baud:
Code: [Select]
int ledPin = 13;

//variables to keep track of time of injection code////
unsigned long time1 = 0;
unsigned long time2 = 0;


void setup()
{
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.begin(9600);
}

void loop()
{

  digitalWrite(ledPin, HIGH);
  time1 = micros();
  Serial.print("light the LED for all to see! ");
  Serial.println(time1);

  Serial.print("Turn off the LED it does not need to be ");
  digitalWrite(ledPin, LOW);
  time2 = micros();
  Serial.println(time2);

  Serial.print("total time = ");
  Serial.print(time2 - time1);
  Serial.println("micros");
  delay(5000); 
}

Typical output in micros():
Code: [Select]
light the LED for all to see! 35358256
Turn off the LED it does not need to be 35373908
total time = 15652micros


Using 115200 baud:
Code: [Select]
light the LED for all to see! 35029036
Turn off the LED it does not need to be 35030356
total time = 1320micros


Removing all but total time print, code:
Code: [Select]
int ledPin = 13;

//variables to keep track of time of injection code////
unsigned long time1 = 0;
unsigned long time2 = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.begin(115200);
}

void loop()
{
  digitalWrite(ledPin, HIGH);
  time1 = micros();

  digitalWrite(ledPin, LOW);
  time2 = micros();

  Serial.print("micros = ");
  Serial.println(time2 - time1);

  delay(5000); 
}



results:
Quote
micros = 12
micros = 12
micros = 8
micros = 8
micros = 8

Good links: Eagle tutorial= http://www.youtube.com/playlist?list=PLDE1858BD83D19C70
General Arduion tutorials = http://tronixstuff.wordpress.com
http://www.gammon.com.au/forum/bbshowpost.php?bbtopic_id=123

Go Up