I am trying to run this code on a Mega but get a 0 return from the newCycle serialPrint test and it doesnt read the PWM signal. I cant see what's wrong?
const byte fuelin = 44;
const byte fuelout = A6;
volatile unsigned long riseTime = 0;
volatile unsigned long lowTime = 0;
volatile unsigned long highTime = 0;
volatile bool newCycle = false;
void risingEdgeISR();
void fallingEdgeISR();
void setup() {
Serial.begin(9600);
pinMode(fuelin, INPUT);
pinMode(fuelout, OUTPUT);
attachInterrupt(digitalPinToInterrupt(fuelin), risingEdgeISR, RISING);
attachInterrupt(digitalPinToInterrupt(fuelin), fallingEdgeISR, FALLING);
}
void loop(){//change to fuel later
Serial.print(newCycle);
if (newCycle) {
noInterrupts(); // Prevent variable changes during read
unsigned long hTime = highTime;
unsigned long lTime = lowTime;
newCycle = false;
interrupts();
// Calculate duty cycle
float dutyCycle = 0.0;
if (hTime + lTime > 0) {
dutyCycle = (float)hTime / (hTime + lTime);
}
// Map duty cycle to PWM output
int outputValue = (int)(dutyCycle * 255.0);
analogWrite(fuelout, outputValue);
// Debug output
Serial.print("Duty Cycle: ");
Serial.print(dutyCycle * 100.0);
Serial.print("% | PWM Output Value: ");
Serial.println(outputValue);
}
}
// ISR for rising edge
void risingEdgeISR() {
unsigned long now = micros();
lowTime = now - (riseTime + highTime); // Time between last high end and new rise
riseTime = now;
}
// ISR for falling edge
void fallingEdgeISR() {
unsigned long now = micros();
highTime = now - riseTime;
newCycle = true; // Mark that we have a complete cycle
}
Pin 44 is the main problem: on the Mega, only pins 2, 3, 18, 19, 20 and 21 have external interrupts. The Mega variant file in the Arduino AVR core maps every other pin to NOT_AN_INTERRUPT, so both attachInterrupt calls silently do nothing and newCycle stays 0 forever. There is a second issue: two attachInterrupt calls on the same pin do not run side by side - the core stores exactly one callback per interrupt (intFunc[] in WInterrupts.c), so the second call replaces the first. Move the signal to one of the six interrupt pins and use a single ISR on CHANGE that reads the pin state to tell rising from falling edges.
I'm not sure this will work. If I remember correctly you can have one, and only one, of RISING, FALLING or CHANGE on an interrupt pin. (I think there is LOW and HIGH also). You can't have two of them on the same pin.
So I think you need to use CHANGE, and you will need to check the pin level in the interrupt code to decide what action to take.
Another option is to setup a handlers for both rising and falling interrupts, but starting with enabling only one of it and switch to another one at the end of the handler itself.
Based on Mega pin number (44) I suppose that it is an Arduino analogWrite() output with pwm freq below 1Khz. So the measurement the pwm freq and duty is definitely a possible and a not a very complex task.
Let us try to prove/disprove your above proposition:
1. Let us build the following circuit (Fig-1) where the 1 Hz PWM (~50% duty cycle) signal will interrupt the UNO on both rising and falling edges. The intention is to see if the MCU can distinctly detect both Rising Edge and Falling Edge interrupts on the single INT0 pin.
4. Conclusion
The Serial Monitor shows that the MCU is interrupted on both edges of the interrupting signal. But the timestamp shows a time gap of 1 sec between rising and falling interrupts, which should be 500 ms. So, the experiment is ambiguous.
This conclusion does not contradict what @PaulRB wrote; you simply misunderstood him.
The limitation he described is more accurately stated as follows: at any given time, each interrupt source can have only one type of handler attached to it. Now, look at your code—that is exactly what you have. You first set a RISING handler, and then, once the interrupt fires, you set a falling-edge handler. In doing so, the newly assigned handler REPLACES the previous one.
In this respect, your code differs fundamentally from the OP's code: she(he) attempts to attach two handlers to a single interrupt simultaneously—this will not work.
I have not misunderstood @PaulRB at all. I ran the experiment because he mentioned the words "If I remember correctly ..."!
My experiment is giving ambiguous results -- Serial Monitor shows that the MCU is apparently interrupted on both edges, but the timestamp does not support it.
Your method of using interrupts is perfectly correct. The inaccuracy in the results is most likely due to a typo in the code. I haven’t examined it closely—for instance, I don’t recall the AVR timer settings without rereading the docs, so I can’t verify your constants.
If you’d like, I can share my own code for measuring PWM on an Uno; it works without any errors.
That 1 Hz PWM with ~50% duty cycle is correct and can be monitored using onboard led L. The constants have come from the frequency equation, which is also given in the setup() function.
I am unable to undestand why does the Serial Monitor show the message that the MCU is interrupted by both edges. I have measured the time difference using millis() which shows the same 1 sec time difference.
I have expected a time difference of 500 ms -- the time difference between the rising and falling edges!
True, but would that be any more efficient than using CHANGE and reading the pin state in the interrupt code? Probably about the same, I would imagine.
It means that the issue is in the your timer settings and not in interrupt firing. The Monitor shows that the MCU is interrupted by both edges because that’s how it actually is.
The CHANGE interrupt requires tracking the direction of the changes.
When I first tackled this problem, it seemed simpler to use Rising and Failing. And then I just proceeded in the way I had already tried :)
If you need accurate timestamps, use millis() at the Arduino side. The serial monitor relies on the PC telling the serial monitor that there is data which might have a delay.
The following setup (Fig-1) works well using two separate interrupt pins, proving that @PaulRB is right in saying that a single interrupt pin can handle only one triggering mode of interrupt signal.