Replace a potentiometer with 2 buttons

Status
Not open for further replies.

edrummer

Well-known member
I need to change this code so that it uses 2 buttons (forward and reverse) instead of the pot. I tried to just connect to switches to A1 and 5v and A1 and gnd. but that doesn't work. The pot is for one axis of a joystick so the center position is off. This is the only code I found that works but I have another motor that I need buttons instead of the pot. Anyone know how to change the code to make it work?

Code:
#include <AccelStepper.h> // accelstepper library
AccelStepper stepper(1, 8, 9); // direction Digital 9 (CCW), pulses Digital 8 (CLK)

//Pins
const byte Analog_X_pin = A1; // x-axis readings
const byte enablePin = 7;

//Variables
int Analog_X = 0;             //x-axis value
int Analog_X_AVG = 0;         //x-axis value average
  //---------------------------------------------------------------------------- 
void setup() {
  Serial.begin(9600);
  //----------------------------------------------------------------------------    
  //PINS
  pinMode(Analog_X_pin, INPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(2, INPUT_PULLUP); 
  pinMode(3, INPUT_PULLUP);
  //----------------------------------------------------------------------------  
  InitialValues(); // averaging the values of analog pin 0 (value from potmeter)
  //----------------------------------------------------------------------------  
  // Stepper parameters
  // setting up some default values for maximum speed and maximum acceleration
  stepper.setMaxSpeed(2000);     //SPEED = Steps / second  
  stepper.setAcceleration(1000); //ACCELERATION = Steps /(second)^2    
  stepper.setSpeed(1000);
  delay(1000);
}

void loop()
{
  ReadAnalog();
  ReadLimits();  
  stepper.runSpeed(); //step the motor (this will step the motor by 1 step at each loop indefinitely)
}

void ReadLimits()
{
  if( digitalRead(2)==LOW && stepper.speed()>0 )//read input, assuming they have pull-up resistors.
  {
    stepper.setSpeed(0);
  }

  if( digitalRead(3)==LOW && stepper.speed()<0 )//read input, assuming they have pull-up resistors.
  {
    stepper.setSpeed(0);
  }
}

void ReadAnalog() {
  if (abs(Analog_X-Analog_X_AVG) > 50) {
    digitalWrite(enablePin, HIGH);  // enable the driver
    stepper.setSpeed(5*(Analog_X-Analog_X_AVG));   
  } else {
    digitalWrite(enablePin, LOW);   // disable the driver
    stepper.setSpeed(0);
  }
  // Reading the potentiometer in the joystick: 
  Analog_X = analogRead(Analog_X_pin);  
  // if the value is 25 "value away" from the average (midpoint), we allow the update of the speed
  // This is a sort of a filter for the inaccuracy of the reading
  if (abs(Analog_X-Analog_X_AVG) > 50) {
    stepper.setSpeed(5 * (Analog_X-Analog_X_AVG));    
  } else {
    stepper.setSpeed(0);
  }
}

void InitialValues() {
  //Set the values to zero before averaging
  float tempX = 0;
  //----------------------------------------------------------------------------  
  // read the analog 50x, then calculate an average. 
  // they will be the reference values
  for (int i = 0; i<50; i++) {
    tempX += analogRead(Analog_X_pin);  
    delay(10); //allowing a little time between two readings
  }
  //----------------------------------------------------------------------------  
  Analog_X_AVG = tempX/50; 
  //----------------------------------------------------------------------------  
  Serial.print("AVG_X: ");
  Serial.println(Analog_X_AVG);
  Serial.println("Calibration finished");  
}
 
What Teensy is in use? Is it one that is 5V tolerant?

From 2 buttons FWD and REV ? Is the motion to stop when the button released - not return to zero?
 
Yes 3.2 is 5V tolerant. Momentary switches stop when not pressed nothing else. Can I use pins A0 and A1 for the switches or D pins?
 
Last edited:
Since it wasn't stated ... had to ask given the use of 5V - could have been an AVR Teensy - otherwise it makes no sense to use 5V for an input when while 5V tolerant - it is a device designed for 3.3V usage.

Any pin with a '#" on the Gray background is digital using that number - all of the edge pins. In the case of A0 and A1 they would be digital pin 14 and 15, so yes.

The T_3.2 does have Analog only pins as indicated on the card backside - those in orange without a gray digital pin value.

The question was about 'desired behavior in the program' - not how the physical switch works.

>> From 2 buttons FWD and REV ? Is the motion to stop when the button released - not return to zero?

unclear if the desire is three effective states : -1 (when REV held) or 0 or +1 (when FWD held)

Or if 5 REV presses from zero would have the effect of -5, followed by 8 FWD presses resulting in +3?
 
I have no idea what all that is, I just want the motor to run forward when the button is pressed, stop when released, and the same for the reverse button.
 
I have no idea what all that is, I just want the motor to run forward when the button is pressed, stop when released, and the same for the reverse button.

That would be this then :: effective states : -1 (when REV held) or 0 or +1 (when FWD held)

The code posted has a lot more involved that isn't relevant given no analog is desired ...

Perhaps start with this example installed with TeensyDuino: ...\hardware\teensy\avr\libraries\Bounce2\examples\more\bounceTwo\bounceTwo.ino

Using that library will prevent 'bounce' or high/low chatter as the button is pressed.

This code will run as fast as the Teensy will allow and be very sensitive and responsive to button press and release - on 5ms intervals of the debounce code testing.

Edit might look like this - this code doesn't use external pullups - but internal with pin wired across switch to ground - to use external pullups remove these elements: ", INPUT_PULLUP"
Code:
/*
 DESCRIPTION
 ====================
 Simple example of the Bounce library that switches the debug LED when
 either of 2 buttons are pressed.
 */

// Include the Bounce2 library found here :
// https://github.com/thomasfredericks/Bounce2
#include <Bounce2.h>

#define BUTTON_PIN_FWD 2
#define BUTTON_PIN_REV 3


#define LED_PIN 13

// Instantiate a Bounce object
Bounce debouncer1 = Bounce();

// Instantiate another Bounce object
Bounce debouncer2 = Bounce();

void setup() {

  // Setup the first button with an internal pull-up :
  pinMode(BUTTON_PIN_FWD[B], INPUT_PULLUP[/B]);
  // After setting up the button, setup the Bounce instance :
  debouncer1.attach(BUTTON_PIN_FWD);
  debouncer1.interval(5); // interval in ms

  // Setup the second button with an internal pull-up :
  pinMode(BUTTON_PIN_REV[B], INPUT_PULLUP[/B]);
  // After setting up the button, setup the Bounce instance :
  debouncer2.attach(BUTTON_PIN_REV);
  debouncer2.interval(5); // interval in ms


  //Setup the LED :
  pinMode(LED_PIN, OUTPUT);

}

void loop() {
  // Update the Bounce instances :
  debouncer1.update();
  debouncer2.update();

  // Get the updated value :
  int pForward = debouncer1.read();
  int pReverse = debouncer2.read();

  // Turn on the LED if either button is pressed :
  if ( ( pForward == LOW || pReverse == LOW ) || ( pForward == HIGH && pReverse == HIGH ) ) {
    // when both are pressed treat as if neither is pressed
    Serial.print( " Stop the motor")
    digitalWrite(LED_PIN, LOW );
  }
  else if ( pForward == HIGH ) {
    Serial.print( "  motor FORWARD ")
    digitalWrite(LED_PIN, HIGH );
  }
  else if ( pReverse == HIGH ) {
    Serial.print( "  motor REVERSE ")
    digitalWrite(LED_PIN, HIGH );
  }

}
 
I need to change this code so that it uses 2 buttons (forward and reverse) instead of the pot. I tried to just connect to switches to A1 and 5v and A1 and gnd. but that doesn't work.
That's a dangerous circuit - press both buttons and the supply is shorted out, possibly welding the switches shut too.

Also when neither button is pressed the pin is left floating, so that its voltage is undefined - CMOS inputs have
infinite resistance effectively.

Normally you'd use one pin per switch, using INPUT_PULLUP and switching to GND. The pin then reads HIGH
when the button is idle and LOW when pressed, a.k.a. "active low".

If you want to use one pin to read two switches you'd need a circuit that doesn't short out the supply nor leave
the pin floating. Something like this would work:
two_button.png
 
Thanks, I was thinking I would need dpdt switches to do that way. With a 10k pot A1 is 5k to Vcc and 5k to gnd when the pot is centered and the motor is off, correct? Would it be better to just add the buttons to 2 unused pins and adjust the code? I'm using TB6600 drivers and i've tried several other codes but this one is the only one that worked well. It has the end or limit switches which I need also which is why I wanted to just modify it to use the buttons. I'm afraid I don't know where to adjust the code to tell the motor to go forward when I press this button and reverse when I press the other.
 
If the post #6 code works reliably to print the desired message using wired buttons - then instead of just printing - issue the commands to the motor as indicated for FWD or REV? What the commands look like is beyond me - would they be the same as code posted previously?

For the STOP switches you'll need to add those as inputs as well and when FWD STOP triggers the FWD button code must not Print or energize the motor, and likewise with the REV STOP and REV button.
 
Well this is my first attempt at modifying this code. I know it won't work but I wanted to see if I could get somebody to steer me in the right direction. I commented out all the analog stuff and just tried to put in a few things to see if anything is close. What I really don't understand is where the code tells the driver to go in either direction. If anybody could point that out I'd appreciate it, or anything else that would help.


Code:
#include <AccelStepper.h> // accelstepper library
AccelStepper stepper(1, 8, 9); // direction Digital 9 (CCW), pulses Digital 8 (CLK)
#define button 4
#define button 5

//Pins
//const byte Analog_X_pin = A1; // x-axis readings
const byte enablePin = 7;
const byte button 4
const byte button 5
//Variables
//int Analog_X = 0;             //x-axis value
//int Analog_X_AVG = 0;         //x-axis value average
  //---------------------------------------------------------------------------- 
void setup() {
  Serial.begin(9600);
  //----------------------------------------------------------------------------    
  //PINS
  //pinMode(Analog_X_pin, INPUT);
  //pinMode(Analog_X_pin, INPUT);
 // pinMode(Analog_X_pin, INPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(2, INPUT_PULLUP); 
  pinMode(3, INPUT_PULLUP);
  pinMode(4  INPUT_PULLUP); //button 1
  pinMode(5  INPUT_PULLUP); //button 2
  //----------------------------------------------------------------------------  
  InitialValues(); // averaging the values of analog pin 0 (value from potmeter)
  //----------------------------------------------------------------------------  
  // Stepper parameters
  // setting up some default values for maximum speed and maximum acceleration
  stepper.setMaxSpeed(2000);     //SPEED = Steps / second  
  stepper.setAcceleration(1000); //ACCELERATION = Steps /(second)^2    
  stepper.setSpeed(1000);
  delay(1000);
}

void loop()
{
  if (digitalRead(SW1) && digitalRead(SW2)) digitalWrite(motorOn, LOW);
  digitalWrite(motorOn, HIGH);
  ReadLimits();  
  stepper.runSpeed(); //step the motor (this will step the motor by 1 step at each loop indefinitely)
}

void ReadLimits()
{
  if( digitalRead(2)==LOW && stepper.speed()>0 )//read input, assuming they have pull-up resistors.
  {
    stepper.setSpeed(0);
  }

  if( digitalRead(3)==LOW && stepper.speed()<0 )//read input, assuming they have pull-up resistors.
  {
    stepper.setSpeed(0);
  }
}

void digitalRead(4) {
  if (pin 4 HIGH) {
    digitalWrite(enablePin, HIGH);  // enable the driver
    stepper.setSpeed(2000));   
  } else {
    digitalWrite(enablePin, LOW);   // disable the driver
    stepper.setSpeed(0);
  }
    if (pin 5 HIGH) {
    digitalWrite(enablePin, HIGH);  // enable the driver
    stepper.setSpeed(2000));   
  } else {
    digitalWrite(enablePin, LOW);   // disable the driver
    stepper.setSpeed(0);
  }


