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.
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...
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!
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
}
}
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
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!
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
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).
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.
byte sensorValue = 0; // value read from the pot
Should be:
unsigned int sensorValue = 0; // value read from the pot