Reducing response time between events

I have a sketch running on my arduino mega that constantly checks the value being returned from 4 different potentiometers. It then checks the value being read against a minimum value I've set in order to determine the next step. To give a better idea, I'll explain a bit about what I have setup and what it is doing:

My circuit has 4 potentiometers, 4 x 5mm leds, 4 RGB LED strips, and the mega. In this setup, each potentiometer has a corresponding 5mm led, and a corresponding led strip that it controls based on the value read within the sketch. So we can say that pot A controls led A and rgb strip A, then B controls B, etc... The response time is very quick when turning "on" or "off a single potentiometer, but gets grossly dragged out when, say, all 4 are being changed rather quickly.

I understand that the arduino can only execute one thing at a time, but I would like to find a more efficient way of running my sketch so that the response time is as low as realistically possible. Another thing to clarify is that I am not a programmer. This sketch is the most code of any sort that I have written. As for the real-world applications of my setup: I am building a play kitchen for my girls, the potentiometers will be used for the cooktop controls, and the 5mm leds to indicate which "burner" is turned on (the rgb light strips).

I appreciate any and all feedback anyone has to give, and will happily take advise on how to improve my arduino programming. Please take a quick look at my sketch and let me know if there's anything I am doing wrong, what I could do better, and how I can reduce the response time between events if at all possible!

int potentiometers[4] {
  0, 1, 2, 3
};

int indicatorLights[4] {
  50, 51, 52, 53
};

int colorTerminals[4] {
  2, 5, 8, 11
};

int brightness = 0;

void setup() {
  Serial.begin(9600);
  for (int i =0; i < 4; i++) {
    pinMode(indicatorLights[i], OUTPUT);
    pinMode(colorTerminals[i], OUTPUT);
  }
}

void ReadPots() {
  for (int i = 0; i < 4; i++) {
    int selectedPot = potentiometers[i];
    int potVal = map(analogRead(selectedPot), 0, 1023, 0, 255);
    int selectedColorTerminal = colorTerminals[i];
    int selectedIndicator = indicatorLights[i];
    int indicatorState = digitalRead(selectedIndicator);
    if (potVal < 20) {
      if ( indicatorState ) {
        TurnOff(selectedIndicator, selectedColorTerminal, indicatorState);
      }
      else if ( !indicatorState ) {
        RemainOff(selectedIndicator, selectedColorTerminal, indicatorState);
      }
    }
    else if (potVal > 20) {
      if ( indicatorState ) {
        RemainOn(selectedIndicator, selectedColorTerminal, indicatorState);
      }
      else if ( !indicatorState ) {
        TurnOn(selectedIndicator, selectedColorTerminal, indicatorState);
      }
    }
  }
}

void TurnOff (int indicator, int colorTerminal, int state) {
  digitalWrite(indicator, !state);
  brightness = 255;
  for (int j = 0; j < 256; j++) {
    analogWrite(colorTerminal, brightness);
    brightness -=1;
    delay(10);
  }
}

void RemainOff (int indicator, int colorTerminal, int state) {
  brightness = 0;
  digitalWrite(indicator, state);
  analogWrite(colorTerminal, brightness);
}

void RemainOn (int indicator, int colorTerminal, int state) {
  brightness = 255;
  digitalWrite(indicator, state);
  analogWrite(colorTerminal, brightness);
}

void TurnOn (int indicator, int colorTerminal, int state) {
  digitalWrite(indicator, !state);
  brightness = 0;
  for (int j = 0; j < 256; j++) {
    analogWrite(colorTerminal, brightness);
    brightness +=1;
    delay(10);
  }
}

void loop() {
  ReadPots();
}

I believe this part is the one that slows down your execution:

  for (int j = 0; j < 256; j++) {
    analogWrite(colorTerminal, brightness);
    brightness +=1;
    delay(10);
  }

256 * 10 = 2560 ms = 2.56 seconds each time you call this.

To verify this, you should add some chronometers in your code. Put the following lines at strategic places in your code, to see the time pass:

Serial.print("Some tag :");
Serial.println(millis());

Of course, you have to replace the "some tag" by a message relevant to the place you add the lines (the name of a function for example).

When you see a great difference between 2 successive printouts means that part is slow.

