A new spin on an old question in LED control...

Hello Arduino community! I have a probably very simple coding question that is stumping me...

I want to be able to set the output intensity of an LED with a potentiometer while the LED is off, then turn the LED on for a set amount of time via a push button.

I have attached my current code and a circuit diagram for your perusal. Any assistance is appreciated. :slight_smile:

Currently my code produces no error output, and seems to compile and run. However, It is not producing the desired effect. It instead turns the LED off completely and does not allow me to control its intensity with the potentiometer or on/off state via button push. It simply remains off at all times...

POT_buttonControlForLaser.ino (2.62 KB)

How is the pushbutton wired to the input?

Have you been able to make the button feature and the PWM feature work separately?

Cannot download your sketch on the iPad.

Use CTRL T to format the sketch.
Please use code tags.
Use the </> icon in the posting menu.

[code] Paste sketch here. [/code]

Try moving the pull down resistor to the green wire switch terminal, then to GND.

An image of your wiring is far far better the Fritzing diagrams.

Show us a good ‘image’ of your wiring.
Posting images:
https://forum.arduino.cc/index.php?topic=519037.0

BTW, in future setups, make the red power rail on the breadboard +5V and the Blue rail GND.

.

You have to be careful with those little tactile switches, the legs are shorted through in one direction.

tactile switch.PNG

Those switches are at the root of many problems here, in fact two today.

Particularly, not actually fitting into solderless breadboards.

Thanks so much for all your helpful tips everyone! I will be sure to make some revisions in short order and come back to this thread tomorrow with better preparation!

See you soon!

After checking my wiring, I found that my buttons are correctly wired, and all connections are firmly in place. Finagling a bit more with the code, I have come to the point where the LED remains off while I adjust the intensity with the potentiometer, and the LED turns on for a certain amount of time after I push the button. Unfortunately, I find that instead a 1 second pulse as I would like, I get a pulse ranging in length from 9 to 15 seconds generally and I do not know why the timing is so off. I suspect it is due to code optimization issues on my part, but I cant really see where the problem is.

I am sure it is obvious to sages like yourselves, but my green eyes seem to be missing where in the loop between lines 55 and 69 such a large cyclical delay is entering into the picture.

Any assistance and advice is appreciated! Thanks again! I have reformatted the code as per your request. Apologies for the inconvenience.

// These constants won't change. They're used to give names to the pins used:
const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
const int analogOutPin = 9; // Analog output pin that the LED is attached to
const int digitalInPin = 7; // button input pin
int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)
int buttonState = 0;
unsigned long previousMillis = 0;
unsigned long interval = 1000;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  // initialize the LED pin as an output:
  pinMode(analogOutPin, OUTPUT);
  // intialize the button pin as an input
  pinMode(digitalInPin, INPUT);

}

void loop() {



  //setup button state and see what it is set to.
  buttonState = digitalRead(digitalInPin);
  //check the current time
  unsigned long currentMillis = millis();

  if (buttonState == HIGH) {
    // change the analog out value:

    while (currentMillis - previousMillis > interval) {       //My timed loop line 55
      previousMillis = currentMillis;
      // read the analog in value:
      sensorValue = analogRead(analogInPin);
      // map it to the range of the analog out:
      outputValue = map(sensorValue, 0, 1023, 0, 255);
      analogWrite(analogOutPin, outputValue);
    }
  } else {
    analogWrite(analogOutPin, 0);
    // print the results to the Serial Monitor:
    Serial.print("sensor = ");
    Serial.print(sensorValue);
    Serial.print("\t output = ");
    Serial.println(outputValue);     //serial monitor output line 69


  }


}

Did you try moving the pull down resistor as mentioned in post #3?

Let’s see your wiring.

I do not have a camera that I can use for photographing the wiring unfortunately. I do apologize.

I have done as suggested and moved the resistor to the green terminal, and then to ground, and found that it greatly reduced the delay time. Thank you for the expert tip! However, the pulse time is still rather strange. When I push the button and have the interval set to 1000 milliseconds, the led lights for approximately 1 second. However, when I change the interval to anything other than 1000 milliseconds, I find that the pulse time is unpredictably shorter or longer after a button press. Additionally the time the LED is on for seems to depend on the length of the button press. I want the pulse time to be consistently as close to the set interval time as possible, regardless of the time the button is pressed for...

I am not sure what is happening in the timing structure of the code, the way I read it, it looks like, in sequential order,

  • looping continuously
    -check for button press
    -if button is not pressed LED LOW
    -if button is pressed, LED to analogInputValue(value mapped from potentiometer) for INTERVAL milliseconds
    -after interval, continue with LED being set to LOW
    -Write results to serial monitor
    REPEAT

