Automotive related project

Hi guys.

My goal is to capture internal cylinder pressure in function of cranckshaft angle of an engine in the work stroke.

I am having trouble here, and i am hoping for your help…for now i will try to explain what i have done with the least words.

Resuming the automotive engineering part talk, what i have to do is:

1- Start measuring 50 degrees cranckshaft before Top Dead Center (TDC) in work stroke;

2- Find a way to detect TDC and corresponding pressure;

3- Continue measuring pressure values after TDC during some degree interval till finish signal capture.

For the hardware i have the following:

1- An aftermarket pressure sensor in combustion chamber (0-250 Bar to 0-5V output corresponding to 0-1023 ADC);

2- Inductive pick up sensor with an LM393 comparator circuit to convert sine to square wave to arduino;

3- Two teeth ferromagnetic wheel atached to cranckshaft like the one in atached file.

The function of the arduino board/sketch is:

1- Detect pulses from the teeth and in function of it, start signal capture, detect TDC and finish the signal capture.

2- Save the measured values and after a determined amount of captures print values in serial monitor.

In more detail i will try to explain the sketch i wrote bellow, and what its various sections do. I have comments in the sketch too.

ISR routine : What it does is just detect the changing pulses (this are 4 per turn, since there are 2 teeth) and increase two counters inside it and save time stamp with micros function.

Section 1: Waits for 24 pulses, or 6 cranckshaft turns for engine speed stabilization.

Section 2: Here, after more 4 pulses, and corresponding time stamp captures, it calculates each
teeth duration (teeth placed before TDC is smaller than teeth at TDC).

Section 3: This section compares the teeth durations, for measuring sincronization, since when i start the engine the sensor can be somewhere between the two teeth.

I just want it to start pressure signal capture when the first teeth that passed in front of the sensor for every turn is the one before TDC. Case its not it will start every time again till desired sincronization.

Section 4: This section just changes one ISR counter variable to 0 and changes variable k to 4 to start signal capture.

Section 5: Here according to the counter variable (copy) will start pressure signal capture, TDC detection and finish capture. It does this by 1200 loop cycles and saves the values in arrays.

Section 6: After 1200 values it prints to serial monitor and resets every variables for next cycle.

The signals (pressure and speed sensor) are fine since i scan it with an osciloscope an behaves as expected.

The problem is that the most of the times the sketch prints nothing, (sometimes it does) and i dont find the problem and need your help to at least look at the sketch and see if i am doing something wrong.

I am in these for a long time and i really want to finish this project.

Please give me a help.

Thanks a lot.

int count_pulses_1=0;
volatile int count_pulses_2=0;


int row = 0;

int copy=0;
int copy_sincro=0;
volatile unsigned long copy_pulse=0; 



int time1=0;
int time2=0;



volatile int k=0; //In the begining k=0, it will store the 6 time values in the array_time//


volatile int count_sincro=0;


int array_copy [1200];
int array_psg [1200];

 volatile unsigned long array_time[4];



void setup() {
  
  Serial.begin(9600);
 

  pinMode(3,INPUT);
   
  digitalWrite(3,HIGH); 

  attachInterrupt(1,react,CHANGE);  

}