I think you want to look into state machines for this sort of thing. You want to process all the channels in a short period of time, spending microseconds doing whatever one channel needs before hopping to the next.

I wrote this state-machine driven control up based on your code. It compiles error-free but I'm certain I probably messed something up somewhere.

Give it a look-see and a go.

#define READ_POT_VAL        0
#define TURN_REMAIN_OFF     1
#define TROFF_TURNOFF       2
#define TROFF_REMAINOFF     3
#define TURN_REMAIN_ON      4
#define TRON_REMAINON       5
#define TRON_TURNON         6

#define NUM_CHANNELS        4

#define CHANNEL_A           0   
#define CHANNEL_B           1
#define CHANNEL_C           2
#define CHANNEL_D           3

//state machine initial states for each channel
//all start at READ_POT_VAL
byte
    stateChannel[NUM_CHANNELS] =
    {
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL
    };


int potentiometers[NUM_CHANNELS] 
    {
        0, 1, 2, 3
    };

int indicatorLights[NUM_CHANNELS] 
    {
        50, 51, 52, 53
    };

int colorTerminals[NUM_CHANNELS] 
    {
        2, 5, 8, 11
    };

//used to store 0-255 pot values for state machine to look at later
byte
    PotVals[NUM_CHANNELS];
    

void setup() 
{
    Serial.begin(9600);
    
    for (int i=0; i < NUM_CHANNELS; i++) 
    {
        pinMode(indicatorLights[i], OUTPUT);
        pinMode(colorTerminals[i], OUTPUT);
        
    }//for
    
}//setup

void ReadPots() 
{
    int 
        i;
        
    for( i=0; i<NUM_CHANNELS; i++ )
        PotVals[i] = map(analogRead(potentiometers[i]), 0, 1023, 0, 255);
        
}//ReadPots

void StateMachine( void )
{
    static byte
        Channel = CHANNEL_A,
        bright[NUM_CHANNELS];
    static unsigned long
        timerChannel[NUM_CHANNELS];
    unsigned long
        timeNow;

    switch( stateChannel[Channel] )
    {
        case    READ_POT_VAL:
            if( PotVals[Channel] < 20 )
                stateChannel[Channel] = TURN_REMAIN_OFF;
            else if( PotVals[Channel] >= 20 )
                stateChannel[Channel] = TURN_REMAIN_ON;
                            
        break;
    
        case    TURN_REMAIN_OFF:
            if( digitalRead( indicatorLights[Channel] ) )
            {
                digitalWrite(indicatorLights[Channel], LOW);
                timerChannel[Channel] = millis();
                bright[Channel] = 255;
                stateChannel[Channel] = TROFF_TURNOFF;
            }
            else
                stateChannel[Channel] = TROFF_REMAINOFF;
        break;
    
        case    TROFF_TURNOFF:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;                
            timerChannel[Channel] = timeNow;
            
            bright[Channel]--;
            analogWrite( colorTerminals[Channel], bright[Channel]);                
            if( bright[Channel] == 0 )
            {
                stateChannel[Channel] = READ_POT_VAL;    
                BumpChannel( &Channel );
                
            }//if
            
        break;
        
        case    TROFF_REMAINOFF:
            digitalWrite( indicatorLights[Channel], LOW);
            analogWrite( colorTerminals[Channel], 0);
            stateChannel[Channel] = READ_POT_VAL;
            BumpChannel( &Channel );
            
        break;
    
        case    TURN_REMAIN_ON:
            if( digitalRead( indicatorLights[Channel] ) )
                stateChannel[Channel] = TRON_REMAINON;
            else
            {
                digitalWrite( indicatorLights[Channel], HIGH );
                timerChannel[Channel] = millis();
                bright[Channel] = 0;
                stateChannel[Channel] = TRON_TURNON;
            }//else
                
        break;
        
        case    TRON_REMAINON:
            digitalWrite(indicatorLights[Channel], HIGH);
            analogWrite(colorTerminals[Channel], 255);
            stateChannel[Channel] = READ_POT_VAL;
            BumpChannel( &Channel );        
            
        break;
        
        case    TRON_TURNON:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;
            timerChannel[Channel] = timeNow;
            
            bright[Channel]++;
            analogWrite(colorTerminals[Channel], bright[Channel]);                
            if( bright[Channel] == 255 )
            {
                stateChannel[Channel] = READ_POT_VAL;    
                BumpChannel( &Channel );
                
            }//if
    
        break;
        
    }//switch
    
}//StateMachine