Am I blind ? or is this the way it should go?

PS To answer the first respondent's question. Yes I have been able to get the LED to work with the Fading circuit (IE POT control of brightness by analog to digital map) and the button push circuit to work separately. There is something wrong in my sequence of commands, or perhaps in my choice of timing control in the way I have combined the systems in software I suspect.

When you ask for help, you need to supply the information we ask for.

Buy a camera!
or
get one from Santa :wink:

Try this:

const byte analogInPin = A0; // Analog input pin that the potentiometer is attached to
const byte analogOutPin = 9; // Analog output pin that the LED is attached to
const byte digitalInPin = 7; // button input pin

//byte sensorValue = 0;        // value read from the pot
//byte outputValue = 0;        // value output to the PWM (analog out)

unsigned int sensorValue = 0; // value read from the pot              <-----<<<< correction
unsigned int outputValue = 0; // value output to the PWM (analog out) <-----<<<< correction


byte buttonState = 0;
byte lastButtonState = 0;

unsigned long previousMillis = 0;

unsigned long interval = 1000;

void setup()
{
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);

  // initialize the LED pin as an output:
  pinMode(analogOutPin, OUTPUT);           //LOW is LED off

  // intialize the button pin as an input
  pinMode(digitalInPin, INPUT);            //pressed gives HIGH on pin

}

void loop()
{
  unsigned long currentMillis = millis();

  buttonState = digitalRead(digitalInPin);

  //get pot (sensor) setting
  sensorValue = analogRead(analogInPin);
  //map it to the range of the analog out
  outputValue = map(sensorValue, 0, 1023, 0, 255);
  Serial.print("sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t output = ");
  Serial.println(outputValue);

  //has switch changed state?
  if (lastButtonState != buttonState)
  {
    lastButtonState = buttonState;      //update to the new state

    if (buttonState == HIGH)            //switch 'just' went HIGH?
    {
      previousMillis = currentMillis;   //time when the switch was just pressed
    }

    else                                //switch 'just' went LOW
    {
    }

  } //ENF of      if (lastButtonState != buttonState)

  //Switch pressed?
  if (buttonState == HIGH)
  {
    //If we are inside the interval, send sensor value to LED
    if (currentMillis - previousMillis < interval)
    {
      analogWrite(analogOutPin, outputValue);
    }

    //when finished with 'this' interval, turn off LED
    else
    {
      analogWrite(analogOutPin, 0);
    }

  } //END of     if (buttonState == HIGH)

  //switch was not pressed, turn off LED
  else
  {
    analogWrite(analogOutPin, 0);
  }

} //END of loop()

If it is what you want, do you fully understand it?

Unfortunately, that code does not do what I am looking for. As Pretty and readable as it is! :stuck_out_tongue:

I understand that I have been lazy in the implementation of my button state machine, but I have not been able to confirm that as the issue. After compiling and running the code you provided, I find that it works, but does not allow me to control the length of the interval.

I want to be able to set the interval in the code, turn the potentiometer to some value, and push the button to have the LED turn on at the brightness associated with that pot value for INTERVAL milliseconds.

I have cleaned up my state machine though, just as a precaution and to verify that is not the source of the issue. Thank you for the pointer :slight_smile:

That code works fine here.

You can make interval 1000, 2000, 5000 or what ever you want.

When you ‘first’ push and ‘hold’ the switch, the LED goes to the intensity set on the pot.

After the time interval is up, the LED goes off.

If you let go of the switch within the interval, the LED goes off.

Maybe you don't want to hold the switch during the interval

Try this version:

const byte analogInPin = A0; // Analog input pin that the potentiometer is attached to
const byte analogOutPin = 9; // Analog output pin that the LED is attached to
const byte digitalInPin = 7; // button input pin

//byte sensorValue = 0;        // value read from the pot
//byte outputValue = 0;        // value output to the PWM (analog out)

unsigned int sensorValue = 0; // value read from the pot              <-----<<<< correction
unsigned int outputValue = 0; // value output to the PWM (analog out) <-----<<<< correction

byte buttonState = 0;
byte lastButtonState = 0;

boolean switchWasPressed = false; 

unsigned long previousMillis = 0;

unsigned long interval = 1000;

void setup()
{
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);

  // initialize the LED pin as an output:
  pinMode(analogOutPin, OUTPUT);           //LOW is LED off

  // intialize the button pin as an input
  pinMode(digitalInPin, INPUT);            //pressed gives HIGH on pin

}