void loop() {

 noInterrupts();        //Deactivate interrupt and does the copies from the variables called in the interrupt//

 copy_sincro=count_sincro;

  interrupts();
///////////////////////////////////////////////////////////// SECTION 1////////
  if (k==0) 
{

if (copy_sincro==24) //Waits 6 turns of the engine to stabilize speed//

{
 noInterrupts();  
k=1;
count_sincro=0;
interrupts();

}

}
////////////////////////////////////////////////////////  SECTION 2///////////////
 if (k==1) 
 { 
   noInterrupts(); 
   
   if (copy_sincro==4) //With k=1 and copy_sincro=4 it will calculate the time periods time1 and time 2 from the micros function in the interrupt//
   
 {
  
    k=2;
   interrupts();
   time1=array_time[1]-array_time[0];
   time2=array_time[3]-array_time[2];
 }
 }
/////////////////////////////////////////////////////////// SECTION 3 ///////////////////
if (k==2)
{

   if (time1<time2)  //Option 1, by luck the teeth before TDC was the first to pass in front of sensor, so k=3, and goes directly to signal capture bellow//
   {
   k=3;
   }
   else //Else it will start the time 1 and time 2 capture again till time1<time2//
   {
    
    noInterrupts();
    k=0;
    count_sincro=0;
    interrupts();
   }
}
////////////////////////////////////////////////////////////////////////// SECTION 4 ///////////////////
if (k==3) //After the above sincronization it will put k=4 and start the signal capture and then print the values//
    {
 k=4;
noInterrupts();
count_pulses_2=0;
interrupts();

}


/////////////////////////////////////////////////////////////////////////////SECTION 5 ///////////////////////
if (k==4)
{
 noInterrupts();  //Deactivate interrupt and does the copies from the variables called in the interrupt//
 array_copy[count_pulses_1]=copy;
 copy = count_pulses_2;
 interrupts();
 
  switch (copy) {

   case 0:
   array_psg[count_pulses_1]=0; 
      break;
      
    case 1:
       array_psg[count_pulses_1]=analogRead(A0); 
      break;
      
   case 2:
   array_psg[count_pulses_1]=analogRead(A0); 
      break;
      
      case 3:
     array_copy[count_pulses_1]=100;
      array_psg[count_pulses_1]=analogRead(A0); 
       break;
      
   case 4:
       array_copy[count_pulses_1]=copy;
       array_psg[count_pulses_1]=analogRead(A0); 
      break;
     
    }
    count_pulses_1++;
    
   }
    
     switch (count_pulses_1) //Prints out the captured values as intended// ////////////SECTION 6///////////////////////////

{
  noInterrupts();
 
  case 1199:
  
Serial.println();
Serial.print("count_pulses_1: ");
Serial.println(count_pulses_1);
Serial.print("time1: ");
Serial.println(time1);
Serial.print("time2: ");
Serial.println(time2);
Serial.println();
Serial.println("copy: ");
Serial.println(copy);
Serial.println();
Serial.println("count_pulses_2: ");
Serial.println(count_pulses_2);
Serial.println();
Serial.print("k: ");
Serial.println(k);
Serial.println();

     for (count_pulses_1=0; count_pulses_1<1200; count_pulses_1++)
{

/*Serial.print("DATA,TIME,");/*Serial.print(array_1[count_pulses_1]); Serial.print(",");Serial.print(array_copy [count_pulses_1]);/*Serial.print(",");
Serial.println(array_psg[count_pulses_1]);//Serial.print(",");Serial.print(count_pulses_2);Serial.print(",");Serial.print(copy);Serial.print(",");Serial.println(k);*/

Serial.println(array_psg[count_pulses_1]);
Serial.print(array_copy [count_pulses_1]);

row++;


}
count_pulses_1=0; //After printing starts all over again//
count_pulses_2=0;
k=0;
count_sincro=0;
interrupts();
break;

}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
}
void react() //Interrupt routine//
{


  if (k==1)
{
  array_time[count_sincro]= micros();
}

count_sincro++;
count_pulses_2++;
}

Your arrays are too large for the smaller arduinos. Which one are you using?

Arduino mega 2560

This looks odd:

 if (k==1) 
  { 
    noInterrupts(); 

    if (copy_sincro==4) //With k=1 and copy_sincro=4 it will calculate the time periods time1 and time 2 from the micros function in the interrupt//

    {

      k=2;
      interrupts();
      time1=array_time[1]-array_time[0];
      time2=array_time[3]-array_time[2];
    }
  }

Why are you turning interrupts off here and leaving them off?

As a debugging aid you can light one or two LEDs, signaling what the Arduino “thinks” about the processed tooth signals. Then you can connect these outputs to your scope as well, and verify that both markers are detected and distinguished properly, and the exact delay between sensor and output signals. A logic analyzer may be helpful for watching multiple channels at the same time. The LEDs are optional, digital outputs are sufficient for signal monitoring.

Thanks for reply.

Why are you turning interrupts off here and leaving them off?

After k=2 setence i have interrupts(). Maybe i am wrong but i thought that activate interrupts again.