void BumpChannel( byte *Chan )
{
    byte
        ch;
            
    ch = *Chan;
    ch++;
    ch &= 0x03;
    *Chan = ch;
    
}//BumpChannel


void loop() 
{
    ReadPots();
    StateMachine();
    
}//loop

lesept:
I believe this part is the one that slows down your execution:

  for (int j = 0; j < 256; j++) {

analogWrite(colorTerminal, brightness);
    brightness +=1;
    delay(10);
  }



256 * 10 = 2560 ms = 2.56 seconds each time you call this.

To verify this, you should add some chronometers in your code. Put the following lines at strategic places in your code, to see the time pass:


Serial.print("Some tag :");
Serial.println(millis());



Of course, you have to replace the "some tag" by a message relevant to the place you add the lines (the name of a function for example). 

When you see a great difference between 2 successive printouts means that part is slow.

Thank you very much for pointing this out. It is something I will admit that i hadn't even considered (delaying 10 for each iteration of the for loop). That definitely explains a lot and I'm glad you caught this. I will adjust and see how the result works out.

Blackfin:
I think you want to look into state machines for this sort of thing. You want to process all the channels in a short period of time, spending microseconds doing whatever one channel needs before hopping to the next.

I wrote this state-machine driven control up based on your code. It compiles error-free but I'm certain I probably messed something up somewhere.

Give it a look-see and a go.

#define READ_POT_VAL        0

#define TURN_REMAIN_OFF    1
#define TROFF_TURNOFF      2
#define TROFF_REMAINOFF    3
#define TURN_REMAIN_ON      4
#define TRON_REMAINON      5
#define TRON_TURNON        6

#define NUM_CHANNELS        4

#define CHANNEL_A          0 
#define CHANNEL_B          1
#define CHANNEL_C          2
#define CHANNEL_D          3

//state machine initial states for each channel
//all start at READ_POT_VAL
byte
    stateChannel[NUM_CHANNELS] =
    {
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL
    };

int potentiometers[NUM_CHANNELS]
    {
        0, 1, 2, 3
    };

int indicatorLights[NUM_CHANNELS]
    {
        50, 51, 52, 53
    };

int colorTerminals[NUM_CHANNELS]
    {
        2, 5, 8, 11
    };

//used to store 0-255 pot values for state machine to look at later
byte
    PotVals[NUM_CHANNELS];

void setup()
{
    Serial.begin(9600);
   
    for (int i=0; i < NUM_CHANNELS; i++)
    {
        pinMode(indicatorLights[i], OUTPUT);
        pinMode(colorTerminals[i], OUTPUT);
       
    }//for
   
}//setup

void ReadPots()
{
    int
        i;
       
    for( i=0; i<NUM_CHANNELS; i++ )
        PotVals[i] = map(analogRead(potentiometers[i]), 0, 1023, 0, 255);
       
}//ReadPots

