Dear Forum,
this is my first post because usually I can find easily an answer or some guidance to my Arduino related question but today ... well.
I've tried to make a simple TTL pulse delay circuit whith an Arduino Nano 328. The task is to deliver a pulse after an interrupt has been detected ... so very easy - one would think.
I know that delayMicroseconds is not perfect and one could use some workaround with micros() etc. to wait for a specific amount of time and than do the task but delayMicroseconds() is sufficient in my application.
The problem I've encountered is that the time between the detected interrupt and the pulse varies ( approx 5 µs) which is something we would expect from the accuracy given in the Arduino Reference, HOWEVER, the pulse width itself (20µs) which is also shaped by delayMicroseconds is PERFECT! no variance at all!
Unfortunately the variation between the input pulse and the delayed pulse is not random, for me it looks like something which is just out of sync (like two sine wave with almost the exact frequencies) and that's why my question: can one sync the interrupt calls with the void loop entries?
Here's the code :
int pin = 12; //pulse output
volatile boolean state = false; //value changed by the pulse interrupt routine
volatile int x = 1; //value changed by the button interrupt routine
unsigned long delay_val = 1;
volatile unsigned long button_time = 0;
volatile unsigned long last_button_time = 0;
void setup()
{
noInterrupts();
pinMode(pin, OUTPUT);
digitalWrite(pin,LOW);
attachInterrupt(0, pulse, RISING);
attachInterrupt(1, increment, FALLING);
}
void loop()
{
delay_val = (x*100)-12;
if (state==true){
noInterrupts();
delayMicroseconds(delay_val); //Somehow my Arduino has a 12 µs delay with delayMicroseconds set to 0, here we get rid of it !
digitalWrite(pin, HIGH);
delayMicroseconds(20);
digitalWrite(pin, LOW);
state = ! state;
}
interrupts();
}
void pulse()
{
noInterrupts();
state = ! state;
}
void increment() {
noInterrupts();
button_time = millis();
if (button_time - last_button_time > 250)
{
x++;
last_button_time = button_time;
if(x>20){x=1;}
}
}
//Somehow my Arduino has a 12 µs delay with delayMicroseconds set to 0, here we get rid of it
Using delayMicroseconds(0) is not valid. Lowest number is 3 or 4.
void loop()
{
delay_val = (x*100)-12;
if (state==true){
noInterrupts();
delayMicroseconds(delay_val); //Somehow my Arduino has a 12 µs delay with delayMicroseconds set to 0, here we get rid of it !
digitalWrite(pin, HIGH);
delayMicroseconds(20);
digitalWrite(pin, LOW);
state = ! state;
//move interrupts(); to here?
}
interrupts(); <<<why is this here, instead of up a little farther?
// here, it is being called constantly, instead of only after it
// has been turned off following state == true
}
Dear CrossRoads,
thanks! Indeed delayMicroseconds(0) is weird but what I meant was basically without it so no delay between interrupt and the pulse at all gives me ~12 µs difference with the mentioned variance in between.
Dear holmes4,
thanks for your kind advice. Indeed I wasn't too saving with noInterupts(), BUT: the one in the main loop actually helped quite substantially and reduced the variance.
Regards,
glycylalanin
By the way ... what if I would send the board to sleep very briefly ... might this help?
I've played a little with the instructions given on this page Arduino, Zigbee and Embedded Development: Sleeping Arduino - Part 4 Wake Up Via Internal Timer but with little success ... as I mess around with interrupts again, the pulses are not initiated .... but every help is appreciated ...
Regards,
glycylalanin
I thought maybe it would help to upload a little movie. What you see in Ch1 is the output of my function generator triggering the scope and the Arduino at about 1 kHz. 100µs later there's the pulse which is not exactly 20 µs but who cares. But what you also see is the shifting of the rectangular pulse of a couple of µs.
Regards,
glycylalanin
glycylalanin:
The problem I've encountered is that the time between the detected interrupt and the pulse varies ( approx 5 µs) which is something we would expect from the accuracy given in the Arduino Reference, HOWEVER, the pulse width itself (20µs) which is also shaped by delayMicroseconds is PERFECT! no variance at all!
Others have mentioned the unnecessary use of noInterrupts() which may well affect the values in micros().
If all you want is to start a pulse when an interrupt occurs why not manipulate the pulse pin in the ISR. You can use digitalWrite() which is relatively slow or you can use PORTn (direct port manipulation) which is a little trickier to code but will change the pin in a single instruction. You could also use the ISR to record the micros() value of when the pulse starts and then use code in loop() to check when the pulse should end.
Unfortunately I had no luck to include the micros(). But it works much better though not perfect. There are still those jumps ... Well for me its good enough.
Thank you !
Regards,
glycylylanin
If that doesn't give sufficiently accurate pulses you could use the first ISR to start one of the hardware Timers which would trigger another interrupt when the pulse duration expires.