As a debugging aid you can light one or two LEDs, signaling what the Arduino "thinks" about the processed tooth signals. Then you can connect these outputs to your scope as well, and verify that both markers are detected and distinguished properly, and the exact delay between sensor and output signals. A logic analyzer may be helpful for watching multiple channels at the same time. The LEDs are optional, digital outputs are sufficient for signal monitoring.

That sounds interesting.

The program gets always stuck in the section 5. Till there works as expected.

I printed some variables after the "count_pulses_1" reaching 1200, and the variable "count_pulses_2" is always 0 and should be incremented by the ISR routine detecting changing pulses of the tooth in the wheel.

I think the problem is here but i find no explanation for that.

You see in atachment, where the two red arrows point, copy and count_pulses_2 variables are 0 and should be at least 4.

All other variables have the kind of expected value.

The funny thing is that sometimes it works good, but very few times does that. It seems to me like for some reason the arduino, when reaches section 5 of the program, doesnt care about the interrupt.

serbar10:
After k=2 setence i have interrupts(). Maybe i am wrong but i thought that activate interrupts again.

Well it does, but only if copy_sincro==4, which, since you’re relying on your interrupt routine to increment copy_sincro, seems unwise. I assume it’s the interrupts statement in section five that’s reactivating them.

On that point, I don’t know why you’re trying to turn interrupts off in section five either - serial output depends on them. Consider detachInterrupt instead.

Well it does, but only if copy_sincro==4, which, since you're relying on your interrupt routine to increment copy_sincro, seems unwise

Thats a good point. Already altered like this:

if (k==1) 
 { 
   noInterrupts(); 
  
   
   if (copy_sincro==4) //With k=1 and copy_sincro=4 it will calculate the time periods time1 and time 2 from the micros function in the interrupt//
   
 {
  
    k=2;
   
   time1=array_time[1]-array_time[0];
   time2=array_time[3]-array_time[2];
 }
 interrupts();
 }

On that point, I don't know why you're trying to turn interrupts off in section five either - serial output depends on them.

In section 5 i just deactivate the interrupt to make the copy of the variable count_pulses_2 to copy and activate right after.

I think your talking about nointerrupt() in the section 6, when the array values are printed?

serbar10:
I think your talking about nointerrupt() in the section 6, when the array values are printed?

Yup, my mistake - it is section six.

I have this because my thought was: theres no point listen whats hapening in the engine at least while the values of the arrays are being printed. Perahps theres no logic in that... whats your opinion?

I didnt know too, that interfered with the serial.print function.

Consider detachInterrupt instead.

I only have one interrupt. What sort of advantage would that give?

Thanks a lot for help.

Generally, if you're going to turn interrupts off, it should be for the least time possible - just long enough to copy/change data in a volatile variable that is changed in an interrupt routine.

If you don't want to listen to engine data while printing the results, detachinterrupt will let you do that without turning all other interrupts off too. You may only have one interrupt explicitly specified, but there are others being used too behind the scenes.

I understand now.

And when i want to activate the interrupt again? Should i use interrupts()? or attachinterrupt()? Or its not important?

You'll need to use attachinterrupt to reactivate it.

Thanks.

The sketch is more stable.

But the main problem is time, at engine idle the arduino starts signal captation and does it faster than the wheel completes one turn, so when it reaches the first teeth (60 degree before TDC) it allready completed the 1200 loops, so the all zero values reason explained...

When i increase rpm the program works fine till 3000 rpm, after that blocks and doesnt serial print values. I think its too busy buffer.

Can you give your opinion?

Thanks.

Hard to say without seeing the code, please post your latest version.

Here it is:

int count_pulses_1=0;
volatile int count_pulses_2=0;


int row = 0;

int copy=0;
int copy_sincro=0;
volatile unsigned long copy_pulse=0; 



int time1=0;
int time2=0;
int time3=0;

volatile int k=0; 


volatile int count_sincro=0;   


int array_copy [1200];
int array_psg [1200];

 volatile unsigned long array_time[4];



void setup() {
  
  Serial.begin(38400);
 

  pinMode(3,INPUT);
   
  digitalWrite(3,HIGH); 

  attachInterrupt(1,react,CHANGE);  

}