/*
void ReadAnalog() {
  if (abs(Analog_X-Analog_X_AVG) > 50) {
    digitalWrite(enablePin, HIGH);  // enable the driver
    stepper.setSpeed(5*(Analog_X-Analog_X_AVG));   
  } else {
    digitalWrite(enablePin, LOW);   // disable the driver
    stepper.setSpeed(0);
  }
  // Reading the potentiometer in the joystick: 
  Analog_X = analogRead(Analog_X_pin);  
  // if the value is 25 "value away" from the average (midpoint), we allow the update of the speed
  // This is a sort of a filter for the inaccuracy of the reading
  if (abs(Analog_X-Analog_X_AVG) > 50) {
    stepper.setSpeed(5 * (Analog_X-Analog_X_AVG));    
  } else {
    stepper.setSpeed(0);
  }
}
*/
void InitialValues() {
  //Set the values to zero before averaging
  float tempX = 0;
  //----------------------------------------------------------------------------  
  // read the analog 50x, then calculate an average. 
  // they will be the reference values
  for (int i = 0; i<50; i++) {
    //tempX += analogRead(Analog_X_pin);  
    delay(10); //allowing a little time between two readings
  }
  //----------------------------------------------------------------------------  
  //Analog_X_AVG = tempX/50; 
  //----------------------------------------------------------------------------  
  //Serial.print("AVG_X: ");
  //Serial.println(Analog_X_AVG);
  Serial.println("Calibration finished");  
}
 
