Multiple Solenoids triggered by Hall Effect Sensor

I am now on the software side of my project ( http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1289168643/28#28 )

The goal is to to use a hall sensor to read a magnet on the crankshaft gear. Then using the signal, calculate the point where the piston is at the very top of the stroke (TDC). This will allow me to accurately fire the solenoids at specified times for desired amounts of time. As a member on the forum pointed out,

You can calculate RPM by measuring the time between pulses. And you can calculate position (in fractions of a degree if necessary) by dividing the period (the time between TDC) by 360. Once you know where TDC is, and you know the RPM (or actually the time between TDC), then it is almost trivial to calculate (and adjust) the position and period of any solenoid opening.

Unfortunately, I am a mechanical engineer major and have no background of programming. Rendering me pretty lost with the whole sketch side.

To make it more complicated, I will have a button on the board which when depressed will change how long the solenoid is open at set increments (I.E. 20%, 30%...) I am also running an LCD to display RPMS as well as a percentage of the stroke for which the solenoid is open.

I have come across a Bike Spoke POV project http://www.openobject.org/opensourceurbanism/Adding_a_Sensor

It is very similar in function but different enough that I cannot follow it very well. http://www.openobject.org/opensourceurbanism/Spoke-o-dometer_Beta_8

All the pieces have been purchased including the uno.

With all that said, I have read Libraries and examples, but the language just doesn't flow for me yet. Can someone give me a push in the right direction? Where do I start? Is the bike POV similar enough that a few modifications and it will work?

Thank you for your time, Austin

This is the code I have pieced together thus far. Please let me know if I’m on the correct path.
I am confused about the Position Calculation. The time divided by 360 returns a decimal, not a degree…

//-----------------------------------------------
 #include <LiquidCrystal.h>
 LiquidCrystal lcd(7,8,9,10,11,12)
 volatile unsigned int eventcount;
 unsigned int degree; // Angle of rotation out of 360
 unsigned int rpm;
 unsigned long timeold;
 int So17Pin = 3 // Solenoids 1 and 7 assigned to Pin 3
 int So35Pin = 4 // Solenoids 3 and 5 assigned to Pin 4
 int So28Pin = 5 // Solenoids 2 and 8 assigned to Pin 5
 int So46Pin = 6 // Solenoids 4 and 6 assigned to Pin 6


 void setup()
 {
   Serial.begin(9600);
   pinMode (So17Pin, OUTPUT);
   pinMode (So35Pin, OUTPUT);
   pinMode (So28Pin, OUTPUT);
   pinMode (So46Pin, OUTPUT);
   attachInterrupt(0, rpm_count, RISING);
   eventcount = 0;
   degree = 0;
   rpm = 0;
   timeold = 0;
 }

  void rpm_count()
 {
   eventcount++;
   //Updated Count
 }

 void loop()
 {
   if (eventcount >= 1) {

     degree = (millis() - timeold) / 360;
     rpm = (millis() - timeold) / eventcount;
     rpm = 1000/rpm;
     rpm = rpm*60;
     timeold = millis();
     eventcount = 0;
     Serial.println(degree,DEC);
     Serial.println(rpm,DEC);

   }
   // Open for 80% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= 143.2) || (degree >= 1) {
     digitalWrite(So17, HIGH);
     digitalWrite(So46, HIGH);
     }
else {
  digitalWrite(So17, LOW);
  digitalWrite(So46, LOW);
}

  // Open for 80% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= 324.2) || (degree >= 181) {
     digitalWrite(So35, HIGH);
     digitalWrite(So28, HIGH);
     }
else {
  digitalWrite(So35, LOW);
  digitalWrite(So28, LOW);
}
//-----------------------------------------------

Updated Code:

Please let me know if this looks correct

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