void StateMachine( void )
{
    static byte
        Channel = CHANNEL_A,
        bright[NUM_CHANNELS];
    static unsigned long
        timerChannel[NUM_CHANNELS];
    unsigned long
        timeNow;

switch( stateChannel[Channel] )
    {
        case    READ_POT_VAL:
            if( PotVals[Channel] < 20 )
                stateChannel[Channel] = TURN_REMAIN_OFF;
            else if( PotVals[Channel] >= 20 )
                stateChannel[Channel] = TURN_REMAIN_ON;
                           
        break;
   
        case    TURN_REMAIN_OFF:
            if( digitalRead( indicatorLights[Channel] ) )
            {
                digitalWrite(indicatorLights[Channel], LOW);
                timerChannel[Channel] = millis();
                bright[Channel] = 255;
                stateChannel[Channel] = TROFF_TURNOFF;
            }
            else
                stateChannel[Channel] = TROFF_REMAINOFF;
        break;
   
        case    TROFF_TURNOFF:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;               
            timerChannel[Channel] = timeNow;
           
            bright[Channel]--;
            analogWrite( colorTerminals[Channel], bright[Channel]);               
            if( bright[Channel] == 0 )
            {
                stateChannel[Channel] = READ_POT_VAL;   
                BumpChannel( &Channel );
               
            }//if
           
        break;
       
        case    TROFF_REMAINOFF:
            digitalWrite( indicatorLights[Channel], LOW);
            analogWrite( colorTerminals[Channel], 0);
            stateChannel[Channel] = READ_POT_VAL;
            BumpChannel( &Channel );
           
        break;
   
        case    TURN_REMAIN_ON:
            if( digitalRead( indicatorLights[Channel] ) )
                stateChannel[Channel] = TRON_REMAINON;
            else
            {
                digitalWrite( indicatorLights[Channel], HIGH );
                timerChannel[Channel] = millis();
                bright[Channel] = 0;
                stateChannel[Channel] = TRON_TURNON;
            }//else
               
        break;
       
        case    TRON_REMAINON:
            digitalWrite(indicatorLights[Channel], HIGH);
            analogWrite(colorTerminals[Channel], 255);
            stateChannel[Channel] = READ_POT_VAL;
            BumpChannel( &Channel );       
           
        break;
       
        case    TRON_TURNON:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;
            timerChannel[Channel] = timeNow;
           
            bright[Channel]++;
            analogWrite(colorTerminals[Channel], bright[Channel]);               
            if( bright[Channel] == 255 )
            {
                stateChannel[Channel] = READ_POT_VAL;   
                BumpChannel( &Channel );
               
            }//if
   
        break;
       
    }//switch
   
}//StateMachine

void BumpChannel( byte *Chan )
{
    byte
        ch;
           
    ch = *Chan;
    ch++;
    ch &= 0x03;
    *Chan = ch;
   
}//BumpChannel

void loop()
{
    ReadPots();
    StateMachine();
   
}//loop

