delay timings not working correctly

I’m testing a sketch to use a Micro Pro (32U4) to send characters to my pc with the keypress function.

I’m using an example from

I’m setting LONG delays (tens of seconds) so I can see each stage. But the events are happening much faster than I expect.

So I have a delay of 50 seconds after the “run” command before entering “notepad.exe” - but it launches almost immediately.

I cant see why the delays are not working properly - any ideas?

Sketch attached

sketch_jun17a.ino (4.86 KB)

Please insert your code in your post; you're missing out on people that use cell phones.

Read the sticky "how to use this forum", specifically about how to post code.

I can't look at your code right now; a guess is that you use the wrong type for your timing (e.g. int versus unsigned long)'

OP’s code

//sketch to test timer interrupt on Micro Pro:  code copied from earlier work so some unused variables.
// pin assignments
const byte ledPin = 9;   //LED on pin D5 with resistor to GROUND - note this must be a pin that supports PWM
const byte button = 7;   //Button switch is connected between pin 2 and ground. NANO supports "external interrupt" on pins D2, D3
const int analogPin = A10; //wiper connects to Analog pin 10; compiler assigns correct number value automatically

//variables shared between ISR and code must be type volatile.
volatile bool toggleVal=0; // 0=resting, 1=active
volatile bool intFlag = 0; //if ==1 flags that an interrupt has occurred to allow routine to be suspended
volatile int intCount = 0; //count how many times the interrupt has occurred. 

//For interrupt button debounce:
volatile unsigned long lastIntMillis=0; //this is the time of the last interrupt
volatile unsigned long debounceMillis = 500; //dont allow another in less than 0.5 sec

#include "Keyboard.h"

#define DDRFmask 0b00001111 //AND mask, sets MSByte as inputs (=0)
#define PORTFmask 0b11110000 //OR mask, sets MSByte "outputs" high for input-pullup 

class Flasher
{
  int ledPin, flashRate;
  boolean ledValue;
  unsigned long tNow, tLoop=0;

  //constructor - creates a flasher and initialises variables and state
  public:
  Flasher(int pin, int rate) //pin and rate are just local variables
  {
    ledPin = pin;
    pinMode(ledPin, OUTPUT);
    flashRate = rate; //just initialised, speed will be set as soon as update called.
    //intCount used elsewhere also already initialised
  }

  int readA2(){
  //read analog input from potentiometer and process it for rate control
  unsigned long analogVal = analogRead(analogPin)+ 75; //max value is approx 1020, minimum zero so add 75
  //Serial.println(analogVal);
  analogVal*=analogVal;  //square it so high end value has more effect
  analogVal = analogVal>>11; //right shift to bring value back to max 600 min 2 
  int speed = analogVal; //to set a max flash rate of 5msec and slowest about 1 per sec
  return speed;
  }
  
  void update()
  {
    flashRate=readA2();
  if(intCount>=flashRate)
    {
    ledValue=!ledValue;
    digitalWrite(ledPin, ledValue);
    intCount=0; 
    }
  
  }
};  //end of Flasher class

class Fader
{
  int ledPin;
  volatile int fadeValue, change;
  int fadeRate;
  int Nmax, Nmin;

  //constructor - creates a fader and initialises variables and state
  public:
  Fader(int pin, int rate) //pin and rate are just local variables to pass values to instance
  {
    ledPin = pin;
    pinMode(ledPin, OUTPUT);
    fadeValue = 20; //start near minimum
    change = 2; //changes from + to - & vv
    Nmax=245, Nmin=15; //extremes of brightness
    fadeRate=rate;
  }
  
  void update()
  {
   if(intCount>=fadeRate)
   {
   if ((fadeValue <= Nmin)||(fadeValue>=Nmax))
    { change*=-1; }
    fadeValue +=change; 
    analogWrite(ledPin, fadeValue);
    intCount=0;  
    }
  }
};  //end of Fader class

//create an instance of Flasher and Fader
Flasher Flash1(9,200);
Fader Fade1(9,10);  

void keyout()
{
  delay(10000);
  Keyboard.press(KEY_LEFT_GUI);
  Keyboard.press('r');
  delay(10000);
  Keyboard.releaseAll();
  delay(50000);
  Keyboard.print("notepad.exe");
  Keyboard.press(KEY_RETURN);
  delay(10000);
  Keyboard.releaseAll();
  delay(20000);
  Keyboard.print("Test launch and send characters to Notepad");
}

// Interrupt is called once a millisecond, 
ISR(TIMER0_COMPA_vect) 
{
  intCount+=1; 
}

void setup() { 
  //Serial.begin(9600);
  Keyboard.begin();
  //set up button press to generate hardware interrupt
   pinMode (button,INPUT_PULLUP);  //this is our interrupt button
  attachInterrupt(digitalPinToInterrupt(button), isr, FALLING);
   //Timer0 is already used for millis() - we'll just interrupt somewhere
   //in the middle and call the "Compare A" function below
   OCR0A = 0xAF;  // set compare register to #175, interrupt on match
   TIMSK0 |= _BV(OCIE0A);
  //Direct access to registers for port F follows
  DDRF&=DDRFmask;   //to set pins 18-21 as inputs
  PORTF|=PORTFmask; //with input-pullup
}

void isr(){ //this is the hardware interrupt service routine
  //if there has been enough time since the last interrupt then the switch value has been stable, so this isnt a bounce
  if(millis() - lastIntMillis > debounceMillis){
  toggleVal = !toggleVal;
  intFlag = 0;  
  lastIntMillis = millis();  //record time of interrupt
  intCount=0; //count time from last hardware interrupt
  //Direct access to registers for port F follows
  byte switchval=PINF>>4; //read data from PORT F pins 18-21
  switchval&=0111;//mask off msb  
  //Serial.println(switchval, BIN);
  keyout();
  }
}

void loop() {
  // put your main code here, to run repeatedly:
if(toggleVal){Flash1.update();} else { Fade1.update();}
}

…R

That is not going to work - and I'm not sure where to start with the problems.

You should not call a long running function from an ISR. An ISR should be designed to complete very quickly - 100 microsecs would be a long time for an ISR.

As the code has all those delay()s I suspect there is no need to use an interrupt. It seems to be triggered by a button press. There is no need to use an interrupt to detect stuff done by a human because humans are sllooowwwwww.

You should not be mixing millis() and delay() because all the delay()s will probably overrun the interval you are testing with millis(). Use millis() for ALL your timing.

Have a look at how the code is organized in Several Things at a Time

Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

...R

As Robin said this is not going to work

One obvious problem is that the ISR calls the keyout() function which has delay()s in it. The delay() function relies on interrupts to work. Interrupts are automatically disabled while in an ISR. Can you see a problem ?

Even if it did work then this comment
  //if there has been enough time since the last interrupt then the switch value has been stable, so this isnt a bounceis very amusing considering that the delay()s in keyout() add up to 100 seconds.

Thanks for all your help; for some reason I am not getting email updates about this.

Anyway, basically for the part I'm testing I have too much code.

The hardware interrupt is needed but I'll change it and just use it to set a flag.

Of course you are right about interrupt routines should be short.

HeliBob: "One obvious problem is that the ISR calls the keyout() function which has delay()s in it.
The delay() function relies on interrupts to work.
Interrupts are automatically disabled while in an ISR.
Can you see a problem ?"

silly me!

I really dont want to use delays anyway it was just supposed to be a "quick fix" to test thet bit of code.