void loop()
{
  unsigned long currentMillis = millis();

  buttonState = digitalRead(digitalInPin);

  //get pot (sensor) setting
  sensorValue = analogRead(analogInPin);
  //map it to the range of the analog out
  outputValue = map(sensorValue, 0, 1023, 0, 255);
  Serial.print("sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t output = ");
  Serial.println(outputValue);

  //has switch changed state?
  if (lastButtonState != buttonState)
  {
    lastButtonState = buttonState;      //update to the new state

    if (buttonState == HIGH)            //switch 'just' went HIGH?
    {
      previousMillis = currentMillis;   //time when the switch was just pressed
      switchWasPressed = true;          //flag indicating the switch was just pressed
    }

    else                                //switch 'just' went LOW
    {
    }

  } //END of      if (lastButtonState != buttonState)

  //switch has been pressed?
  if (switchWasPressed == true)
  {
    //If we are inside the interval, send sensor value to LED
    if (currentMillis - previousMillis < interval)
    {
      analogWrite(analogOutPin, outputValue);
    }

    //when finished with 'this' interval, turn off LED
    else
    {
      analogWrite(analogOutPin, 0);
      switchWasPressed = false;          //cancel this switch pressed sequence
    }

  } //END of     if (switchWasPressed == true)

  //switch was not pressed, turn off LED
  else
  {
    analogWrite(analogOutPin, 0);
  }

} //END of loop()

Oh! I see now what you did there with the button state... Changing from direct Boolean logic as it relates to the switch signal, to a logical variable that switches and maintains the state even after the button is released.

The addition of the "switchWasPressed" variable was the important little change that I had overlooked.

Goodness, so it was my unwillingness to be rigorous with the state machine that caused the problem.

Lesson learned, don't skimp on the details of state maintenance!

Problem solved. Thanks to all of you for the help, and expert advice.

For anyone finding this thread in the future, managing state is very important to achieving the control you desire.

To control the state of the LED with a single button press, required the implementation of a boolean variable to keep track of the previous state of the button, instead of directly encoding the HIGH or LOW signal into the state machine logic. Examining my first section of code will demonstrate what that later setup looks like. To achieve my desired outcome, of single press activation for an arbitrary and preset time period at a preset power, the "switchWasPressed" variable was required to keep track of the past state of the button so regardless of how long it was pressed, the LED was activated for precisely the specified interval.

You had a programming problem, and a switch wiring hardware problem.

Switch change detection, is an important thing to master.
Also, proper timing of events is a must have skill.
‘Fags’ are very useful in programs too.
The ‘type’ you use for your varaiables can save your SRAM.

Although your switch now works with the changes suggested, you would be urged to wire your switch as examples S3 or S2 in the image below.

S3 is arguably better as you don’t need an external resistor.
You would have to use INPUT_PULLUP in setup() as shown in the code at the top of the image.
A push gives a LOW (the inverse of what you have now).

In the future, a proper schematic (not Fritzing) and a good image of your wiring should accompany your question.

You can reduce your code size, but we’ll leave that up to you.

Good luck with your projects!

EDIT:
Remember in some applications, you should also incorporate switch debounce code.

Ah! A useful wiring diagram! I will take note of changes for the immediate future. I intend to make this a long term setup, and to add it to documentation for future users. Thanks so much!

There is actually just one more thing that bothers me.

In the current implementation of the code and wiring, I find that the analogOutputValue is limited to 63, I need the full range of intensities for my particular application.

What happens, is, when I turn the potentiometer, the sensor value rises as the pot turns, all the way to 255, then returns to 0, and the outputvalue rises to 67 and then returns to 0 at the same time as the sensor value returns to zero. This continues until the potentiometer is at it's maximum rotation.

Any sage advice here? is there some interaction of the boolean logic and the way I do my mapping that causes the change?

In the current implementation of the code and wiring, I find that the analogOutputValue is limited to 63, I need the full range of intensities for my particular application.

This was my fault as I changed the wrong line. :confused:

byte sensorValue = 0; // value read from the pot

Should be:

unsigned int sensorValue = 0; // value read from the pot

Edit:
Changes have been made in post #14

Ah! I actually spotted it this morning and forgot to make the changes to this thread for future viewers!

The issue was the result of a limit of the variable type used.

Thanks for fixing the post. +1 more karma for you wise sage.

For specificity, the unsigned int can store a value much larger than a byte.

Byte is limited to a much smaller size. Refer to the table of integer types and variable types in C language for details.

https://en.cppreference.com/w/cpp/types/byte

This limit on the stored values in the byte type caused the looping value behavior previously mentioned.