Thank you so much for the time you took to throw all of that together! I will definitely have to do some research on using state machines with the arduino (as mentioned in my post, I'm new to programming) and how I can utilize your example. It may take some time because honestly, it is a little overwhelming looking at all of that! Luckily I'm a quick learner so hopefully I can go over your code to see what changes were made and how they change the operation of the program I am currently running. I love a good challenge, and this looks like you've served me up a good one! Thanks a ton for your feedback! I'll be sure to let you know what progress I can make with this!

yeahWhateverMan:
Thank you so much for the time you took to throw all of that together! I will definitely have to do some research on using state machines with the arduino (as mentioned in my post, I'm new to programming) and how I can utilize your example. It may take some time because honestly, it is a little overwhelming looking at all of that! Luckily I'm a quick learner so hopefully I can go over your code to see what changes were made and how they change the operation of the program I am currently running. I love a good challenge, and this looks like you've served me up a good one! Thanks a ton for your feedback! I'll be sure to let you know what progress I can make with this!

Well, I hope it works! I kind of rushed it; even if it doesn't work first time, the idea is to see what one person's interpretation of a state machine is. If it works as I think it should, the results should be pretty cool :slight_smile:

But it's not as complex as it looks. If you look, you'll see I just sort of copy-pasted and made minor changes to the code you'd already written. It's just done in a format that allows the processor to do many little bits for each channel many times per unit time rather than spending a lot of time focused on just one channel.

PM me if you have questions.

Blackfin:
Well, I hope it works! I kind of rushed it; even if it doesn't work first time, the idea is to see what one person's interpretation of a state machine is. If it works as I think it should, the results should be pretty cool :slight_smile:

But it's not as complex as it looks. If you look, you'll see I just sort of copy-pasted and made minor changes to the code you'd already written. It's just done in a format that allows the processor to do many little bits for each channel many times per unit time rather than spending a lot of time focused on just one channel.

PM me if you have questions.

The code you provided works brilliantly! There's not a significant difference in operation from the sketch I wrote, but there is a noticeable difference nonetheless. It appears to be slightly faster when turning all 4 pots on or off, so that's an automatic hats off to you! I did try modifying my sketch to reduce the 10 ms delay between iterations of the for loop that increases or decreases the brightness and it doesn't accomplish what I am looking for. Faster: absolutely. But the desired effect I'm after is that of an electric range heating up or cooling down. Your code accomplishes that in a more natural feeling way (if that makes sense). I can't thank you enough for your help, and I will definitely be in contact if I have any questions about the code. For now, I have some lights to play with.

yeahWhateverMan:
The code you provided works brilliantly! There's not a significant difference in operation from the sketch I wrote...

This bothered me because I really expected it to improve the timing. So I went back and looked at the code. I realized I'd made a blunder, not even following my own rule about doing just a little bit for each channel, each pass.

So I re-wrote some of it. Please try this one to see if there's an improvement:

#define READ_POT_VAL        0
#define TURN_REMAIN_OFF     1
#define TROFF_TURNOFF       2
#define TROFF_REMAINOFF     3
#define TURN_REMAIN_ON      4
#define TRON_REMAINON       5
#define TRON_TURNON         6

#define NUM_CHANNELS        4

#define CHANNEL_A           0   
#define CHANNEL_B           1
#define CHANNEL_C           2
#define CHANNEL_D           3

//state machine initial states for each channel
//all start at READ_POT_VAL
byte
    stateChannel[NUM_CHANNELS] =
    {
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL
    };


int potentiometers[NUM_CHANNELS] 
    {
        0, 1, 2, 3
    };

int indicatorLights[NUM_CHANNELS] 
    {
        50, 51, 52, 53
    };

int colorTerminals[NUM_CHANNELS] 
    {
        2, 5, 8, 11
    };

//used to store 0-255 pot values for state machine to look at later
byte
    PotVals[NUM_CHANNELS];
    

void setup() 
{
    Serial.begin(9600);
    
    for (int i=0; i < NUM_CHANNELS; i++) 
    {
        pinMode(indicatorLights[i], OUTPUT);
        pinMode(colorTerminals[i], OUTPUT);
        
    }//for
    
}//setup

void StateMachine( void )
{
    static byte
        Channel = CHANNEL_A,
        bright[NUM_CHANNELS];
    static unsigned long
        timerChannel[NUM_CHANNELS];
    unsigned long
        timeNow;

    switch( stateChannel[Channel] )
    {
        case    READ_POT_VAL:
            PotVals[Channel] = map(analogRead(potentiometers[Channel]), 0, 1023, 0, 255);
            //
            if( PotVals[Channel] < 20 )
                stateChannel[Channel] = TURN_REMAIN_OFF;
            else if( PotVals[Channel] >= 20 )
                stateChannel[Channel] = TURN_REMAIN_ON;

            BumpChannel( &Channel );
            
        break;
    
        case    TURN_REMAIN_OFF:
            if( digitalRead( indicatorLights[Channel] ) )
            {
                digitalWrite(indicatorLights[Channel], LOW);
                timerChannel[Channel] = millis();
                bright[Channel] = 255;
                stateChannel[Channel] = TROFF_TURNOFF;
            }
            else
                stateChannel[Channel] = TROFF_REMAINOFF;
                
            BumpChannel( &Channel );
        break;
    
        case    TROFF_TURNOFF:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;                
            timerChannel[Channel] = timeNow;
            
            bright[Channel]--;
            analogWrite( colorTerminals[Channel], bright[Channel]);                
            if( bright[Channel] == 0 )
                stateChannel[Channel] = READ_POT_VAL;    
            
            BumpChannel( &Channel );

        break;
        
        case    TROFF_REMAINOFF:
            digitalWrite( indicatorLights[Channel], LOW);
            analogWrite( colorTerminals[Channel], 0);
            stateChannel[Channel] = READ_POT_VAL;
            BumpChannel( &Channel );
            
        break;
    
        case    TURN_REMAIN_ON:
            if( digitalRead( indicatorLights[Channel] ) )
                stateChannel[Channel] = TRON_REMAINON;
            else
            {
                digitalWrite( indicatorLights[Channel], HIGH );
                timerChannel[Channel] = millis();
                bright[Channel] = 0;
                stateChannel[Channel] = TRON_TURNON;
            }//else

            BumpChannel( &Channel );
                            
        break;
        
        case    TRON_REMAINON:
            digitalWrite(indicatorLights[Channel], HIGH);
            analogWrite(colorTerminals[Channel], 255);
            stateChannel[Channel] = READ_POT_VAL;
            //
            BumpChannel( &Channel );        
            
        break;
        
        case    TRON_TURNON:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;
            timerChannel[Channel] = timeNow;
            
            bright[Channel]++;
            analogWrite(colorTerminals[Channel], bright[Channel]);                
            if( bright[Channel] == 255 )
                stateChannel[Channel] = READ_POT_VAL;    
            //
            BumpChannel( &Channel );
    
        break;
        
    }//switch
    
}//StateMachine

void BumpChannel( byte *Chan )
{
    byte
        ch;
            
    ch = *Chan;
    //
    ch++;
    if( ch == NUM_CHANNELS )
        ch = 0;
    //  
    *Chan = ch;
    
}//BumpChannel


void loop() 
{
    StateMachine();
    
}//loop

Blackfin:
This bothered me because I really expected it to improve the timing. So I went back and looked at the code. I realized I'd made a blunder, not even following my own rule about doing just a little bit for each channel, each pass.

So I re-wrote some of it. Please try this one to see if there's an improvement:

#define READ_POT_VAL        0

#define TURN_REMAIN_OFF    1
#define TROFF_TURNOFF      2
#define TROFF_REMAINOFF    3
#define TURN_REMAIN_ON      4
#define TRON_REMAINON      5
#define TRON_TURNON        6

#define NUM_CHANNELS        4

#define CHANNEL_A          0 
#define CHANNEL_B          1
#define CHANNEL_C          2
#define CHANNEL_D          3

//state machine initial states for each channel
//all start at READ_POT_VAL
byte
    stateChannel[NUM_CHANNELS] =
    {
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL,
        READ_POT_VAL
    };

int potentiometers[NUM_CHANNELS]
    {
        0, 1, 2, 3
    };

int indicatorLights[NUM_CHANNELS]
    {
        50, 51, 52, 53
    };

int colorTerminals[NUM_CHANNELS]
    {
        2, 5, 8, 11
    };

//used to store 0-255 pot values for state machine to look at later
byte
    PotVals[NUM_CHANNELS];

void setup()
{
    Serial.begin(9600);
   
    for (int i=0; i < NUM_CHANNELS; i++)
    {
        pinMode(indicatorLights[i], OUTPUT);
        pinMode(colorTerminals[i], OUTPUT);
       
    }//for
   
}//setup

void StateMachine( void )
{
    static byte
        Channel = CHANNEL_A,
        bright[NUM_CHANNELS];
    static unsigned long
        timerChannel[NUM_CHANNELS];
    unsigned long
        timeNow;

switch( stateChannel[Channel] )
    {
        case    READ_POT_VAL:
            PotVals[Channel] = map(analogRead(potentiometers[Channel]), 0, 1023, 0, 255);
            //
            if( PotVals[Channel] < 20 )
                stateChannel[Channel] = TURN_REMAIN_OFF;
            else if( PotVals[Channel] >= 20 )
                stateChannel[Channel] = TURN_REMAIN_ON;

BumpChannel( &Channel );
           
        break;
   
        case    TURN_REMAIN_OFF:
            if( digitalRead( indicatorLights[Channel] ) )
            {
                digitalWrite(indicatorLights[Channel], LOW);
                timerChannel[Channel] = millis();
                bright[Channel] = 255;
                stateChannel[Channel] = TROFF_TURNOFF;
            }
            else
                stateChannel[Channel] = TROFF_REMAINOFF;
               
            BumpChannel( &Channel );
        break;
   
        case    TROFF_TURNOFF:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;               
            timerChannel[Channel] = timeNow;
           
            bright[Channel]--;
            analogWrite( colorTerminals[Channel], bright[Channel]);               
            if( bright[Channel] == 0 )
                stateChannel[Channel] = READ_POT_VAL;   
           
            BumpChannel( &Channel );

break;
       
        case    TROFF_REMAINOFF:
            digitalWrite( indicatorLights[Channel], LOW);
            analogWrite( colorTerminals[Channel], 0);
            stateChannel[Channel] = READ_POT_VAL;
            BumpChannel( &Channel );
           
        break;
   
        case    TURN_REMAIN_ON:
            if( digitalRead( indicatorLights[Channel] ) )
                stateChannel[Channel] = TRON_REMAINON;
            else
            {
                digitalWrite( indicatorLights[Channel], HIGH );
                timerChannel[Channel] = millis();
                bright[Channel] = 0;
                stateChannel[Channel] = TRON_TURNON;
            }//else

BumpChannel( &Channel );
                           
        break;
       
        case    TRON_REMAINON:
            digitalWrite(indicatorLights[Channel], HIGH);
            analogWrite(colorTerminals[Channel], 255);
            stateChannel[Channel] = READ_POT_VAL;
            //
            BumpChannel( &Channel );       
           
        break;
       
        case    TRON_TURNON:
            timeNow = millis();
            if( (timeNow - timerChannel[Channel]) < 10 )
                return;
            timerChannel[Channel] = timeNow;
           
            bright[Channel]++;
            analogWrite(colorTerminals[Channel], bright[Channel]);               
            if( bright[Channel] == 255 )
                stateChannel[Channel] = READ_POT_VAL;   
            //
            BumpChannel( &Channel );
   
        break;
       
    }//switch
   
}//StateMachine

void BumpChannel( byte *Chan )
{
    byte
        ch;
           
    ch = *Chan;
    //
    ch++;
    if( ch == NUM_CHANNELS )
        ch = 0;
    // 
    *Chan = ch;
   
}//BumpChannel

void loop()
{
    StateMachine();
   
}//loop

Holy F*ing Fk! That's all I can say really! You're an official god in my books. Is there a way I can send you a video of how it is working? I doubt you'd be as speachless as I was when I first saw it in action, but I think you'd be happy with how amazing your code has made this! Honestly I cannot thank you enough, this is so awesome!

So glad to hear! I'd love to see it; perhaps you could create an account at Imgur (if you don't already have one) or Youtube and upload a video there.

<sigh> One more improvement for you:

Replace the TR_OFF state code:

case    TROFF_TURNOFF:
    timeNow = millis();
    if( (timeNow - timerChannel[Channel]) < 10 )
        return;                
    timerChannel[Channel] = timeNow;
            
    bright[Channel]--;
    analogWrite( colorTerminals[Channel], bright[Channel]);                
    if( bright[Channel] == 0 )
        stateChannel[Channel] = READ_POT_VAL;    
            
    BumpChannel( &Channel );

break;

with

case    TROFF_TURNOFF:
    timeNow = millis();
    if( (timeNow - timerChannel[Channel]) >= 10 )
    {
        timerChannel[Channel] = timeNow;
                
        bright[Channel]--;
        analogWrite( colorTerminals[Channel], bright[Channel]);                
        if( bright[Channel] == 0 )
            stateChannel[Channel] = READ_POT_VAL;    
    }//if
    //            
    BumpChannel( &Channel );

break;

:slight_smile:

Blackfin:
<sigh> One more improvement for you:

Replace the TR_OFF state code:

case    TROFF_TURNOFF:

timeNow = millis();
    if( (timeNow - timerChannel[Channel]) < 10 )
        return;               
    timerChannel[Channel] = timeNow;
           
    bright[Channel]--;
    analogWrite( colorTerminals[Channel], bright[Channel]);               
    if( bright[Channel] == 0 )
        stateChannel[Channel] = READ_POT_VAL;   
           
    BumpChannel( &Channel );

break;




with 



case    TROFF_TURNOFF:
    timeNow = millis();
    if( (timeNow - timerChannel[Channel]) >= 10 )
    {
        timerChannel[Channel] = timeNow;
               
        bright[Channel]--;
        analogWrite( colorTerminals[Channel], bright[Channel]);               
        if( bright[Channel] == 0 )
            stateChannel[Channel] = READ_POT_VAL;   
    }//if
    //           
    BumpChannel( &Channel );

break;




:)