void loop() {

detachInterrupt(1);       //Deactivate interrupt and does the copies from the variables called in the interrupt//

 copy_sincro=count_sincro;
 copy = count_pulses_2;
 attachInterrupt(1,react,CHANGE);  
///////////////////////////////////////////////////////////// SECTION 1////////  
  if (k==0) 
{
 
if (copy_sincro==4) 
{
  detachInterrupt(1); 
  k=1;
attachInterrupt(1,react,CHANGE);
}
 
}
////////////////////////////////////////////////////////  SECTION 2///////////////
 if (k==1) 
 { 
  detachInterrupt(1); 
  k=2;
   
   time1=array_time[1]-array_time[0];
   time2=array_time[3]-array_time[2];
   time3=array_time[3]-array_time[0];
   
 attachInterrupt(1,react,CHANGE);  
 }
/////////////////////////////////////////////////////////// SECTION 3 ///////////////////
if (k==2)
{

   if (time1<time2)  //Option 1, by luck the teeth before TDC was the first to pass in front of sensor, so k=3, and goes directly to signal capture bellow//
   {
   k=4;
  detachInterrupt(1); 
   count_pulses_2=0;
attachInterrupt(1,react,CHANGE);  
   }
   else //Else it will start the time 1 and time 2 capture again till time1<time2//
   {
    
detachInterrupt(1); 
    k=0;
    count_sincro=0;
attachInterrupt(1,react,CHANGE);  
   }
}
/////////////////////////////////////////////////////////////////////////////SECTION 4 ///////////////////////
if (k==4)
{
  switch (copy) {

 case 0:
   
   array_copy[count_pulses_1]=0;
   array_psg[count_pulses_1]=0;

      break;
      
    case 1:
       array_copy[count_pulses_1]=1;
       array_psg[count_pulses_1]=analogRead(A0);

      break;
      
   case 2:
  array_copy[count_pulses_1]=2;
  array_psg[count_pulses_1]=analogRead(A0); 

    break;
      
      case 3:
      array_copy[count_pulses_1]=3;
      array_psg[count_pulses_1]=analogRead(A0); 
  
     break;
      
   case 4:
      array_copy[count_pulses_1]=4;
      array_psg[count_pulses_1]=analogRead(A0); 
    
    break;
     
    }
    count_pulses_1++;
    
   }

     switch (count_pulses_1) //Prints out the captured values as intended// 

{
detachInterrupt(1); 
 
  case 1199:
  


Serial.print("DATA,TIME,");
Serial.println(count_pulses_1);

    for (count_pulses_1=0; count_pulses_1<1200; count_pulses_1++)
{

Serial.print("DATA,TIME,");Serial.print(array_copy [count_pulses_1]);Serial.print(",");
Serial.println(array_psg[count_pulses_1]);


row++;


}
count_pulses_1=0; //After printing starts all over again//
count_pulses_2=0;
k=0;
count_sincro=0;
attachInterrupt(1,react,CHANGE);  
break;

}
 

}

////////////////////////////////////////////////////////////////////////////////////////////////////

void react() //Interrupt routine//
{


 if (k==0)
{
  array_time[count_sincro]= micros();
}

count_sincro++;
count_pulses_2++;
}

Is there a way of saving this kind of very fast capturing data with arduino to some device like some memory card and then convert to usable data like xls file?

It would be very useful here i think.

Another question:

Do deactivating interrupts in the sketch mess with micros() function? I am asking because i have a routine in the sketch to predict the rpm where i call micros() and i dont get the real rpm value. I check with tachometer in the vehicle and is always a lower value than expected.

But at any given engine speed the real rpm and the calculated rpm in my sketch have a fixed relation, more or less 1,36 times bigger the real rpm.

I can't see anything immediately obviously wrong causing your problem. There is this though:

 switch (count_pulses_1) //Prints out the captured values as intended// 
  {
    detachInterrupt(1); 

  case 1199:

Should be:

 switch (count_pulses_1) //Prints out the captured values as intended// 
  {

  case 1199:
    detachInterrupt(1);