Referring back to post#6 sketch - the BOUNCE2 lib was used as an example to make sure the buttons were properly monitored without BOUNCE - pushing/releasing most buttons will see them cycle HIGH/LOW multiple times in the first couple of milliseconds.

The Teensy can read and run fast enough to see that ON/OFF Chatter and will result in the MOTOR being tormented with repeat commands to Start and STOP.

Was that sketch tested to provide expected PRINTING of the FWD and REV button detect to the Serial Monitor?

If that same code was run without use of a Bounce library - those strings would print multiple times on each press and release.

The p#10 sketch uses direct I/O reads ... also the line:
Code:
if (digitalRead(SW1) && digitalRead(SW2)) digitalWrite(motorOn, LOW);

looks to request BOTH buttons ON and then starts the motor on LOW - only when both pressed and only some default direction?

Starting with p#6 if it works as expected when wired to the pins Add to that sketch as needed to get the desired functionality.

If p#6 doesn't work it should be corrected before advancing. Not using that scheme will likely only result in troubles down the road when reading the pins directly as noted.
 
That bit of code is for the end switches, they worked fine. What I'm trying to do is replace the analog parts so I can use buttons instead of the pot.
 
That bit of code is for the end switches, they worked fine. What I'm trying to do is replace the analog parts so I can use buttons instead of the pot.

