Alternative solution to millis() not running during long ISRs for AC dimmer

Hello everyone, I am running into an issue where millis() does not update during my long delayed ISRs. I did a bunch of research and all posts seem to tell me to offload the processing to outside of the ISR. I did that and the total timing becomes correct, but the output waveform is slowly becomes off course in relation to the zero crossing wave. So I have two versions of the code: one that performs the AC dimming correctly power-wise but the total time is incorrect, and another that does not perform the AC dimming correctly power-wise but the total time is incorrect. For example, I want the motor to run at .2 for 5s and then 3 for 5s, then 7 for 5s. Version one would change the speed of the motor correctly but would last more than 15s (depending on the delay in the ISR). Version two would not change the speed of the motor correctly but the whole thing would end in 15s (which is what I want). Please assume the hardware is correct, I have a working zero-detection circuit with a triac and optoisolator. Ideally I would like to stick with the second version of the code:

First version:
#include <digitalWriteFast.h>

int timeframes[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
float percent[]{.1,.1,.1,.1,.1,8,8,8,8,8,3,3,3,3,3};
int timeran = 15; //each int is 2 bytes

//dont touch stuff below unless you have to//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define AC_LOAD 7 //Output to Opto Triac pin

//Calculations / variables

const int timePerCycle = 1/60; //time in us
const int timeZeroCrossing = 1/2timePerCycle1000; //~8333us
volatile int timePerStep = timeZeroCrossing/100;
volatile unsigned long curTime = 0;
volatile int ISRcounter = 0;

void setup()
{
pinModeFast(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(digitalPinToInterrupt(2), zero_cross_change, CHANGE);
}

//the interrupt function must take no parameters and return nothing
void zero_cross() //function to be fired at the zero crossing to dim the light
{

/int dimtime = (timePerStepdimming); //dimming = % of max speed
if(once){
delayMicroseconds(8287/2); // Wait till firing the triac
once = 1;
}
else{
delayMicroseconds(500);
}
digitalWriteFast(AC_LOAD, HIGH); // Fire the triac
delayMicroseconds(8287); // Triac on propogation delay
digitalWriteFast(AC_LOAD, LOW); // No longer trigger the triac (the next zero crossing will swith it off)
delayMicroseconds(500);
digitalWriteFast(AC_LOAD, HIGH);
delayMicroseconds(8287/2);
*/
}

void zero_cross_change(){

//if(((curTime > 1501) && (curTime<2501))||((curTime > 3001) && (curTime<4001))||((curTime > 5000) && (curTime<6000))||((curTime > 16001) && (curTime<16500))){
//if(curTime>1000 && curTime <7999){
if((curTime<(timeframes[ISRcounter]1000)) && ISRcounter <=timeran){
int delaytime = 833.33
percent[ISRcounter];
digitalWriteFast(AC_LOAD,HIGH);
delayMicroseconds((8333-(delaytime/2))/2);
digitalWriteFast(AC_LOAD, LOW);
delayMicroseconds(delaytime-4); //4us threshold to run this instruction
digitalWriteFast(AC_LOAD, HIGH);
}

// else if(curTime > 8000 && curTime < 16000){
// digitalWriteFast(AC_LOAD, LOW);
// }

else{
ISRcounter++;
digitalWriteFast(AC_LOAD, HIGH);
}
}

void loop() {
curTime = millis();
}

Second version:
#include <digitalWriteFast.h>

int timeframes[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
float percent[]{.1,.1,4,4,4,4,4,4,4,4,.2,.2,.2,.2,.2};
int timeran = 15; //each int is 2 bytes

//dont touch stuff below unless you have to//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define AC_LOAD 7 //Output to Opto Triac pin

//Calculations / variables

const int timePerCycle = 1/60; //time in us
const int timeZeroCrossing = 1/2timePerCycle1000; //~8333us
volatile int timePerStep = timeZeroCrossing/100;
volatile unsigned long curTime = 0;
volatile int ISRcounter = 0;
bool nOPFlag = 0;
bool highFlag = 0;

void setup()
{
pinModeFast(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(digitalPinToInterrupt(2), zero_cross_change, CHANGE);
}

/*void zero_cross() //function to be fired at the zero crossing to dim the light
{

/int dimtime = (timePerStepdimming); //dimming = % of max speed
if(once){
delayMicroseconds(8287/2); // Wait till firing the triac
once = 1;
}
else{
delayMicroseconds(500);
}
digitalWriteFast(AC_LOAD, HIGH); // Fire the triac
delayMicroseconds(8287); // Triac on propogation delay
digitalWriteFast(AC_LOAD, LOW); // No longer trigger the triac (the next zero crossing will swith it off)
delayMicroseconds(500);
digitalWriteFast(AC_LOAD, HIGH);
delayMicroseconds(8287/2);

}*/

//interrupt
void zero_cross_change(){

if((curTime<(timeframes[ISRcounter]*1000000)) && ISRcounter < timeran){
nOPFlag = 1;
}

else if(ISRcounter < timeran){
nOPFlag = 0;
ISRcounter++;
}
}

void normalOP(){
int delaytime = 833.333*percent[ISRcounter];
digitalWriteFast(AC_LOAD,HIGH);
delayMicroseconds((8333.333-(delaytime/2))/2);
digitalWriteFast(AC_LOAD, LOW);
delayMicroseconds(delaytime);
digitalWriteFast(AC_LOAD, HIGH);
}

void ending(){
digitalWriteFast(AC_LOAD, HIGH);
}

void loop() {
curTime = micros();
if(nOPFlag==1){
{
normalOP();
}
}
if(nOPFlag==0){
ending();
}
}

You can use a hardware timer as demonstrated here.

Edit:
For even more optimization, replace digitalWrite() in the linked code with Direct Port Manipulation.

You have several calculations where you appear to want something other than a whole number - but you use data type int, which will only provide -32786 to 32767.
Try using data type float instead. You must still use whole numbers for delay() and delayMicroseconds() tho.

Please read the how to use this forum sticky, specifically point #7 about posting code using code tags. Next modifiy your post and add the code tags.

in this SE answer by me are two sketches. one with TimerOne library, second with Timer1 registers.

Alternative solution to millis() not running during long ISRs for AC dimmer

There should not be a long ISR. If an ISR takes even 100 microsecs to complete it would long.

...R

all the above.
Rethink how youre collecting that input and read about best practices for interrupts.