//-----------------------------------------------
 #include <LiquidCrystal.h>
 LiquidCrystal lcd(7,8,9,10,11,12);
 volatile unsigned int eventcount; 
 unsigned int valve; // Time Valve Open
 unsigned int rpm;
 unsigned int degree;
 unsigned long timeold;
 int So17Pin = 3; // Solenoids 1 and 7 assigned to Pin 3
 int So35Pin = 4; // Solenoids 3 and 5 assigned to Pin 4
 int So28Pin = 5;// Solenoids 2 and 8 assigned to Pin 5
 int So46Pin = 6; // Solenoids 4 and 6 assigned to Pin 6
 int buttonPin = 13; // Button For Switching % 
 int buttonPushCounter = 0;   // counter for the number of button presses
 int buttonState = 0;         // current state of the button
 int lastButtonState = 0;     // previous state of the button
 
 
 void setup()
 {
   Serial.begin(9600);
   pinMode (So17Pin, OUTPUT);
   pinMode (So35Pin, OUTPUT);
   pinMode (So28Pin, OUTPUT);
   pinMode (So46Pin, OUTPUT);
   pinMode(buttonPin, INPUT);
   attachInterrupt(0, rpm_count, RISING); // Interrupt 0 is Pin 2 Hall Sensor
   eventcount = 0;
   valve = 0;
   rpm = 0;
   timeold = 0;
   degree = 0;
 }
 
  void rpm_count()
 {
   eventcount++;
   //Updated Count
 }
 
 void loop()
 {
   if (eventcount >= 1) { 
     
     rpm = (micros() - timeold) / eventcount; 
     rpm = 1000000/rpm;
     rpm = rpm*60; 
     timeold = micros();
     eventcount = 0;
     degree = (60000000/rpm);
     degree = degree/360;
     
     Serial.println(degree,DEC);
     Serial.println(rpm,DEC);
     
   }
  
   if (buttonState != lastButtonState) {
    
    if (buttonState == HIGH) {
 
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter, DEC);
    } 
    else {
         Serial.println("off"); 
    }
  }
    lastButtonState = buttonState;
  
   if (buttonPushCounter % 1 == 0) {
   // Open for 80% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (valve <= ( degree*143.2) || (valve >= degree*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 80% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (valve <= (degree*324.2) || (valve >= (degree*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}
 }
//-----------------------------------------------
eventcount = 0;
   valve = 0;
   rpm = 0;
   timeold = 0;
   degree = 0;

Not needed - they have global scope, so they are automatically initialised to zero.
Some of them don’t even need to be global.
Some of them could possibly benefit from being "float"s, but the code is a little lacking in meaningful comments.

int So17Pin = 3; // Solenoids 1 and 7 assigned to Pin 3
 int So35Pin = 4; // Solenoids 3 and 5 assigned to Pin 4
 int So28Pin = 5;// Solenoids 2 and 8 assigned to Pin 5
 int So46Pin = 6; // Solenoids 4 and 6 assigned to Pin 6
 int buttonPin = 13; // Button For Switching

I’d make these "“const”.

Not needed - they have global scope, so they are automatically initialised to zero.
Some of them don’t even need to be global.
Some of them could possibly benefit from being "float"s, but the code is a little lacking in meaningful comments.

Thank you, I will take your suggestions into consideration and continue posting the updated code here.

Here is the latest update.
How do I make sure that the value of eventcount doesn’t go over 1? If I’m not mistaken, with the eventcount++ it adds one to the last count, but in the ReadingRPM Playground, it acts like after 20 it resets. With my statement of if(eventcount >= 1) will that limit it to 1 and only 1? Do I even need to include eventcount in my (time-timeold)/eventcount if its always one?

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