In use the direct read of the end switches may chatter as well - depending on how they are switched - could result in bouncing on/off - adding those as two more de bounced buttons may be better.

But the P#6 code was just button - no analog? Do the buttons trigger it properly? If so use that as the model.
 
I don't even have the code any where near correct, yes I can add denounce but I need help with the code.
 
Hope was that the post #6 code would be a starting point to show the switches working. It is just a Bounce2 example modified as noted for two buttons.

If that works to reliably read the two buttons and print FWD, REV, STOP then that would be something to build on.

That would PRINT continuously if tried as it treats each loop as new - forgot to add no print on no state change that would look like this perhaps:
Code:
#define STOP 1
#define FWD 2
#define REV 3

void loop() {
  static int32_t motorLast=0;
  // Update the Bounce instances :
  debouncer1.update();
  debouncer2.update();

  // Get the updated value :
  int pForward = debouncer1.read();
  int pReverse = debouncer2.read();

  // Turn on the LED if either button is pressed :
  if ( ( pForward == LOW || pReverse == LOW ) || ( pForward == HIGH && pReverse == HIGH ) ) {
    // when both are pressed treat as if neither is pressed
    if ( motorLast != STOP ) {
      Serial.print( " Stop the motor")
      digitalWrite(LED_PIN, LOW );
    }
    motorLast = STOP;
  }
  else if ( pForward == HIGH ) {
    if ( motorLast != FWD ) {
      Serial.print( "  motor FORWARD ")
      digitalWrite(LED_PIN, HIGH );
    }
    motorLast = FWD;
  }
  else if ( pReverse == HIGH ) {
    if ( motorLast != REV ) {
      Serial.print( "  motor REVERSE ")
      digitalWrite(LED_PIN, HIGH );
    }
    motorLast = REV;
  }

}

Getting that first piece of code working allows trusting the buttons to move the motor, except it needs two more input to recognize and implement the END STOP switches to override the buttons when they hit the end.
 
Status
Not open for further replies.
Back
Top