This is awesome. I barely noticed the delay in turning off until I ran this fix. Awesome stuff, I really appreciate what you've done here. My kids are not going to notice these little details, but I'm one of those "little details count" kind of guys. I am very glad that I came here for help and was lucky enough to have you make this infinitely better.

I took a couple of videos, one with the arduino running my original sketch, and one running the sketch you posted, that way you can see the tremendous difference you've made. As soon as they're uploaded to onedrive I will send you a link!

yeahWhateverMan:
when, say, all 4 are being changed rather quickly.

From a purely physical point of view, I'm trying to picture how that would happen in this project?

yeahWhateverMan:
This is awesome. I barely noticed the delay in turning off until I ran this fix. Awesome stuff, I really appreciate what you've done here. My kids are not going to notice these little details, but I'm one of those "little details count" kind of guys. I am very glad that I came here for help and was lucky enough to have you make this infinitely better.

I took a couple of videos, one with the arduino running my original sketch, and one running the sketch you posted, that way you can see the tremendous difference you've made. As soon as they're uploaded to onedrive I will send you a link!

:slight_smile:

There's room for improvement (imo); for example, the brightness of the LEDs when the stove is "on" could be set in relation to the pot value so if you turn it on a little past "20" the LEDs come on just a bit up to full brightness when the pot is cranked. A little sound (bacon frying type sound, e.g) would be neat too :slight_smile:

Very cool project BTW. I hope your kids enjoy it.

I definitely agree, there's always room for improvement! The very first sketch that I wrote for this actually just mapped the analogRead from the pots and regurgitated that value to the output. But after playing around with my own electric range, I couldn't actually see a difference in brightness between heat settings when the element was fully heated, the only difference was how often the element would switch between "on" and "off" to maintain the target temp. This is what inspired my approach here, with the led strips gradually increasing brightness when coming on and vice versa. I figured it could do without the constant switching on and off but it may be a feature I will look to add later on. I also do plan on adding sound with the cooktop at some point, though I haven't got around to any planning yet on how or what sounds to include.

My primary goal is to make the entire kitchen as interactive and engaging as possible. I plan on adding realistic interactive features to each "appliance". At some point, I would like to add in some educational features as well that will encourage the kids to learn as they play. But I'll take one victory at a time. I really can't thank you enough for your help making this part work as I had imagined!

Now as promised, here is a link to the video of my prototype running my original sketch:
https://1drv.ms/v/s!As_B8CkuHh6zkWYt_Mrd-cO3oofj

And running your code:
https://1drv.ms/v/s!As_B8CkuHh6zkWgmAzi38lSb_hZw

I uploaded a few clips so I'm not 100% sure if this second one was taken before or after the improvement to the TROFF code, but regardless you will notice a striking improvement from the original code!

