Monostable jitter

I have been playing tonight with a monostable function.

The idea is to trigger a pulse output based on a 50-2000 Hz interupt driven input. my first simple try was to put the output high in the interupt service and use a delay to provide the pulse width back in the loop but I find the jitter on the pulse width is huge. Is that normal?

next try will be to use milli or micro to time the pulse width, is that a better way?

I have been playing tonight with a monostable function.

It might be useful for others to see your code.
Just a thought.

sorry, its so simple I did not think it worthy,

with this code the pulse width seems to go from about 1 to 10 ms (difficult to get a stable trigger) with a 50 Hz input

//--------------------------------------------------------------
//
// Interrupt driven sketch to output monostable pulse
// Input is on pin digital 2 ie external int0
// Output on pin 7
//
//--------------------------------------------------------------

unsigned long pulsewidth;

void setup()
{
  pulsewidth = 10; 
  
 attachInterrupt(0, freq_fun, FALLING);  //enable int0

  pinMode(7, OUTPUT);
  
 
}

void loop()
{

delay(pulsewidth);              // time pulse width
digitalWrite(7, LOW);    // turn off/LOW

       
}

void freq_fun()
{
 digitalWrite(7, HIGH);   // turn on HIGH
}

//-----------------------------------------------

What happens when the interrupt happens HERE?

delay(pulsewidth); // time pulse width
HERE
digitalWrite(7, LOW); // turn off/LOW

.

sorry larry im really new to this but surly the interupt is external so I cant define or measue when it will happen

An interrupt can happen any time.

If it happens HERE, execution will go to the interrupt routine, set the pin high, return from then interrupt routine then the pin will immediately go LOW.
Hence, you will see a very very short high pulse on the pin, not even close to 10ms.

Jitter. . .

.

ah I think I see your point, the interupt returns to the same point in the loop, I was assuming it returned to the beginning, time for a rethink thanks

It returns to execute the next line of code.
.

as I understand it I cant use a delay in the interupt service so maybe a calibrated loop to hold the output high?

there must be a better way to do it but off to bed now, thanks guys

Use BWD blink without delay techniques to set up timing code.
There is an example that comes with the IDE.
Robin2 Has a great discussion here:

Mr. Gammon also covers the topic here:
http://www.gammon.com.au/blink

Read Nicks interrupt thread here:
http://www.gammon.com.au/interrupts

kev169:
sorry, its so simple I did not think it worthy,

Please edit your post, select the code, and put it between [code][/code] tags.

You can do that by hitting the “Code” icon above the posting area. It is the first icon, with the symbol: </>

Please use code tags.

Read this before posting a programming question

You are randomly turning the pin high, but turning it low after a fixed delay? No wonder it jitters. Try using a timer.

http://www.gammon.com.au/timers

thanks for the replys guys and keeping me right mods, slowly getting the hang of it all. Here is the new code now working with a timer. Comments welcome :slight_smile:

//--------------------------------------------------------------
//
// Interrupt driven sketch to output monostable pulse
// Input is on pin digital 2 ie external int0
// Output on pin 7
// test at 17Hz == 1000rpm == 60ms period 
//
//--------------------------------------------------------------

unsigned long pulsewidth;
unsigned long zerotime; 
unsigned long pulsetime;
volatile boolean flag;

// Interrupt Service Routine (ISR)
void isr ()
{
 flag = true;
 zerotime = millis();
 digitalWrite(7, HIGH);
 }  


void setup()
{
  pulsewidth = 20; //milliseconds 
  zerotime = 0;
  flag = false;
 attachInterrupt(0, isr, FALLING);  //enable int0
  pinMode(7, OUTPUT);
}


void loop(){

    if (flag) {

        pulsetime = millis() - zerotime;
  
        if (pulsetime >= pulsewidth) {
        digitalWrite(7, LOW);    // turn off/LOW
        flag = false;
        zerotime = 0;
      }    
    
    }    

}

kev169:
Comments welcome :slight_smile:

Using millis() for timing of very short time periods is bad, because millis() is not running steadily.
Better use micros() for very short timings.

You are expecting input interrupt to be "50-2000 Hz" as you wrote in the initial posting.

How long do you want the output pulse duration?

Is " pulsewidth = 20; //milliseconds " always?

That will not work. 2000 Hz * 20ms = 40000ms = 40 seconds

You cannot create a total pulse time of 40 seconds within one single second!

Thanks for the tip re using micros instead of mills I will change it.

The pulse duration was just for this test. Next step is to add a pure time delay which will be adjusted as a function of speed or frequency and the pulse duration will be determined by a fraction of the period. In case you had not guessed its basically a steam engine controller with variable valve timing and dwell angles. Currently im working on an rpm meter and the feed to a 4x7 segment display.