//-----------------------------------------------
 volatile unsigned int eventcount; // Assinging the Count Feature
 unsigned int rt; // Rotation Time
 unsigned int degree; // Position of Piston
 unsigned int rpm; // RPM
 unsigned long timeold; // Previous time Hall Sensor Picked up
 const int So17Pin = 3; // Solenoids 1 and 7 assigned to Pin 3
 const int So35Pin = 4; // Solenoids 3 and 5 assigned to Pin 4
 const int So28Pin = 5; // Solenoids 2 and 8 assigned to Pin 5
 const int So46Pin = 6; // Solenoids 4 and 6 assigned to Pin 6
 const int buttonPin = 13; // Button For Switching "Valve Open Time" Percent 
 const int button2Pin = 14; // Button For Start Mode Intake 1+7
 const int button3Pin = 15; // Button For Start Mode Intake 3+5
 int buttonPushCounter = 0;   // counter for the number of button presses--- used with button for "Valve Open Time" Percent
 int buttonState = 0;         // current state of the button
 int button2State = 0;        // current state of the button 2
 int button3State = 0;        // current state of  the button 3
 int lastButtonState = 0;     // previous state of the button
 int lastButton2State = 0;     // previous state of the button 2
 int lastButton3State = 0;     // previous state of the button 3
 
 void setup()
 {
   Serial.begin(9600); // Communicate to Serial Port
   pinMode (So17Pin, OUTPUT); // Solenoid 1+7 as Output
   pinMode (So35Pin, OUTPUT); // Solenoid 3+5 as Output
   pinMode (So28Pin, OUTPUT); // Solenoid 2+8 as Output
   pinMode (So46Pin, OUTPUT); // Solenoid 4+6 as Output
   pinMode(buttonPin, INPUT); // Button for "Valve Open Time" as Input
   pinMode(button2Pin, INPUT); // Button For Start Mode 1+7 Intake
   pinMode(button3Pin, INPUT); // Button For Start Mode 3+5 Intake
   attachInterrupt(0, event_count, RISING); // Interrupt 0 is Pin 2 Hall Effect Sensor
   
 }
   void loop()
 { if(eventcount >=1)
   // Calculate position of piston
     rt = (micros() - timeold)/ eventcount; // Time Between Each Hall Pulse
     rt = rt/360; // Time Between Each Hall Pulse Divided by ( 360 Degrees)--- Time for 1 degree of rotation
     rt = abs(rt); // Absolute value of found time--- To make sure every degree is a positive number ( with time-timeold and deceleration of rotation speed, there will be a negative number produced)
     timeold = micros();
     eventcount = 0;     
    
    // Calculate RPM 
     rpm = (micros() - timeold) / eventcount;  // Time Between Each Hall Pulse
     rpm = 1000000/rpm;  // (Microseconds to Second) Divided by (Time Between Each Hall Pulse)
     rpm = rpm*60; //((Microseconds to Second) Divided by (Time Between Each Hall Pulse)) Times (Seconds to Minutes)
     timeold = micros();
     eventcount = 0; 
          
     Serial.println(rpm,DEC); // Print RPM on Serial
     
   //-------------------------------------------------------------------------------------- START MODE
   
    if (rpm = 0) // If Device is not spinning then Enable the Button's 2 and 3. If it is spinning Disable the Button's 2 and 3
    {
    if (button2State != lastButton2State) // Start Mode Button2 Pressed--- Intake 1 and 7 Exhaust 4 and 6 
    {
        if (button2State == HIGH) {
     digitalWrite(So17Pin, HIGH); // Fire Intake 1 and 7
     digitalWrite(So46Pin, HIGH); // Fire Exhaust 4 and  6
     Serial.println("Start In 1+7"); // Display Via Serial "Start In 1+7"
       } 
     }
  
    {
    if (button3State != lastButton3State) // Start Mode Button3 Pressed--- Intake 3 and 5 Exhaust 2 and 8
    {
    
    if (button2State == HIGH) {
     digitalWrite(So35Pin, HIGH); // Fire Intake 3 and 5
     digitalWrite(So28Pin, HIGH); // Fire Exhaust 2 and 8
     Serial.println("Start In 3+5"); // Display Via Serial "Start In 1+7"
       } 
     }
    }
   //------------------------------------------------------------------------------------ RUN MODE
     { 
   }
  // Open for 100% Stroke Intake (1 and 7) Exhaust (4 and 6)
  if (degree <= ( rt*179) || (degree >= rt*1) ) // If the piston is inbetween 1 to 179 degrees of revolution then...
  {
     digitalWrite(So17Pin, HIGH); // Fire Solenoid 1 and 7 (Intake)
     digitalWrite(So46Pin, HIGH); // Fire Solenoid 4 and 6 (Exhaust)
     Serial.println("Intake (1,7) Exhaust (4,6) Fired 100%"); // Print Status and Percent of Valve Open
     }
else { 
  digitalWrite(So17Pin, LOW); // Don't Fire Solenoid 1 and 7 (Intake)
  digitalWrite(So46Pin, LOW); // Don't Fire Solenoid 4 and 6 (Exhaust)
  }
  // Open for 100% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*359) || (degree >= (rt*181)) ) // If the piston is inbetween 181 to 359 degrees of revolution then...
  { 
     digitalWrite(So35Pin, HIGH); // Fire Solenoid 3 and 5 (Intake)
     digitalWrite(So28Pin, HIGH); // Fire Solenoid 2 and 8 (Exhaust)
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 100%"); // Print Status and Percent of Valve Open
     }
else { 
  digitalWrite(So35Pin, LOW); // Don't  Fire Solenoid 3 and 5 (Intake)
   digitalWrite(So28Pin, LOW); // Don't Fire Solenoid 2 and 8 (Exhaust)
}

}
 
  //------------------------------------------ Button Control--- Allows the Change of How Long Valve Stays Open Per Revolution
  
   if (buttonPushCounter <= 9){
   if (buttonState != lastButtonState) // "Percent of "Valve Open Time" " Button Pressed
   {
    
    if (buttonState == HIGH) {
       buttonPushCounter++; // Update Button Counter
      Serial.print("number of button pushes:  "); // Display Via Serial "number of button pushes: "
      Serial.println(buttonPushCounter, DEC); // Display Via Serial Button Push Count
    } 
    else {          
     lastButtonState = buttonState; // Stay at last button state if Button is not Pressed
    }
   }
   else {
     buttonPushCounter = 0; // Resets to 0 if it has been pressed more than 9 times
   }
 
 //---------------- 90% Valve Open  
  if (buttonPushCounter == 1) // If button is pressed once
  {
    Serial.println("90%"); 
   // Open for 90% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*161.1) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 90%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 90% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*342.1) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 90%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 80% Valve Open    
   if (buttonPushCounter == 2) {
     Serial.println("80%"); 
   // Open for 80% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*143.2) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 80%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 80% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*324.2) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 80%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 70% Valve Open  
if (buttonPushCounter == 3) {
  Serial.println("70%"); 
   // Open for 70% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*125.3) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 70%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 70% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*306.3) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 70%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 60% Valve Open  
if (buttonPushCounter == 4) {
  Serial.println("60%"); 
   // Open for 60% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*107.4) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 60%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 60% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*288.4) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 60%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 50% Valve Open  
if (buttonPushCounter == 5) {
  Serial.println("50%"); 
   // Open for 50% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*89.5) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);

Continuation…

 Serial.println("Intake (1,7) Exhaust (4,6) Fired 50%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 50% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*270.5) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 50%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 40% Valve Open  
if (buttonPushCounter == 6) {
  Serial.println("40%"); 
   // Open for 40% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*71.6) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 40%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 40% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*252.6) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 40%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 30% Valve Open  
if (buttonPushCounter == 7) {
  Serial.println("30%"); 
   // Open for 30% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*53.7) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 30%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 30% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*234.7) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 30%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 20% Valve Open  
if (buttonPushCounter == 8) {
  Serial.println("20%"); 
   // Open for 20% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*35.8) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 20%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 20% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*216.8) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 20%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

//---------------- 10% Valve Open  
if (buttonPushCounter == 9) {
  Serial.println("10%"); 
   // Open for 10% Stroke Intake (1 and 7) Exhaust (4 and 6)
   if (degree <= ( rt*17.9) || (degree >= rt*1) ){
     digitalWrite(So17Pin, HIGH);
     digitalWrite(So46Pin, HIGH);
      Serial.println("Intake (1,7) Exhaust (4,6) Fired 10%");
     }
else { 
  digitalWrite(So17Pin, LOW);
  digitalWrite(So46Pin, LOW);
}
  // Open for 10% Stroke Intake (3 and 5) Exhaust (2 and 8)
  if (degree <= (rt*198.9) || (degree >= (rt*181)) ){
     digitalWrite(So35Pin, HIGH);
     digitalWrite(So28Pin, HIGH);
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 10%");
     }
else { 
  digitalWrite(So35Pin, LOW);
  digitalWrite(So28Pin, LOW);
}

}

   }
 }
  void event_count()
 {
   eventcount++; // Hall Effect Count Updater 
 }


 
//-----------------------------------------------
     eventcount = 0;    
    
    // Calculate RPM
     rpm = (micros() - timeold) / eventcount;  // Time Between Each Hall Pulse

First, you set eventcount to 0, then, you divide by eventcount. Yeah, that will work. NOT.

How do I make sure that the value of eventcount doesn't go over 1? If I'm not mistaken, with the eventcount++ it adds one to the last count, but in the ReadingRPM Playground, it acts like after 20 it resets. With my statement of if(eventcount >= 1) will that limit it to 1 and only 1? Do I even need to include eventcount in my (time-timeold)/eventcount if its always one?

eventcount is incremented in the event_count() function, which is your interrupt service routine. You do NOT want to [u]constrain[/u] eventcount.

You want, in loop(), to periodically copy the value in eventcount, after recording time and disabling interrupts, and then reset it and re-enable interrupts.

You then want to base RPM on the copy of eventcount and the two times.

First, you set eventcount to 0, then, you divide by eventcount. Yeah, that will work. NOT.

Love the sarcasm. Thanks! ;)

But you did point out a big mistake which also answers my question. I need to only use event count once and calculate rpm off the previous calculation. I was told that disabling and re enabling the interrupts would not be good to use with data that has to be very accurate.

Code should look like this correct?

  void loop()
   // Calculate position of piston
     rt = (micros() - timeold)/ eventcount; // Time Between Each Hall Pulse
     rt = rt/360; // Time Between Each Hall Pulse Divided by ( 360 Degrees)--- Time for 1 degree of rotation
     rt = abs(rt); // Absolute value of found time--- To make sure every degree is a positive number ( with time-timeold and deceleration of rotation speed, there will be a negative number produced)
     timeold = micros();
     eventcount = 0;    
    
    // Calculate RPM
     rpm = 60000000/(rt*360)];  // Time Between Each Hall Pulse
               
     Serial.println(rpm,DEC); // Print RPM on Serial
    
   //-------------------------------------------------------------------------------------- START MODE
  
    if (rt = 0)

I was told that disabling and re enabling the interrupts would not be good to use with data that has to be very accurate.

Since the eventcount and time will all be based on whether or not interrupts are enabled, the RPM value will not be impacted by disabling/enabling interrupts. There may be other reasons not to.

The problem with leaving them enabled though is here:

 volatile unsigned int eventcount; // Assinging the Count Feature

ints don’t fit in registers. So, processing an interrupt requires reading two bytes into two different registers, incrementing the LSB, checking for overflow, and incrementing the MSB if necessary.

This works fine, since another interrupt can not happen during the processing of this interrupt.

In loop, though, while making a copy of eventcount and/or reinitializing eventcount, an interrupt could fire. Then, the MSB could be from before the interrupt and the LSB from after the interrupt, when either reading or writing to eventcount.

This problem, and the need to disable/enable interrupts if eventcount was a byte.

Changing it to a byte, though, means that loop has to reset eventcount BEFORE it overflows. That means that the interval needs to be determined such that at maximum RPM, eventcount is copied and reset at less than that interval, so that it never overflows.

[edit]By the way, time never decreases, so rt should never be negative. Or should always be, depending on the order of the operands. If it is always negative, switch them around. The abs() function call is not needed.[/edit]

This problem, and the need to disable/enable interrupts if eventcount was a byte.

Changing it to a byte, though, means that loop has to reset eventcount BEFORE it overflows. That means that the interval needs to be determined such that at maximum RPM, eventcount is copied and reset at less than that interval, so that it never overflows.

Thanks for the advice. I will change it to byte instead. I'm still trying to avoid disabling/enabling interrupts as the rt value is doing much more than displaying a value. Could you give me an example of what you mean by copying the event count at a maximum rpm?

If I have event count reseting to 0 after each count anyways, is your suggestion even needed?

By the way, time never decreases, so rt should never be negative. Or should always be, depending on the order of the operands. If it is always negative, switch them around. The abs() function call is not needed.

I thought this as well, but what happens when "time is less than time old"? It produces a negative number which after the calculations would give me a negative position degree. Right?

thanks again

Could you give me an example of what you mean by copying the event count at a maximum rpm?

What I meant was that you need to determine the maximum RPM rate that you are trying to monitor. Given that, you can determine how long before 255 interrupts have occurred. Then, you need to make sure that the code reads and resets eventcount at least that often.

If I have event count reseting to 0 after each count anyways, is your suggestion even needed?

How can you be assured of doing this? If the motor is running at 15 RPM, you might be able to, but get it up to 15000 RPM, and you won’t be able to.

but what happens when “time is less than time old”?

The time that an interrupt occurs is recorded. The time that the next interrupt occurs is recorded. How can the 2nd time ever occur before the 1st time?

How can you be assured of doing this? If the motor is running at 15 RPM, you might be able to, but get it up to 15000 RPM, and you won't be able to.

Are you saying that if the device spins too fast, the eventcount reset to 0 won't be able to keep up? It will never see 15000 RPM let alone 5000RPM.

The time that an interrupt occurs is recorded. The time that the next interrupt occurs is recorded. How can the 2nd time ever occur before the 1st time?

Theoretically lets say the motor is spining at 5000 RPM the time between each revolution is 200 milliseconds. Now within one revolution the engine is spinning at 5500 RPM which takes 150 milliseconds to make one revolution.

150-200= -50 millisecond difference.

Are you saying that if the device spins too fast, the eventcount reset to 0 won’t be able to keep up?

No. I’m saying that the faster it spins, the less time you have before eventcount, as a byte, overflows. You need to make sure that you can copy eventcount and reset it within that window.

Theoretically lets say the motor is spining at 5000 RPM the time between each revolution is 200 milliseconds. Now within one revolution the engine is spinning at 5500 RPM which takes 150 milliseconds to make one revolution.

150-200= -50 millisecond difference.

You have a watch, right? Every time I yell tick (an interrupt), you make a tick marks (eventcount++). Every 5 minutes, you compute ticks/minute and throw away the page with the tick marks on it (reset eventcount to 0).

That is what the Arduino is doing to compute RPM (ticks per unit of time).

If the time between my yelling tick changes (the RPM changes), the time that you last threw a page away can never be greater than time you next prepare to through a page away.

That example makes it clear. I have removed the abs function.
Also, the RPMReading Playground uses the same byte and event count function and is able to see over 3000 RPM. They are also using every 20 counts, so, I don’t think I have an overflow issue. If it comes up I’ll deal with it.

At the moment I’m having a mental block though. The code I wrote

if (degree <= ( rt*179) || (degree >= rt*1) ) // If the piston is inbetween 1 to 179 degrees of revolution then...
  {
     digitalWrite(So17Pin, HIGH);

Doesn’t make sense because my degree variable is not equal to anything.

How do I write this script a different way? Obviously I was trying to tell it, that if the value is between rt1 and rt179 to fire solenoid 1 and 7.

Thanks

Obviously I was trying to tell it, that if the value is between rt*1 and rt*179 to fire solenoid 1 and 7.

If what value is between rt and rt * 179?

Unless both solenoids are connected to the same pin, you'll need multiple digitalWrite statements.

If what value is between rt and rt * 179?

Unless both solenoids are connected to the same pin, you'll need multiple digitalWrite statements.

Thats my issue. I'm havnig trouble putting a value to that "value".

If the piston is in between 1 to 179 degrees of the stroke, I want it to fire said solenoids. How do I write this? I know how long it takes to make a revolution, and I know how long it takes to make one degree inside that revolution...

Unless both solenoids are connected to the same pin, you'll need multiple digitalWrite statements.

Both solenoids are connected to the same pin

I know how long it takes to make a revolution, and I know how long it takes to make one degree inside that revolution.

But, you don't have a point of reference for where you are in the cycle.

If you knew when the last interrupt fired, and what time it is now, and a very fast calculator, you could determine where the crankshaft is now.

To do this, you'll need to expand what happens in the ISR, to include recording when the interrupt fired. Keep in mind, though, that millis or micros return unsigned longs, and to ensure that the time variable does not get corrupted, interrupts will need to be disabled/re-enabled in the ISR.

But, you don’t have a point of reference for where you are in the cycle.

If you knew when the last interrupt fired, and what time it is now, and a very fast calculator, you could determine where the crankshaft is now.

To do this, you’ll need to expand what happens in the ISR, to include recording when the interrupt fired. Keep in mind, though, that millis or micros return unsigned longs, and to ensure that the time variable does not get corrupted, interrupts will need to be disabled/re-enabled in the ISR.

Paul, I don’t mean to be rude, but have you read my code?

I have already covered all of this except the disabling the interrupts which I will add in, in the future. Hence:

void loop()
 { if(eventcount >=1)
   // Calculate position of piston
     rt = (micros() - timeold)/ eventcount; // Time Between Each Hall Pulse
     rt = rt/360; // Time Between Each Hall Pulse Divided by ( 360 Degrees)--- Time for 1 degree of rotation
    
     timeold = micros();
     eventcount = 0;

What I need help with is telling the microprocessor that, when its at a certain point of the revolution when to fire the valves.

I was trying to accomplish it like this

if (degree <= ( rt*179) || (degree >= rt*1) ) // If the piston is inbetween 1 to 179 degrees of revolution then...
  {
     digitalWrite(So17Pin, HIGH);

But realized that the variable degree does not equal anything

Paul, I don't mean to be rude, but have you read my code?

Yes, I've read your code. You have on part of your code processing an interrupt when the hall-effect sensor sees a magnet. You have another part of your code calculating RPM and (trying to calculate) position. But, those two parts of code do not share a common reference (time).

rt = (micros() - timeold)/ eventcount; // Time Between Each Hall Pulse

This comment is wrong. Some number of events have occurred during some known amount of time. rt is calculating the average time to rotate the crankshaft once.

     rt = rt/360; // Time Between Each Hall Pulse Divided by ( 360 Degrees)--- Time for 1 degree of rotation

This comment is right. It IS calculating the time to rotate the crankshaft one degree.

But, so what? When you are doing this, you have no idea where the crankshaft is. The last eventcount increment could have been 3 degrees or 180 degrees or 350 degrees in the past.

In addition to recording that the hall effect sensor fired, you need to record WHEN it fired. Then, when you know how long it takes to travel one degree, you'll know when (assuming a (relatively) constant speed of rotation) the crankshaft will be at a given position. When it gets to be that time, change the state of the pin.