arduin_ologist:
From a purely physical point of view, I'm trying to picture how that would happen in this project?

If you take a peek at the clips I shared (links in my last comment to Blackfin) then you will see what I was referring to, and I'm sure you will see how this affects the overall operation. Was it a completely necessary change? maybe not, but why settle for less? My daughters are both quite familiar with how our real cooking appliances work because we spend a lot of time in the kitchen together preparing and cooking our meals.

I'd like them to be able to experience something as close to reality as possible to keep them engaged and see what their imaginations can "cook-up". I wouldn't spend the time and money on this project that I have and will continue to invest, just to settle for "good enough". Another important point is that this project is being build for both kids to play with and enjoy together, ideally encouraging and further developing their sense of team work and cooperation. With that in mind, it should become immediately apparent that it is actually very likely 2+ controls will be used at the same time, necessitating a faster response time for their satisfaction.

yeahWhateverMan:
My primary goal is to make the entire kitchen as interactive and engaging as possible. I plan on adding realistic interactive features to each "appliance". At some point, I would like to add in some educational features as well that will encourage the kids to learn as they play. But I'll take one victory at a time. I really can't thank you enough for your help making this part work as I had imagined!

Now as promised, here is a link to the video of my prototype running my original sketch:
https://1drv.ms/v/s!As_B8CkuHh6zkWYt_Mrd-cO3oofj

And running your code:
https://1drv.ms/v/s!As_B8CkuHh6zkWgmAzi38lSb_hZw

I uploaded a few clips so I'm not 100% sure if this second one was taken before or after the improvement to the TROFF code, but regardless you will notice a striking improvement from the original code!

Looks great. Your girls are going to love it :slight_smile: