Multiple Actions for LEDs

I only intermittently use Arduino to try and run simple sketches for experiments and am struggling with some of the placement of code.

The project I am trying to complete requires two LEDs connected to an Uno board. One LED should remain on and the other should blink at a specific rate. I would also like to control the brightness of both LEDs with a potentiometer, without affecting the blink rate.

I am able to achieve the blinking and dimming separately but not able to implement both using millis(). I can achieve both using delays.

Ultimately, I would like to add two push buttons that would increase or decrease the flash rate of the blinking LED by a measured amount when pressed. I would like to start at 2 Hz and increase/decrease by 1 Hz with each press.

Although I have looked through several tutorials that accomplish some of the blinking and dimming, I am not sure how to implement all three functions in the same sketch. Mostly what happens is one line will overwrite all the others and the LEDs will just blink or dim, but not both.

Is it possible to achieve all of these? Ideally, I would like the module to stand alone without having to re-upload changes from a computer because one will not be available. Any help in re-structuring this code and adding in the button presses would be appreciated.

Current code:

int potPin= A0;             //Declare potPin to be analog pin A0
int LEDPin[]= {9, 10};// Declare LEDPin to be arduino pins 8,9,10,11
int LEDState = 0;         // last state of each led
int readValue;          // Use this variable to read Potentiometer
int writeValue;        // Use this variable for writing to LED
int LEDPin9=9;      // set LEDPin3 as output
int LEDPin10=10;     // set LEDPin5 as output

unsigned long previousMillis = 0;        // will store last time LED was updated


const long interval = 100;           // interval at which to blink (milliseconds)


//boolean LED10State = false; //state variable for LED
//boolean LED9State = false;

void setup() {
 pinMode (LEDPin9, OUTPUT);
 pinMode (LEDPin10, OUTPUT);
      //set potPin to be an input
  for (int i=0; i<=2; i++){    // set each led pin as an output
    pinMode(LEDPin[i], OUTPUT);
  }
  }

void loop() {


 
    unsigned long currentMillis = millis(); //grab current time
    
    readValue = analogRead(potPin);         //Read the voltage on the Potentiometer
    writeValue = map(readValue, 0, 1023, 0, 255);
    
    if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (LEDPin9 == 0) {
      LEDState = writeValue;
    } else {
      LEDState = 0;
    }

    // set the LED with the ledState of the variable:
    analogWrite(LEDPin9, LEDState);
    
    analogWrite(LEDPin10, writeValue);
  }

    
//    //toggle LED10
//    if ((unsigned long)(currentMillis-previousMillisLED10)>= intervalLED10){
//      LED10State =!LED10State; //toggles the state
//      analogWrite(LEDPin10, LED10State); //sets the LED based on ledState
//      //save the 'current' time to pin 10's previousMillis
//      previousMillisLED10 = currentMillis;
//     }
//
//     //toggle LED9
//    if ((unsigned long)(currentMillis-previousMillisLED9)>= intervalLED9){
//      LED9State =!LED9State; //toggles the state
//      analogWrite(LEDPin9, LED9State); //sets the LED based on ledState
//      //save the 'current' time to pin 9's previousMillis
//      previousMillisLED9 = currentMillis;
//    }

//    analogWrite(LEDPin9,writeValue);    // set the pwm value of pin 9
//    analogWrite(LEDPin10,writeValue);    // set the pwm value of pin 10
  

// 
}

You can try this (compiles, not tested):

#define BTN_READ_INTERVAL   50ul    //mS    read buttons every 50mS

#define BLINK_ADJ           25ul    //mS    adjustment per press of an u/d button (period delta is 2xNmS/press)
#define MIN_BLINK_VAL       25ul    //mS    N   Hz = 1/(2xN/1000); for N=500,   Hz=20
#define MAX_BLINK_VAL       2000ul  //mS    N   Hz = 1/(2xN/1000); for N=2000, Hz=0.25

const byte potPin= A0;              //Declare potPin to be analog pin A0
const byte pinLED_Blink = 9;        // set LEDPin3 as output
const byte pinLED_Solid = 10;       // set LEDPin5 as output
const byte pinBtnUp = 11;           //frequency adjust pin input (up)
const byte pinBtnDn = 12;           //frequency adjust pin input (up)

bool LEDState = 0;                  //true = LED on
int readValue;                      //potentiometer input
int writeValue;                     //PWM value written to LED

unsigned long nowTime;              //used for timing
unsigned long timeBlink = 0;        //will store last time LED was updated
unsigned long interval = 250;       //Period/2; time of each phase of blink (Ton and Toff) 250 default == 2Hz

byte lastUp;
byte lastDown;

void setup() 
{
    //LEDs
    pinMode (pinLED_Blink, OUTPUT);
    pinMode (pinLED_Solid, OUTPUT);
    digitalWrite( pinLED_Solid, HIGH ); //turn on "solid" LED
    
    //frequency change buttons
    pinMode( pinBtnUp, INPUT_PULLUP );
    lastUp = digitalRead( pinBtnUp );
    pinMode( pinBtnDn, INPUT_PULLUP );
    lastDown = digitalRead( pinBtnDn );        
    
}//setup

void loop() 
{
    //read the frequency adjust buttons
    ReadButtons();
    //update the LED state flag
    SetBlinkFlag();

    //update desired brightness
    readValue = analogRead(potPin);
    writeValue = map(readValue, 0, 1023, 0, 255);

    //update the blinking LED
    analogWrite( pinLED_Blink, (LEDState==true) ? writeValue:0 );
           
}//loop

void SetBlinkFlag( void )
{
    unsigned long
        nowTime;
        
    nowTime = millis();
    if( nowTime - timeBlink >= interval )
    {
        timeBlink = nowTime;
        LEDState ^= true;

    }//if
    
}//SetBlinkFlag

void ReadButtons( void )
{
    byte
        swNow;
    static unsigned long
        timeButton=0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( timeNow - timeButton < BTN_READ_INTERVAL )
        return;

    timeButton = timeNow;
   
    //check up button
    swNow = digitalRead( pinBtnUp );
    if( swNow != lastUp )
    {
        lastUp = swNow;
        if( swNow == LOW )
        {
            if( interval > MIN_BLINK_VAL )
                interval -= BLINK_ADJ;
        }//if
    }//if

    //check down button
    swNow = digitalRead( pinBtnDn );
    if( swNow != lastDown )
    {
        lastDown = swNow;
        if( swNow == LOW )
        {
            if( interval < MAX_BLINK_VAL )
                interval += BLINK_ADJ;
        }//if
    }//if
    
}//ReadButtons

Blackfin:

#define BTN_READ_INTERVAL   50ul    //mS    read buttons every 50mS

#define BLINK_ADJ          25ul    //mS    adjustment per press of an u/d button (period delta is 2xNmS/press)
#define MIN_BLINK_VAL      25ul    //mS    N  Hz = 1/(2xN/1000); for N=500,  Hz=20
#define MAX_BLINK_VAL      2000ul  //mS    N  Hz = 1/(2xN/1000); for N=2000, Hz=0.25

unsigned long interval = 250;      //Period/2; time of each phase of blink (Ton and Toff) 250 default == 2Hz

Thank you so much! The code works really well and is adjustable just the way I would want. I am a bit confused about the lines I quoted above. I was attempting to change the values just as a way of understanding what each did, but I'm still not sure. When I tried looking this up, I was directed to a lot of posts about duty cycle and square waves. How can I convert these numbers to something more understandable? If the LED is flashing at 2 Hz (2 flashes per second) and changing by 1 flash/sec with each button press, I should eventually reach a point (around 60 Hz) where the flashing appears constant to me, though this does not happen. I tried changing MAX_BLINK_VAL, but this didn't seem to change this.

tekjones9:
Thank you so much! The code works really well and is adjustable just the way I would want. I am a bit confused about the lines I quoted above. I was attempting to change the values just as a way of understanding what each did, but I'm still not sure. When I tried looking this up, I was directed to a lot of posts about duty cycle and square waves. How can I convert these numbers to something more understandable? If the LED is flashing at 2 Hz (2 flashes per second) and changing by 1 flash/sec with each button press, I should eventually reach a point (around 60 Hz) where the flashing appears constant to me, though this does not happen. I tried changing MAX_BLINK_VAL, but this didn't seem to change this.

The xxx_BLINK_VAL limits can be thought of this way:

Your interval variable describes the number of milliseconds the LED is on or off and the value in this variable is limited to the MIN and MAX values shown.

Right now, the MIN value is 25ul (25 cast as an unsigned long). That means that the fastest the LED can blink -- off and then on -- is 25mS low, then 25mS high for a cycle time of 50mS. That gives a blink rate of 20Hz which has a definitely noticeable flicker.

60Hz has a period of 16.67mS. This needs to be split between on and off times of 16.67/2 or 8.33mS each. The way things are coded now you can't get that level of granularity; the BLINK_ADJ parameter, 25mS, is how much the half-periods (off and on) are adjusted with each press of the button. You can't really get to 8.33mS when adding or subtracting 25mS.

If you can live with discrete steps, maybe you can alter the code to use canned values in an array and switch to micros() to get a bit more granularity (compiles, not tested):

#define BTN_READ_INTERVAL   50ul    //mS    read buttons every 50mS

const byte potPin= A0;              //Declare potPin to be analog pin A0
const byte pinLED_Blink = 9;        // set LEDPin3 as output
const byte pinLED_Solid = 10;       // set LEDPin5 as output
const byte pinBtnUp = 11;           //frequency adjust pin input (up)
const byte pinBtnDn = 12;           //frequency adjust pin input (up)

bool LEDState = 0;                  //true = LED on
int readValue;                      //potentiometer input
int writeValue;                     //PWM value written to LED

unsigned long nowTime;              //used for timing
unsigned long timeBlink = 0;        //will store last time LED was updated
unsigned long interval = 250000ul;  //Period/2; time of each phase of blink (Ton and Toff) 250 default == 2Hz

byte dlyIndex = 4;
#define NUM_STEPS   12
const unsigned long grDelays[NUM_STEPS] = 
{
    2000000ul,      //0.25Hz
    1000000ul,      //0.5Hz
    666667ul,       //0.75Hz
    500000ul,       //1Hz     
    250000ul,       //2Hz
    100000ul,       //5Hz
    50000ul,        //10Hz
    25000ul,        //20Hz
    16667ul,        //30Hz
    12500ul,        //40Hz
    10000ul,        //50Hz
    8333ul          //60Hz
};


byte lastUp;
byte lastDown;

void setup() 
{
    //LEDs
    pinMode (pinLED_Blink, OUTPUT);
    pinMode (pinLED_Solid, OUTPUT);
    digitalWrite( pinLED_Solid, HIGH ); //turn on "solid" LED
    
    //frequency change buttons
    pinMode( pinBtnUp, INPUT_PULLUP );
    lastUp = digitalRead( pinBtnUp );
    pinMode( pinBtnDn, INPUT_PULLUP );
    lastDown = digitalRead( pinBtnDn );        
    
}//setup

void loop() 
{
    //read the frequency adjust buttons
    ReadButtons();
    //update the LED state flag
    SetBlinkFlag();

    //update desired brightness
    readValue = analogRead(potPin);
    writeValue = map(readValue, 0, 1023, 0, 255);

    //update the blinking LED
    analogWrite( pinLED_Blink, (LEDState==true) ? writeValue:0 );

    interval = grDelays[dlyIndex];
           
}//loop

void SetBlinkFlag( void )
{
    unsigned long
        nowTime;
        
    nowTime = micros();
    if( nowTime - timeBlink >= interval )
    {
        timeBlink = nowTime;
        LEDState ^= true;

    }//if
    
}//SetBlinkFlag

void ReadButtons( void )
{
    byte
        swNow;
    static unsigned long
        timeButton=0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( timeNow - timeButton < BTN_READ_INTERVAL )
        return;

    timeButton = timeNow;
   
    //check up button
    swNow = digitalRead( pinBtnUp );
    if( swNow != lastUp )
    {
        lastUp = swNow;
        if( swNow == LOW )
        {
            if( dlyIndex < (NUM_STEPS-1) )
                dlyIndex++;
        }//if
    }//if

    //check down button
    swNow = digitalRead( pinBtnDn );
    if( swNow != lastDown )
    {
        lastDown = swNow;
        if( swNow == LOW )
        {
            if( dlyIndex > 0 )
                dlyIndex--;
        }//if
    }//if

    //update the interval value
    interval = grDelays[dlyIndex];
    
}//ReadButtons