I am using an arduino mega2560 to make an engine controller in which i am taking 3 signals coming from an engine as input, i want this code to do this: as soon as the states of master and proximity becomes high, the board should generate a pulse at a particular time specified, which should be on for some time and then go off, i am measuring the time by counting the no. of highs occurring on the incremental signal, which should start counting only just after the states of master and proximity match as high.
But the code is not doing the same, its actually generating the pulse much before the point it should, Can someone please explain me where it is going wrong or explain me the functioning of this code so that i may myself figure out what's going wrong ?
const int master = 21; // interrupt 2
const int proximity = 20; // interrupt 3
const int incremental = 3; // interrupt 1
const int ledPin = 12; // injector pin
volatile int counter = 0; // to count 360 degrees
int master_state = 0;
int proximity_state = 0;
volatile float s_o_i = 300; // start of injection
volatile float e_o_i = 360; // end of injection
volatile int n_o_s = 0; // no of strokes
void setup()
{
Serial.begin(9600); // initialize serial communication
pinMode(master, INPUT);
pinMode(proximity, INPUT);
pinMode(incremental, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin,LOW); // so that at start it should not start injecting
attachInterrupt (1, count, RISING); // attach interrupt handler of incremental
}
void count() // ISR
{
if(counter == s_o_i)
{
digitalWrite(ledPin,HIGH); // start injection
}
if(counter == e_o_i)
{
digitalWrite(ledPin,LOW); // stop injection
counter = 0;
}
counter++;
}
void loop()
{
noInterrupts(); // turning off the interrupts
master_state = digitalRead(master);
proximity_state = digitalRead(proximity);
if (master_state == HIGH && proximity_state == HIGH)
{
interrupts(); // turning on the interrupts
}
}
noInterrupts(); // turning off the interrupts
master_state = digitalRead(master);
proximity_state = digitalRead(proximity);
if (master_state == HIGH && proximity_state == HIGH)
{
interrupts(); // turning on the interrupts
}
with
if ( digitalRead(master)) // true if HIGH, false if LOW
{
if ( digitalRead(proximity))
{
interrupts(); // turning on the interrupts
}
else
{
noInterrupts(); // turning off the interrupts
}
}
else
{
noInterrupts(); // turning off the interrupts
}
And put noInterrupts() is setup and lose the 2 int variables and assignments and &&.
On the first occassion that master_state and proximity_state are high, the interrupts are enabled.
After 300 pulses of your incremental signal LEDpin is sent high
60 pulses later LEDpin is sent low again and counter is reset
For these events to occur, master_state and proximity_state must remain high
(otherwise the loop function will disable interrupts and the count stops happening)
SO
once the counter gets set back to zero, master_state and proximity_state must still be high
the loop function therefore enables interrupts
and counting continues.
(even though it's not the next revolution yet)
if master_state or proximity_state go low before the increment has reached 300, you won't be aware this has happened.
When master_state and proximity_state are both high again the counting will start again
BUT not from zero this time. So the led will blink early
So building on my prior assumption. I've modified the loop routine that decides when the interrupts are enabled and disabled.
See how this goes.
const int master = 21; // interrupt 2
const int proximity = 20; // interrupt 3
const int incremental = 3; // interrupt 1
const int ledPin = 12; // injector pin
volatile int counter = 0; // to count 360 degrees
int master_state = 0;
int proximity_state = 0;
volatile float s_o_i = 300; // start of injection
volatile float e_o_i = 360; // end of injection
volatile int n_o_s = 0; // no of strokes
volatile bool fired=0; //SET BY ISR to signal injection has finished
void setup()
{
Serial.begin(9600); // initialize serial communication
pinMode(master, INPUT);
pinMode(proximity, INPUT);
pinMode(incremental, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin,LOW); // so that at start it should not start injecting
attachInterrupt (1, count, RISING); // attach interrupt handler of incremental
noInterrupts(); // turning off the interrupts
}
void count() // ISR
{
if(counter == s_o_i)
{
digitalWrite(ledPin,HIGH); // start injection
}
if(counter == e_o_i)
{
digitalWrite(ledPin,LOW); // stop injection
counter = 0;
fired=1;
}
counter++;
}
bool MPLastState=0; //keeps track of master/proximity
void loop()
{
bool MPThisState=digitalRead(master)&digitalRead(proximity);//high if they're both high
if(fired)
{noInterrupts();// turning off the interrupts until next revolution
fired=0;
counter=0;//belt and braces;
}
if (MPThisState > MPLastState)//Signal has just become positive
{interrupts();
}
MPLastState=MPThisState;
}
const int master = 21; // interrupt 2
const int proximity = 20; // interrupt 3
const int incremental = 3; // interrupt 1
const int ledPin = 12; // injector pin
volatile int counter = 0; // to count 360 degrees
int master_state = 0;
int proximity_state = 0;
volatile float s_o_i = 300; // start of injection
volatile float e_o_i = 360; // end of injection
volatile int n_o_s = 0; // no of strokes
void setup()
{
Serial.begin(9600); // initialize serial communication
pinMode(master, INPUT);
pinMode(proximity, INPUT);
pinMode(incremental, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin,LOW); // so that at start it should not start injecting
attachInterrupt (1, count, RISING); // attach interrupt handler of incremental
}
void count() // ISR
{
if(counter == s_o_i)
{
digitalWrite(ledPin,HIGH); // start injection
}
if(counter == e_o_i)
{
digitalWrite(ledPin,LOW); // stop injection
counter = 0;
}
counter++;
}
void loop()
{
noInterrupts(); // turning off the interrupts
master_state = digitalRead(master);
proximity_state = digitalRead(proximity);
if (master_state == HIGH && proximity_state == HIGH)
{
interrupts(); // turning on the interrupts
}
}
I see that you zero counter at e_o_i.
But the states may still be HIGH, correct?
In shich case the count continues to increment until one or both go low and count is not zero so next time it begins with a head start and early triggers every time.
GoForSmoke:
I see that you zero counter at e_o_i.
But the states may still be HIGH, correct?
In shich case the count continues to increment until one or both go low and count is not zero so next time it begins with a head start and early triggers every time.
NO The count continues until the count function tells it to stop. Counting will not start again until the digitalRead(master)&digitalRead(proximity) TURNS high. Simply still being high will not restart counting. They have to TURN from LOW to HIGH to restart the counter.
GoForSmoke:
I see that you zero counter at e_o_i.
But the states may still be HIGH, correct?
In shich case the count continues to increment until one or both go low and count is not zero so next time it begins with a head start and early triggers every time.
NO The count continues until the count function tells it to stop. Counting will not start again until the digitalRead(master)&digitalRead(proximity) TURNS high. Simply still being high will not restart counting. They have to TURN from LOW to HIGH to restart the counter.
In Pranesh's code, the interrupts are enabled when master and proximity are high. Count is incremented when interrupts are on and pin 3 goes LOW to HIGH. Master and proximity simply need to be HIGH to turn interrupts on, no transition is required.
He has a short time with interrupts disabled from the start of every loop() to the evaluation of master and proximity enabling interrupts, but look at the time slice interrupts stay on. It is maybe less than half the loop() cycle which is why I made the first suggestion in code, leave interrupts on during the whole time proximity is detected to catch all the triggers.
Do we know what drives proximity? I don't recall seeing a circuit or diagram. Maybe it is a Hall sensor detecting a magnet or a gear tooth counter or light detector or direct wire feed. Do you know?
GoForSmoke:
i would zero it whenever proximity or master is LOW and avoid the subtract, compare and addition.
That would get rid of the need to turn interrupts on and off too though the clocks would run then.
The example I gave in answer #9 doesn't turn interrupts on or off. It simply implements a global variable inTheZone to decide whether we're counting or not.
I tried KenF's code but it is not even generating a single pulse now, i think the board's processing speed is slow for this application since the master signal remains on for only 380 microseconds whereas the proximity is on for 27.9 ms (the engine is running at 2 Hz i.e a master signal comes every 0.5 second), so the whole comparison and stuff has to happen in a very small piece of time.
Is it the way i think or something else?
pranesh:
I tried KenF's code but it is not even generating a single pulse now, i think the board's processing speed is slow for this application since the master signal remains on for only 380 microseconds whereas the proximity is on for 27.9 ms
You may need to use an interrupt to detect the master signal.
But I am now unclear about the logic of the system. You are counting pulses when both master and proximity are HIGH. Does that mean you only want to count pulses for the 380 usec duration of the master signal. That may mean using a CHANGE interrupt for the master signal.
I may well be wrong, but I get the feeling that it would do no harm to write out the requirement again from scratch taking account of all that has been said in the various posts so far.