Reputation: 35
So I have a push button that changes a variable value, which controls a motor's strength, when pressed. It goes through a loop back and forth and stops when I release it.
The problem is that whenever the value changes it's being sent to the motor. I want the value to change when I press the button (without sending it to the motor) and when I'll release the button the value will be sent once to the motor (instead of the motor will change its strength very fast all the time and shake).
Here's what I have:
increment = 1;
void update() {
if (millis() - last_update > 300) {
last_update = millis();
strength += increment;
analogWrite(LAUNCHER_PIN, strength);
Serial.print("Canon strength: ");
Serial.print(strength);
if (strength <= CANON_MIN || strength >= CANON_MAX) increment = -increment;
}
}
if (!digitalRead(MOTOR_BTN_PIN)) update();
Upvotes: 0
Views: 2645
Reputation: 483
You need to get the "edge" of the signal when it's going down.
You can think of a buttons signal as a square. When the button is not pressed there is nothing, when you press it, the voltage flows, so it looks like this (this image illustrates a system where you connect your button in pulldown):
So, in total, there are four states of a given digital signal:
In your case, you'll make use of point 4, as this is the state where the button is no longer pressed, and the microcontroller stops receiving signal.
Try this:
#define btnPin 2
uint8_t btn_prev;
void setup() {
pinMode(btnPin, INPUT_PULLUP);
// here the previous button signal is set to HIGH, as we enabled the pullup
btn_prev = digitalRead(btnPin);
}
void loop() {
//for each iteration we read the button singal
uint8_t btn = digitalRead(btnPin);
// we call your update function when the button was low and is now high: a.k.a. falling edge
if (btn == LOW && btn_prev == HIGH)
{
update();
}
// at last, we update the previous state of the button, so that we can check again for a change in the next iteration
btn_prev = digitalRead(btnPin);
}
Hope this makes sense.
Upvotes: 0
Reputation: 3973
If you don't need your main process to continue doing stuff while you press buttons, then you can do something like:
while (!digitalRead(MOTOR_BTN_PIN))
{
if (digitalRead(MOTOR_BTN_PIN))
update();
}
When you press the button you get trapped in the while, and when you finally let go update()
gets called (once).
Upvotes: 0
Reputation: 409356
This is could easily be solved with a simple state machine.
You could have two states: NORMAL
, BUTTON_DOWN
.
Normally you should be in the NORMAL
state, and the loop
function checks if the button is pressed or not. If the button is pressed and you're in state NORMAL
, then you set the state to BUTTON_DOWN
and do whatever other processing you need to do when the button is pressed.
If the button is not pressed, and the current state is BUTTON_DOWN
you know that the button have been released and you go back to the NORMAL
state and do the button-release processing that needs to be done.
Since you only have two states, you could represent that as a single bool
variables, where (for example) false
means NORMAL
and true
means BUTTON_DOWN
.
In pseudo code it could be something like
void loop()
{
if (state == NORMAL)
{
// Do normal processing
if (is_button_pressed())
{
// Do buttown-down processing
state = BUTTON_DOWN;
}
}
else if (state == BUTTON_DOWN)
{
if (!is_button_pressed())
{
// Do button-release processing
state = NORMAL;
}
}
}
By adding a third state, BUTTON_DEBOUNCE
, you could easily handle debounce of the button.
When in state NORMAL
and you detect the button being pressed, you enter the BUTTON_DEBOUNCE
state. If you have been in the BUTTON_DEBOUNCE
state for a certain amount of time (say a few milliseconds) and the button is still pressed then you enter the BUTTON_PRESSED
state and to the button-pressed processing.
If after the short time the button is not pressed, you go back to the NORMAL
state.
If you add a third state like this, then you can no longer have a simple bool
variable representing the state. An enumeration and a variable of that enumeration type might be a better choice then.
Upvotes: 2
Reputation: 245
You can use flag to solve this issue,create a flag variable boolean and set it true and false when event occurs and only pass the value when flag is true
Upvotes: 1